Files
ViperC/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp
T
TermiNexus aa52cf157d revert(transpyv): 回滚跨模块链表 Next 改访问器(改由编译器沿继承链解析字段名)
回滚 13080f6 的 110 处访问器调用,恢复裸字段访问 `x.Next`。

理由:该批访问器是把访问移到定义模块内执行,**绕开**了"继承字段名解析",
属于规避而非修复;缺陷本体在 TPC 侧(导入侧继承展平把泛型基类的继承字段
记成 __inherited_N 占位名,名字丢失)。TPC 已按语义修正:
  · e6451a07 继承展平沿继承链取真实字段名(泛型特化回退模板名),
    展平表直接落 `[("Next", <槽位类型>), ...]`,属性访问是普通表命中;
  · 3ca46c01 顺带修掉 _get_or_create_struct 里"同名枚举成员遮蔽类定义"的 i32 出口。
因此源码侧恢复为唯一写法(裸字段访问),由编译器负责解析。

注:本 commit 只回滚访问器;13080f6 里夹带的 CallGenProp.vp 续行合并(非访问器改动)
已在工作区保留(未提交)。
2026-09-28 21:48:53 +08:00

2633 lines
137 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 lib.core.Gen.GenTypes as GenTypes
import lib.core.Gen.Generator as Generator
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdlib
import stdio
import viperlib
import lib.core.VLogger as VLogger
import lib.core.Gen.Translator as HT
import lib.core.Gen.Type.TypeSpec as TSpec
import lib.core.CompilerFactory as CompilerFactory
import lib.Projectrans.Config as Config
import lib.core.Gen.GenApi as GenApi
# ============================================================
# StmtGenCifMixin - CIf 编译期求值 + NewXxxHandle 工厂
# ============================================================
# ============================================================
# StmtGenCifMixin - CIf 求值 + 工厂(最底层父类)
# ============================================================
novirtual class StmtGenCifMixin:
"""CIf 编译期求值 + NewXxxHandle 工厂(StmtGen 拆分 1/3,最底层)"""
# --- 编译期 CIf 求值状态(原 HandlesIf._g_cif_eval_ok) ---
# 用 8 字节类型:Mixin 独立布局与 Generator 组合布局的字段对齐必须一致
# (i32 首字段在组合布局中导致 EnumTable 相对偏移 4 vs 独立布局 8 的错位,
# this_adjust 无法同时修正,枚举表错位到相邻字段被覆盖——ASTCtx 丢失根因)。
Gen: Generator.Generator*
CifEvalOk: sizet
# --- 枚举注册表(原 HandlesEnum._enum_table/_enum_count) ---
EnumTable: rawptr[GenTypes.EnumEntry]
EnumCount: int
# --- OOM 语句级诊断计数(translate_stmt 限频打印 used) ---
DiagStmtCount: int
# ============================================================
# 簇 B:编译期 CIf 宏求值(迁移自 HandlesIf.vp 模块级函数)
# ============================================================
def _is_cif_attr(self, attr: str) -> int:
"""检查方法名是否为 CIf 系(CIf/CIfdef/CIfndef)"""
if attr is None:
return 0
if string.strcmp(attr, "CIf") == 0: return 1
if string.strcmp(attr, "CIfdef") == 0: return 1
if string.strcmp(attr, "CIfndef") == 0: return 1
return 0
def _is_cif_call(self, node: ast.AST*) -> int:
"""检查 test 是否为 c.CIf(...)/c.CIfdef(...)/c.CIfndef(...)(或裸 CIf 系)调用"""
if node is None or node.kind() != ast.ASTKind.Call:
return 0
cl: ast.Call* = ast.Call*(node)
if cl.func is None:
return 0
fk: int = cl.func.kind()
if fk == ast.ASTKind.Attribute:
at: ast.Attribute* = ast.Attribute*(cl.func)
if at.attr is None:
return 0
if at.value is not None and at.value.kind() == ast.ASTKind.Name:
vn: ast.Name* = ast.Name*(at.value)
if vn.id is not None and string.strcmp(vn.id, "c") == 0:
return self._is_cif_attr(at.attr)
return 0
if fk == ast.ASTKind.Name:
nm: ast.Name* = ast.Name*(cl.func)
if nm.id is not None and self._is_cif_attr(nm.id) != 0:
return 1
return 0
def _get_platform_macro_value(self, name: str) -> int:
"""平台内置宏值(从目标三元组推导,对齐 TPC HandlesIf._get_platform_macros)。
命中置 self.CifEvalOk=1;未命中置 0 返回 0。
"""
self.CifEvalOk = 0
if name is None:
return 0
triple: str = Config.TargetTriple
if triple is None:
triple = "x86_64-pc-windows-gnu"
is_win: int = 0
is_linux: int = 0
is_x64: int = 0
if string.strstr(triple, "windows") is not None \
or string.strstr(triple, "win32") is not None \
or string.strstr(triple, "mingw") is not None \
or string.strstr(triple, "msvc") is not None:
is_win = 1
if string.strstr(triple, "linux") is not None:
is_linux = 1
if string.strstr(triple, "x86_64") is not None:
is_x64 = 1
# 简化:本编译目标为 x86_64 Windows(_WIN64/WIN64 恒与 is_win 一致)
if string.strcmp(name, "_WIN32") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0
if string.strcmp(name, "WIN32") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0
if string.strcmp(name, "_WIN64") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0
if string.strcmp(name, "WIN64") == 0: self.CifEvalOk = is_win; return 1 if is_win else 0
if string.strcmp(name, "__linux__") == 0: self.CifEvalOk = is_linux; return 1 if is_linux else 0
if string.strcmp(name, "__x86_64__") == 0: self.CifEvalOk = is_x64; return 1 if is_x64 else 0
if string.strcmp(name, "__x86_64") == 0: self.CifEvalOk = is_x64; return 1 if is_x64 else 0
if string.strcmp(name, "_M_X64") == 0: self.CifEvalOk = is_x64; return 1 if is_x64 else 0
if string.strcmp(name, "SIZEOF_VOID_P") == 0: self.CifEvalOk = 1; return 8 if is_x64 else 4
if string.strcmp(name, "__SIZEOF_POINTER__") == 0: self.CifEvalOk = 1; return 8 if is_x64 else 4
if string.strcmp(name, "NDEBUG") == 0: self.CifEvalOk = 1; return 0
return 0
def _cif_name_value(self, pool: memhub.MemBuddy*,
trans: HT.Translator*,
name: str) -> int:
"""查宏名值: 本地 CDefine → 跨模块 CDefine → 平台宏。
命中置 self.CifEvalOk=1(值 0 也算命中,如 DISABLED=0);未命中置 0。
"""
self.CifEvalOk = 0
if name is None or trans is None:
return 0
v: int = self.Gen.TypeGenCDef.lookup_cdefine_constant(name)
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
self.CifEvalOk = 1
return v
v2: int = self.Gen.ExprGenCdef._lookup_cross_module_cdefine(pool, name, trans._from_imports, trans._imported_modules)
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
self.CifEvalOk = 1
return v2
pv: int = self._get_platform_macro_value(name)
if self.CifEvalOk != 0:
return pv
return 0
def _cif_attr_value(self, pool: memhub.MemBuddy*,
trans: HT.Translator*,
at: ast.Attribute*) -> int:
"""Attribute 宏值: platmacro.IS_WINDOWS → 本地 CDefine(attr) → 跨模块 CDefine。
命中置 self.CifEvalOk=1;未命中置 0。
"""
self.CifEvalOk = 0
if at is None or at.attr is None or at.value is None or trans is None:
return 0
if at.value.kind() != ast.ASTKind.Name:
return 0
vn: ast.Name* = ast.Name*(at.value)
if vn.id is None:
return 0
v: int = self.Gen.TypeGenCDef.lookup_cdefine_constant(at.attr)
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
self.CifEvalOk = 1
return v
# 跨模块: 确定真实模块名(解析 from_imports 别名)
real_mod: str = vn.id
if trans._from_imports is not None:
resolved: str = self.Gen.ImportsGen.lookup_from_import(trans._from_imports, vn.id, 0)
if resolved is not None:
rm_len: sizet = 0
while resolved[rm_len] != ' ' and resolved[rm_len] != '\0' and resolved[rm_len] != ':':
rm_len += 1
rm_buf: str = pool.alloc(rm_len + 1)
if rm_buf is not None:
for rm_i in range(rm_len):
rm_buf[rm_i] = resolved[rm_i]
rm_buf[rm_len] = '\0'
real_mod = rm_buf
fi_len: sizet = string.strlen(at.attr) + string.strlen(real_mod) + 2
fi: str = pool.alloc(fi_len)
if fi is None:
return 0
viperlib.snprintf(fi, fi_len, "%s:%s", at.attr, real_mod)
v2: int = self.Gen.ExprGenCdef._lookup_cross_module_cdefine(pool, at.attr, fi)
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
self.CifEvalOk = 1
return v2
return 0
def _cif_eval_node(self, pool: memhub.MemBuddy*,
trans: HT.Translator*,
node: ast.AST*) -> int:
"""递归常量求值 CIf 表达式。
支持: Constant(int) / Name(CDefine/跨模块/平台宏) / Attribute(跨模块 CDefine)
/ BinOp(+ - * // % & | ^ << >>) / Compare(== != < > <= >=)
/ BoolOp(and/or) / UnaryOp(not - + ~)。
成功置 self.CifEvalOk=1;失败(含运行时变量)置 0 返回 0。
"""
if node is None:
self.CifEvalOk = 0
return 0
k: int = node.kind()
if k == ast.ASTKind.Constant:
cn: ast.Constant* = ast.Constant*(node)
if cn.const_kind == ast.CONST_INT:
self.CifEvalOk = 1
return cn.int_val
self.CifEvalOk = 0
return 0
if k == ast.ASTKind.Call:
return self._cif_eval_call(pool, trans, node)
if k == ast.ASTKind.Name:
nm: ast.Name* = ast.Name*(node)
if nm.id is None:
self.CifEvalOk = 0
return 0
return self._cif_name_value(pool, trans, nm.id)
if k == ast.ASTKind.Attribute:
at: ast.Attribute* = ast.Attribute*(node)
return self._cif_attr_value(pool, trans, at)
if k == ast.ASTKind.UnaryOp:
uop: ast.UnaryOp* = ast.UnaryOp*(node)
if uop.operand is None:
self.CifEvalOk = 0
return 0
ov: int = self._cif_eval_node(pool, trans, uop.operand)
if self.CifEvalOk == 0:
return 0
if uop.op == ast.OpKind.Not: return 1 if ov == 0 else 0
if uop.op == ast.OpKind.USub: return -ov
if uop.op == ast.OpKind.UAdd: return ov
if uop.op == ast.OpKind.Invert: return ~ov
self.CifEvalOk = 0
return 0
if k == ast.ASTKind.BoolOp:
bo: rawptr[ast.BoolOp] = rawptr[ast.BoolOp](node)
vals: list[ast.AST*]* = bo.values
if vals is None:
self.CifEvalOk = 0
return 0
bn: sizet = len(vals)
if bo.op == ast.OpKind.And:
for bi in range(bn):
rv: int = self._cif_eval_node(pool, trans, vals.get(bi))
if self.CifEvalOk == 0:
return 0
if rv == 0:
return 0
return 1
if bo.op == ast.OpKind.Or:
for bi in range(bn):
rv: int = self._cif_eval_node(pool, trans, vals.get(bi))
if self.CifEvalOk == 0:
return 0
if rv != 0:
return 1
return 0
self.CifEvalOk = 0
return 0
if k == ast.ASTKind.Compare:
cmp: rawptr[ast.Compare] = rawptr[ast.Compare](node)
lv: int = self._cif_eval_node(pool, trans, cmp.left)
if self.CifEvalOk == 0:
return 0
ops_list: list[int] | t.CPtr = (list[int] | t.CPtr)(cmp.ops)
comps: list[ast.AST*]* = cmp.comparators
if ops_list is None or comps is None:
self.CifEvalOk = 0
return 0
cc: sizet = len(comps)
ci: sizet
for ci in range(cc):
rv: int = self._cif_eval_node(pool, trans, comps.get(ci))
if self.CifEvalOk == 0:
return 0
op_id: int = ops_list.get(ci)
ok_cmp: int = 0
if op_id == ast.OpKind.Eq: ok_cmp = 1 if lv == rv else 0
elif op_id == ast.OpKind.Ne: ok_cmp = 1 if lv != rv else 0
elif op_id == ast.OpKind.Lt: ok_cmp = 1 if lv < rv else 0
elif op_id == ast.OpKind.Le: ok_cmp = 1 if lv <= rv else 0
elif op_id == ast.OpKind.Gt: ok_cmp = 1 if lv > rv else 0
elif op_id == ast.OpKind.Ge: ok_cmp = 1 if lv >= rv else 0
else:
self.CifEvalOk = 0
return 0
if ok_cmp == 0:
return 0
lv = rv
return 1
if k == ast.ASTKind.BinOp:
bop: ast.BinOp* = ast.BinOp*(node)
lv: int = self._cif_eval_node(pool, trans, bop.left)
if self.CifEvalOk == 0:
return 0
rv: int = self._cif_eval_node(pool, trans, bop.right)
if self.CifEvalOk == 0:
return 0
if bop.op == ast.OpKind.Add: return lv + rv
if bop.op == ast.OpKind.Sub: return lv - rv
if bop.op == ast.OpKind.Mult: return lv * rv
if bop.op == ast.OpKind.Div:
# 整数常量除法:与 FloorDiv 一致(对齐 TPC ConstEvaluator L354-355)
if rv == 0:
self.CifEvalOk = 0
return 0
return lv // rv
if bop.op == ast.OpKind.FloorDiv:
if rv == 0:
self.CifEvalOk = 0
return 0
return lv // rv
if bop.op == ast.OpKind.Mod:
if rv == 0:
self.CifEvalOk = 0
return 0
return lv % rv
if bop.op == ast.OpKind.BitAnd: return lv & rv
if bop.op == ast.OpKind.BitOr: return lv | rv
if bop.op == ast.OpKind.BitXor: return lv ^ rv
if bop.op == ast.OpKind.LShift: return lv << rv
if bop.op == ast.OpKind.RShift: return lv >> rv
self.CifEvalOk = 0
return 0
self.CifEvalOk = 0
return 0
def _eval_ctraits_isptr(self, symtab: rawptr[GenTypes.SymbolTable],
name: str) -> int:
"""ctraits.isptr(name) 编译期求值。
按变量实际存储类型判断是否指针:alloca 的 pointee 为 Ptr 即指针
(与 TPC ConstEvaluator._eval_compile_time_call 的 LLVM 类型判断一致)。
返回: 1=指针 0=非指针 -1=无法求值(变量不存在/无类型信息)。
"""
if name is None or symtab is None:
return -1
v: llvmlite.Value* = self.Gen.VarGen.lookup_var(symtab, name)
if v is None or v.Ty is None:
return -1
pointee: llvmlite.LLVMType* = v.Ty.Pointee
if pointee is not None and self.Gen.ExprGenBase.is_ptr_type(pointee) != 0:
return 1
return 0
def _cif_eval_call(self, pool: memhub.MemBuddy*,
trans: HT.Translator*,
node: ast.AST*) -> int:
"""编译期函数调用求值:ctraits.isptr(x)。
命中置 self.CifEvalOk=1 返回 1/0;未识别调用置 0 返回 0。
"""
self.CifEvalOk = 0
if node is None or trans is None:
return 0
cl: ast.Call* = ast.Call*(node)
if cl is None or cl.func is None:
return 0
fk: int = cl.func.kind()
if fk != ast.ASTKind.Attribute:
return 0
at: ast.Attribute* = ast.Attribute*(cl.func)
if at.value is None or at.attr is None:
return 0
if at.value.kind() != ast.ASTKind.Name:
return 0
vn: ast.Name* = ast.Name*(at.value)
if vn.id is None:
return 0
if string.strcmp(vn.id, "ctraits") != 0 or string.strcmp(at.attr, "isptr") != 0:
return 0
cargs: list[ast.AST*]* = cl.args
if cargs is None or len(cargs) < 1:
self.CifEvalOk = 0
return 0
arg0: ast.AST* = cargs.get(0)
if arg0 is None or arg0.kind() != ast.ASTKind.Name:
self.CifEvalOk = 0
return 0
nm0: ast.Name* = ast.Name*(arg0)
if nm0.id is None:
self.CifEvalOk = 0
return 0
r: int = self._eval_ctraits_isptr(trans.SymTab, nm0.id)
if r < 0:
self.CifEvalOk = 0
return 0
self.CifEvalOk = 1
return r
def _evaluate_cif_test(self, pool: memhub.MemBuddy*,
trans: HT.Translator*,
test: ast.AST*) -> int:
"""求值 CIf 调用(test 必须是 c.CIf 系调用)。
成功: 置 self.CifEvalOk=1,返回条件值(0/1)
失败(运行时变量/未知结构): 置 self.CifEvalOk=0,返回 0
"""
self.CifEvalOk = 0
cl: ast.Call* = ast.Call*(test)
if cl is None or cl.func is None:
return 0
kind: str = None
fk: int = cl.func.kind()
if fk == ast.ASTKind.Attribute:
at: ast.Attribute* = ast.Attribute*(cl.func)
kind = at.attr
elif fk == ast.ASTKind.Name:
nm: ast.Name* = ast.Name*(cl.func)
kind = nm.id
if kind is None:
return 0
cargs: list[ast.AST*]* = cl.args
if cargs is None or len(cargs) < 1:
return 0
arg0: ast.AST* = cargs.get(0)
if string.strcmp(kind, "CIf") == 0:
v: int = self._cif_eval_node(pool, trans, arg0)
if self.CifEvalOk == 0:
return 0
return 1 if v != 0 else 0
# CIfdef / CIfndef: 判定宏名是否已定义
defined: int = 0
if arg0 is not None and arg0.kind() == ast.ASTKind.Name:
nm0: ast.Name* = ast.Name*(arg0)
if nm0.id is None:
return 0
self._cif_name_value(pool, trans, nm0.id)
defined = self.CifEvalOk
elif arg0 is not None and arg0.kind() == ast.ASTKind.Constant:
cn0: ast.Constant* = ast.Constant*(arg0)
if cn0.const_kind == ast.CONST_STR and cn0.str_val is not None:
self._cif_name_value(pool, trans, cn0.str_val)
defined = self.CifEvalOk
else:
return 0
elif arg0 is not None and arg0.kind() == ast.ASTKind.Attribute:
at0: ast.Attribute* = ast.Attribute*(arg0)
self._cif_attr_value(pool, trans, at0)
defined = self.CifEvalOk
else:
return 0
# 定义判定本身成功(未定义名特判:不报错,defined=0 走 else)
self.CifEvalOk = 1
if string.strcmp(kind, "CIfdef") == 0:
return 1 if defined != 0 else 0
# CIfndef
return 0 if defined != 0 else 1
# ============================================================
# translate_return - Return 语句翻译(迁移自 HandlesReturn.ReturnHandle.Handle)
#
# 翻译返回值(若有)并生成 ret 指令;裸 return 按函数返回类型生成
# 默认零值(void→ret void,ptr→null,float→0.0,其余→零值)。
# ============================================================
def translate_return(self, trans: HT.Translator*,
node: ast.AST*) -> int:
"""翻译 Return 语句"""
rt: rawptr[ast.Return] = rawptr[ast.Return](node)
if rt is None:
return 0
pool: memhub.MemBuddy* = trans.Pool
builder: llvmlite.IRBuilder* = trans._cur_builder
mod: llvmlite.LLVMModule* = trans.Module
val: llvmlite.Value* = None
if rt.value is not None:
# f-string 逃逸(return f"..."):f-string 指向当前函数的栈缓冲,函数返回即
# 失效,返回该指针会让调用方读到已弹栈的帧(历史事故:ASan
# stack-buffer-underflow in vsnprintf)。需要带出函数时先显式拷贝,
# 见 GenApi.escape_fstring_copy。
GenApi.fail_if_fstring_escape(rt.value, "函数返回值")
# return a, b → 打包匿名 struct 值(多返回值,函数返回类型 tuple[T1,T2])
if rt.value.kind() == ast.ASTKind.Tuple:
rtp: ast.Tuple* = ast.Tuple*(rt.value)
rtp_elts: list[ast.AST*]* = rtp.elts
rt_n: sizet = 0
if rtp_elts is not None:
rt_n = len(rtp_elts)
if rt_n > 0 and rt_n <= 16:
rt_vals: sizet* = pool.alloc(8 * 16)
if rt_vals is not None:
rt_val_ok: int = 1
rt_head: llvmlite.ParamNode* = None
rt_tail: llvmlite.ParamNode* = None
rvi: sizet
for rvi in range(rt_n):
ev_i: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, mod, rtp_elts.get(rvi),
trans._funcs, trans._func_count, trans)
if ev_i is None:
rt_val_ok = 0
break
rt_vals[rvi] = sizet(ev_i)
if rt_val_ok != 0:
# 构建匿名 struct 类型(字段类型 = 元素值类型)
rvi2: sizet
for rvi2 in range(rt_n):
rv_i: llvmlite.Value* = llvmlite.Value*((rt_vals[rvi2]))
if rv_i is None or rv_i.Ty is None:
rt_val_ok = 0
break
rn: llvmlite.ParamNode* = llvmlite.new_param_node(pool, rv_i.Ty)
if rn is None:
rt_val_ok = 0
break
if rt_head is None:
rt_head = rn
else:
llvmlite.paramnode_set_next(rt_tail, rn)
rt_tail = rn
rt_struct_ty: llvmlite.LLVMType* = None
if rt_val_ok != 0 and rt_head is not None:
rt_struct_ty = llvmlite.Struct(pool, rt_head, rt_n, None)
rt_tmp: llvmlite.Value* = None
if rt_struct_ty is not None:
rt_tmp = llvmlite.build_alloca(builder, rt_struct_ty)
if rt_tmp is not None:
rvi3: sizet
for rvi3 in range(rt_n):
rv3: llvmlite.Value* = llvmlite.Value*(rt_vals[rvi3])
rfp: llvmlite.Value* = llvmlite.build_gep_struct(builder, rt_struct_ty, rv3.Ty, rt_tmp, rvi3)
if rfp is None:
rt_val_ok = 0
break
llvmlite.build_store(builder, rv3, rfp)
if rt_val_ok != 0:
val = llvmlite.build_load(builder, rt_struct_ty, rt_tmp)
# return self: 返回 self 指针本身(Ptr(StructTy)),而非结构体值
# translate_value 会 load 得到结构体值,但 return self 需要指针
# 注意: lookup_var 返回的是存储 self 的 alloca (Ptr(Ptr(StructTy)))
# 需要 load 得到实际的 self 指针 (Ptr(StructTy))
if rt.value.kind() == ast.ASTKind.Name:
ret_nm: ast.Name* = ast.Name*(rt.value)
if ret_nm is not None and ret_nm.id is not None \
and string.strcmp(ret_nm.id, "self") == 0:
self_ptr: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, "self")
if self_ptr is not None:
# 检查 self_ptr 是否是 Ptr(Ptr(...))(alloca 存储指针)
self_pointee_ty: llvmlite.LLVMType* = None
match self_ptr.Ty:
case llvmlite.LLVMType.Ptr(inner_ty):
self_pointee_ty = inner_ty
if self_pointee_ty is not None and self.Gen.ExprGenBase.is_ptr_type(self_pointee_ty) != 0:
# Ptr(Ptr(StructTy)) → load 得到 Ptr(StructTy)
val = llvmlite.build_load(builder, self_pointee_ty, self_ptr)
else:
val = self_ptr
if val is None:
# P1-A(上下文位宽传播):把当前函数的返回类型作为 target_ty 传入,
# 使 `return 12345`(-> uint64)直接物化 i64 常量,与 `return u64(12345)`
# 一致,并省去下方返回类型对齐生成的 zext。
ret_val_ty: llvmlite.LLVMType* = None
cur_func_rv: llvmlite.Function* = trans._cur_func
if cur_func_rv is not None:
ret_val_ty = llvmlite.function_get_ret_ty(cur_func_rv)
# [C①] 返回注解上下文:记录本次 return 的直接值节点,供裸名泛型
# 构造(`-> Stack[int]` 里 `return Stack()`)用 CurFuncRetAnnot
# 里的类型实参特化;仅该直接值生效(identity 判定在 CallGenCtor)。
trans.CurRetNode = rt.value
val = self.Gen.ExprGen.translate_value(builder, pool, mod, rt.value,
trans._funcs, trans._func_count, trans, ret_val_ty, "返回注解")
trans.CurRetNode = None
# val 为 None 时(裸 return):检查当前函数返回类型
# void 函数(如 __init__/__before_init__)生成 ret void,
# ptr 函数生成 ret ptr null,浮点函数生成 ConstFloat(0.0),
# 否则 ret i32 0(浮点漏处理会报 llc: value doesn't match function result type)
if val is None:
cur_func: llvmlite.Function* = trans._cur_func
is_void_ret: int = 0
is_ptr_ret: int = 0
is_float_ret: int = 0
ret_ty: llvmlite.LLVMType* = None
if cur_func is not None:
ret_ty = llvmlite.function_get_ret_ty(cur_func)
if ret_ty is not None:
match ret_ty:
case llvmlite.LLVMType.Void():
is_void_ret = 1
case llvmlite.LLVMType.Ptr(_pe):
is_ptr_ret = 1
case llvmlite.LLVMType.Float(_fb):
is_float_ret = 1
if is_void_ret != 0:
llvmlite.build_ret_void(builder)
return 0
if is_ptr_ret != 0:
null_val: llvmlite.Value* = llvmlite.ConstNull(pool, ret_ty, "null")
llvmlite.build_ret(builder, null_val)
return 0
if is_float_ret != 0:
zero_f: llvmlite.Value* = llvmlite.ConstFloat(pool, ret_ty, 0.0)
llvmlite.build_ret(builder, zero_f)
return 0
if ret_ty is None:
# fail-fast: 裸 return 无法确定函数返回类型,禁止硬编码 i32 零值兜底
self.Gen.TypeGenErr.fatal_error(rt, "函数返回类型无法确定", "TypeError")
val = llvmlite.ConstZero(pool, ret_ty)
if val is None:
# fail-fast: 无法按返回类型构造零值
self.Gen.TypeGenErr.fatal_error(rt, "函数返回类型无法确定", "TypeError")
# 类型转换:确保 val 类型与函数返回类型匹配
# 处理 i1(bool 比较结果)→ i8(t.CBool)等情况
# i1 → 更宽整数用 zext(bool 语义:1 保持 1,而非 sext 的 0xFF)
# 注意:当 val 是整数而 ret_ty 是 ptr 时(即使 bits 相同,如 i64 vs ptr),
# 也必须 inttoptr 转换,否则 llc 报 "value doesn't match function result type"
cur_func_rt: llvmlite.Function* = trans._cur_func
ret_ty_rt: llvmlite.LLVMType* = None
if cur_func_rt is not None and val is not None and val.Ty is not None:
ret_ty_rt = llvmlite.function_get_ret_ty(cur_func_rt)
# void 函数 return <expr>:丢弃值 + ret void(Python 语义合法;此前
# 直接 build_ret(val) 生成 ret i32 与 define void 冲突 → llc "value
# doesn't match function result type 'void'"——GenApi.add_global_name
# `return g.TranslatorGen.add_global_name(...)` 委托调用根因)。
if ret_ty_rt is not None and val is not None:
rv_void: int = 0
match ret_ty_rt:
case llvmlite.LLVMType.Void():
rv_void = 1
if rv_void != 0:
llvmlite.build_ret_void(builder)
return 0
if ret_ty_rt is not None:
val_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(val.Ty)
ret_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(ret_ty_rt)
val_is_ptr: int = self.Gen.ExprGenBase.is_ptr_type(val.Ty)
ret_is_ptr: int = self.Gen.ExprGenBase.is_ptr_type(ret_ty_rt)
# ptr 类型不一致性:val 是整数但 ret 是 ptr(或反之),必须转换
if val_is_ptr != ret_is_ptr:
# [FIX 2026-08-30] __new__ 返回类型是类指针(T | t.CPtr 语义):
# 返回的实例存储指针来自跨模块调用(如 pool.alloc),Phase A
# 依赖未就绪时其返回类型退化为默认 i32。此时 int→ptr 是退化
# 指针重建而非隐式转换错误——允许 inttoptr,文件保持 pending
# 不写盘,下遍依赖就绪后多遍收敛精确解析(否则 fail-fast 硬
# 中断多遍收敛,memhub↔_list 环永不求解)。
fn_nm_ret: str = None
if cur_func_rt is not None:
fn_nm_ret = llvmlite.function_get_name(cur_func_rt)
if fn_nm_ret is not None and string.strstr(fn_nm_ret, "__new__") is not None \
and val_is_ptr == 0 and ret_is_ptr != 0:
val = llvmlite.build_inttoptr(builder, val, ret_ty_rt)
else:
# 传 trans:Phase A 依赖未就绪(_deps_pending)时,跨模块调用
# 返回类型退化为默认 i32,int→ptr 是退化指针重建而非隐式转换
# 错误,须跳过 fail-fast(与 AssignGenMixin/ExprGenBase 的
# _deps_pending 兜底一致)。否则 return 跨模块指针构造函数
# (如 SSAValue)误报"整数隐式转指针已禁止"。
val = self.Gen.ExprGenBase.coerce_to_type(builder, val, ret_ty_rt, node, trans)
elif val_is_ptr != 0 and ret_is_ptr != 0:
# 指针 → 指针且元素类型不同(如 t\.CVoid(x, CPtr) 得到 i8*,
# 函数返回类型是类指针 Circle* 时)需 bitcast 回,
# 否则 llc 报 "value doesn't match function result type"。
val_pointee: llvmlite.LLVMType* = None
ret_pointee: llvmlite.LLVMType* = None
match val.Ty:
case llvmlite.LLVMType.Ptr(v_inner):
val_pointee = v_inner
match ret_ty_rt:
case llvmlite.LLVMType.Ptr(r_inner):
ret_pointee = r_inner
if val_pointee is not None and ret_pointee is not None \
and uint64(val_pointee) != uint64(ret_pointee):
val = self.Gen.ExprGenBase.coerce_to_type(builder, val, ret_ty_rt, node)
elif val_bits != 0 and ret_bits != 0 and val_bits != ret_bits:
if val_bits == 1 and val_bits < ret_bits:
val = llvmlite.build_zext(builder, val, ret_ty_rt)
else:
# 传 trans:无符号源类型(uint16/uint32/CSizeT 等)扩展用 zext,
# 缺 trans 时 _node_type_unsigned 查不到变量注解 → 误 sext
val = self.Gen.ExprGenBase.coerce_to_type(builder, val, ret_ty_rt, node, trans)
elif self.Gen.ExprGenBase.get_llvm_float_bits(val.Ty) != 0 \
or self.Gen.ExprGenBase.get_llvm_float_bits(ret_ty_rt) != 0:
# Float alignment: SpecTypeBits reports 0 for Float/Double, so the
# integer branch above never runs and a double literal returned from a
# `-> float` function would emit `ret double` (llc: value doesn't match
# function result type 'float'). Coerce here (fpext/fptrunc/si2fp/fptosi),
# same as TPC's emit_return.
val = self.Gen.ExprGenBase.coerce_to_type(builder, val, ret_ty_rt, node, trans)
llvmlite.build_ret(builder, val)
return 0
# ============================================================
# translate_if - if/elif/else 语句翻译(迁移自 HandlesIf.IfHandle.Handle)
#
# 编译期宏条件: if c.CIf(...) / c.CIfdef(...) / c.CIfndef(...)
# 求值成功 → 只编译命中的分支(剪枝,不发射运行时 IR),elif 递归
# 求值失败(运行时变量等)→ 回退运行时翻译。
# 运行时翻译 if 语句为 LLVM IR 控制流:
# br i1 %cond, label %then, label %else
# then:
# ... body ...
# br label %end
# else:
# ... orelse ...
# br label %end
# end:
# ============================================================
def translate_if(self, trans: HT.Translator*,
node: ast.AST*) -> int:
"""翻译 if/elif/else 语句"""
if node is None:
return 0
pool: memhub.MemBuddy* = trans.Pool
builder: llvmlite.IRBuilder* = trans._cur_builder
func: llvmlite.Function* = trans._cur_func
if builder is None or func is None:
return 0
if_node: rawptr[ast.If] = rawptr[ast.If](node)
# 0. 编译期宏条件: if c.CIf(...) / c.CIfdef(...) / c.CIfndef(...)
# 求值成功 → 只编译命中的分支(剪枝,不发射运行时 IR),elif 递归
# 求值失败(运行时变量等)→ 回退运行时翻译
if self._is_cif_call(if_node.test) == 1:
cif_val: int = self._evaluate_cif_test(pool, trans, if_node.test)
if self.CifEvalOk != 0:
if cif_val != 0:
body_cif: list[ast.AST*]* = if_node.children
if body_cif is not None:
bc_cif: sizet = len(body_cif)
bi_cif: sizet
for bi_cif in range(bc_cif):
stmt_cif: ast.AST* = body_cif.get(bi_cif)
if stmt_cif is not None:
self.Gen.StmtGen.translate_stmt(trans, stmt_cif)
else:
orelse_cif: list[ast.AST*]* = if_node.orelse
if orelse_cif is not None and len(orelse_cif) == 1:
sub_cif: ast.AST* = orelse_cif.get(0)
if sub_cif is not None and sub_cif.kind() == ast.ASTKind.If:
# elif: 递归(子 If 的 test 仍会走 CIf 判定或运行时翻译)
self.translate_if(trans, sub_cif)
elif sub_cif is not None:
self.Gen.StmtGen.translate_stmt(trans, sub_cif)
elif orelse_cif is not None:
oc_cif: sizet = len(orelse_cif)
oi_cif: sizet
for oi_cif in range(oc_cif):
stmt_cif2: ast.AST* = orelse_cif.get(oi_cif)
if stmt_cif2 is not None:
self.Gen.StmtGen.translate_stmt(trans, stmt_cif2)
return 0
# 1. 求值条件表达式
cond_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, if_node.test,
trans._funcs, trans._func_count, trans)
# 2. 转换为 i1 条件
# Compare/Not 表达式已返回 i1,直接使用;指针类型与 null 比较;其他类型与 0 比较
if cond_val is None:
# fail-fast: if 条件表达式翻译失败
self.Gen.TypeGenErr.fatal_error(if_node.test, "if 条件表达式翻译失败", "TypeError")
cond_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(cond_val.Ty)
if cond_bits == 1:
cond_i1: llvmlite.Value* = cond_val
elif self.Gen.ExprGenBase.is_ptr_type(cond_val.Ty) != 0:
# 指针类型:与 null 比较(不能用整数 0,否则 llc 报 "integer constant must have integer type")
null_cond: llvmlite.Value* = llvmlite.ConstNull(pool, cond_val.Ty, "null")
cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, null_cond)
else:
zero: llvmlite.Value* = llvmlite.const_int32(pool, 0)
cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, zero)
# 3. 创建基本块(使用 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, "if.then.%d", cnt)
then_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "if.end.%d", cnt)
merge_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
# 检查是否有 else 分支
has_else: int = 0
orelse_list: list[ast.AST*]* = if_node.orelse
if orelse_list is not None:
if len(orelse_list) > 0:
has_else = 1
else_bb: rawptr[llvmlite.BasicBlock] = None
if has_else == 1:
viperlib.snprintf(name_buf, 32, "if.else.%d", cnt)
else_bb = llvmlite.create_block(pool, func, name_buf)
# 4. 发射条件分支
if has_else == 1:
llvmlite.build_cond_br(builder, cond_i1, then_bb, else_bb)
else:
llvmlite.build_cond_br(builder, cond_i1, then_bb, merge_bb)
# 5. 翻译 then body
# 重置 merge 可达标志:分支内嵌套控制流会覆盖该标志,分支末尾判定依据
# "分支最后语句的控制流状态",须防进入本 If 前的残留值污染(append90
# 末句 If 全 return 被 fail-fast 误判"流程掉出末尾"的根因链一环)
trans._ctrl_merge_reachable = 1
llvmlite.position_at_end(builder, then_bb)
body: list[ast.AST*]* = if_node.children
if body is not None:
body_count: sizet = len(body)
for bi in range(body_count):
stmt: ast.AST* = body.get(bi)
if stmt is not None:
self.Gen.StmtGen.translate_stmt(trans, stmt)
# then 块未终止则跳到 merge(记录 then 是否 br 到 merge)
then_branches_merge: int = 0
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
if trans._ctrl_merge_reachable == 0:
# 分支末尾是嵌套控制流且 merge 结构性不可达(全分支 return):
# 当前块是嵌套的 merge(无 terminator),补 unreachable 收尾。
# 不补 br merge——否则外层 If 的"分支是否 br merge"判定把不可达
# 分支当可达,函数末句 If 全 return 被误判"流程掉出末尾"
# (vipermath.vp atan2 根因;对齐 FuncGenDef append90 unreachable)
llvmlite.build_unreachable(builder)
else:
llvmlite.build_br(builder, merge_bb)
then_branches_merge = 1
# 6. 翻译 else body(若有)
else_branches_merge: int = 0
if has_else == 1:
# 同 then:重置标志防残留(else 是普通语句时不被 then 的嵌套控制流值污染)
trans._ctrl_merge_reachable = 1
llvmlite.position_at_end(builder, else_bb)
else_count: sizet = len(orelse_list)
for ei in range(else_count):
stmt: ast.AST* = orelse_list.get(ei)
if stmt is not None:
self.Gen.StmtGen.translate_stmt(trans, stmt)
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
if trans._ctrl_merge_reachable == 0:
# 嵌套控制流全分支 return:补 unreachable,不 br merge(同 then 分支)
llvmlite.build_unreachable(builder)
else:
llvmlite.build_br(builder, merge_bb)
else_branches_merge = 1
# 7. merge 块可达性(末句控制流收尾判定用):无 else 时 cond_br 直接跳 merge(恒可达);
# 有 else 时任一分支 br 到 merge 即可达;全分支 return(无 br)才结构性不可达。
# 经 HandlesBase 模块级全局传递(避免依赖 Translator 字段表)。
trans._ctrl_merge_reachable = 1
if has_else == 1 and then_branches_merge == 0 and else_branches_merge == 0:
trans._ctrl_merge_reachable = 0
# 8. 定位到 merge 块继续后续代码
llvmlite.position_at_end(builder, merge_bb)
return 0
# ============================================================
# translate_while - while 循环语句翻译(迁移自 HandlesWhile.WhileHandle.Handle)
#
# 翻译 while 语句为 LLVM IR 控制流:
# br label %cond
# cond:
# %t = <test>
# %c = icmp ne i32 %t, 0
# br i1 %c, label %body, label %end
# body:
# ... body ...
# br label %cond
# end:
# ============================================================
def translate_while(self, trans: HT.Translator*,
node: ast.AST*) -> int:
"""翻译 while 循环语句"""
if node is None:
return 0
pool: memhub.MemBuddy* = trans.Pool
builder: llvmlite.IRBuilder* = trans._cur_builder
func: llvmlite.Function* = trans._cur_func
if builder is None or func is None:
return 0
while_node: rawptr[ast.While] = rawptr[ast.While](node)
# 1. 创建基本块: cond / body / 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, "while.cond.%d", cnt)
cond_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "while.body.%d", cnt)
body_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "while.end.%d", cnt)
end_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
# 2. 跳转到 cond 块
llvmlite.build_br(builder, cond_bb)
# 3. cond 块: 求值条件,条件分支
llvmlite.position_at_end(builder, cond_bb)
cond_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, while_node.test,
trans._funcs, trans._func_count, trans)
if cond_val is None:
# fail-fast: while 条件表达式翻译失败
self.Gen.TypeGenErr.fatal_error(while_node.test, "while 条件表达式翻译失败", "TypeError")
# Compare/Not 表达式已返回 i1,直接使用;指针类型与 null 比较;其他类型与 0 比较
cond_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(cond_val.Ty)
if cond_bits == 1:
cond_i1: llvmlite.Value* = cond_val
elif self.Gen.ExprGenBase.is_ptr_type(cond_val.Ty) != 0:
# 指针类型:与 null 比较(不能用整数 0,否则 llc 报 "integer constant must have integer type")
null_cond: llvmlite.Value* = llvmlite.ConstNull(pool, cond_val.Ty, "null")
cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, null_cond)
else:
zero: llvmlite.Value* = llvmlite.const_int32(pool, 0)
cond_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, cond_val, zero)
llvmlite.build_cond_br(builder, cond_i1, body_bb, end_bb)
# 4. body 块: 翻译循环体,跳回 cond
llvmlite.position_at_end(builder, body_bb)
# 保存旧循环上下文,设置 break/continue 目标
old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
old_continue: rawptr[llvmlite.BasicBlock] = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = cond_bb
body: list[ast.AST*]* = while_node.children
if body is not None:
body_count: sizet = len(body)
for bi in range(body_count):
stmt: ast.AST* = body.get(bi)
if stmt is not None:
self.Gen.StmtGen.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, cond_bb)
# 5. 定位到 end 块
llvmlite.position_at_end(builder, end_bb)
# 追加90:while 的 cond_br 恒引用 end_bb → merge 恒可达(需正常收尾)
trans._ctrl_merge_reachable = 1
# 无限循环(条件常量真 1/True)且循环体无本层 break → 运行时无任何边
# 到达 end 块(merge 结构性不可达)→ 置 0,函数收尾对末句 While 生成
# unreachable(追加90:无 br 到达 merge 时才安全;否则 llc O2 把
# br-to-unreachable 优化为 fall-through → 双分支执行崩溃)。
# 修复 vrandom.gammavariate 的 while True 全 return 被误判"流程掉出末尾"。
if self._IsConstTrue(while_node.test) != 0 and self._StmtHasBreak(body) == 0:
trans._ctrl_merge_reachable = 0
return 0
# ============================================================
# 无限循环判定辅助(merge 可达性,迁移自 HandlesWhile 模块级函数)
#
# _IsConstTrue: while 条件为常量真(CONST_INT 非 0 / CONST_BOOL 真)
# _NodeHasBreak / _StmtHasBreak: 扫描本层 break(跳过嵌套 While/For
# 子树——嵌套循环的 break 归内层,不影响外层 merge 可达性)
# ============================================================
def _IsConstTrue(self, test: ast.AST*) -> int:
"""while 条件为常量真(1 / True)返回 1"""
if test is None:
return 0
if test.kind() == ast.ASTKind.Constant:
cn: ast.Constant* = ast.Constant*(test)
if cn.const_kind == ast.CONST_INT and cn.int_val != 0:
return 1
if cn.const_kind == ast.CONST_BOOL and cn.int_val != 0:
return 1
return 0
def _NodeHasBreak(self, node: ast.AST*) -> int:
"""递归扫描节点子树(跳过嵌套 While/For 子树),含 Break 返回 1"""
if node is None:
return 0
ch: list[ast.AST*]* = node.children
if ch is not None:
n: sizet = len(ch)
for bi in range(n):
c: ast.AST* = ch.get(bi)
if c is None:
continue
k: int = c.kind()
if k == ast.ASTKind.Break:
return 1
if k == ast.ASTKind.While or k == ast.ASTKind.For:
continue
if self._NodeHasBreak(c) != 0:
return 1
return 0
def _StmtHasBreak(self, body: list[ast.AST*]*) -> int:
"""语句列表是否含本层 break(嵌套循环的 break 归内层)"""
if body is None:
return 0
n: sizet = len(body)
for bi in range(n):
s: ast.AST* = body.get(bi)
if s is None:
continue
k: int = s.kind()
if k == ast.ASTKind.Break:
return 1
if k == ast.ASTKind.While or k == ast.ASTKind.For:
continue
if self._NodeHasBreak(s) != 0:
return 1
return 0
# ============================================================
# translate_for - for 循环语句翻译(迁移自 HandlesFor.ForHandle.Handle)
#
# 支持 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:
# ============================================================
def translate_for(self, trans: HT.Translator*,
node: ast.AST*) -> int:
"""翻译 for i in range(...) 循环语句"""
if node is None:
return 0
pool: memhub.MemBuddy* = trans.Pool
builder: llvmlite.IRBuilder* = trans._cur_builder
func: llvmlite.Function* = trans._cur_func
if builder is None or func is None:
return 0
for_node: ast.For* = ast.For*(node)
# 1. 获取循环变量(Name 单变量 / Tuple 多变量)
target: ast.AST* = 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* = ast.Name*(target)
var_name = target_nm.id
if var_name is None:
return 0
# 2. 解析迭代器:支持 range() 和指针迭代
iter_node: ast.AST* = 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* = ast.Call*(iter_node)
fn_pre: str = self.Gen.ExprGenBase.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)
self.Gen.TypeGenErr.fatal_error(iter_node, err_msg)
self.Gen.TypeGenErr.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(trans, 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* = ast.Call*(iter_node)
fn_mi: str = self.Gen.ExprGenBase.get_func_name(call_mi.func)
if fn_mi is not None and string.strcmp(fn_mi, "enumerate") == 0:
if tk != ast.ASTKind.Tuple:
self.Gen.TypeGenErr.fatal_error(iter_node, "enumerate 迭代需要两个循环变量 (for i, v in enumerate(x))")
tup_ie: ast.Tuple* = ast.Tuple*(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:
self.Gen.TypeGenErr.fatal_error(iter_node, "enumerate 迭代变量必须是简单名称")
return self._handle_enumerate_iter(trans, 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:
self.Gen.TypeGenErr.fatal_error(iter_node, "zip 迭代需要两个循环变量 (for a, b in zip(...))")
tup_iz: ast.Tuple* = ast.Tuple*(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:
self.Gen.TypeGenErr.fatal_error(iter_node, "zip 迭代变量必须是简单名称")
return self._handle_zip_iter(trans, 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* = ast.Name*(iter_node)
if nm_lst.id is not None:
ve_lst: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm_lst.id)
lst_annot: str = self.Gen.VarGen.var_annot_class_name(ve_lst)
if lst_annot is not None:
# dict 容器变量:按 __count__/__keys__ 布局迭代(__iter__ 协议内联)
# [S4] 容器基名精确比较(SpecTypeNameBaseIs):原 strstr("dict") 子串匹配
# 会误命中任何含 "dict" 的类名(如 MyDictHelper)。
if TSpec.SpecTypeNameBaseIs(lst_annot, "dict") != 0:
lst_val: llvmlite.Value* = self.Gen.ExprGen.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 self.Gen.ExprGenBase.is_ptr_type(lst_val.Ty) != 0:
return self._handle_dict_iter(trans, for_node, var_name, lst_val)
# [S4] 同上:原 strstr("list") 会误命中 playlist / GSList 等;
# 非 list 基名的用户类改由下方 OOP __iter__/__next__ 路径处理(更正确)。
if TSpec.SpecTypeNameBaseIs(lst_annot, "list") != 0:
lst_val: llvmlite.Value* = self.Gen.ExprGen.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 self.Gen.ExprGenBase.is_ptr_type(lst_val.Ty) != 0:
return self._handle_list_iter(trans, for_node, var_name, lst_val)
# OOP iter 协议:迭代源是类对象且类有 __iter__/__next__ 方法 →
# 走 __iter__/__next__ 调用迭代(对齐 TPC HandlesFor.py L142-166
# _HandleForIterLlvm)。dict/list 是内置泛型容器已在上方内联处理。
ov_val: llvmlite.Value* = self.Gen.ExprGen.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 self.Gen.ExprGenBase.is_ptr_type(ov_val.Ty) != 0:
ov_st: llvmlite.LLVMType* = self.Gen.StructGen.get_struct_type_from_value(ov_val)
if ov_st is not None:
ov_cn: str = self.Gen.StructGen.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* = self.Gen.CallGenBase.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* = self.Gen.CallGenBase.find_func_in_module(trans.Module, on_lookup)
if on_fn is not None:
return self._handle_oop_iter(trans, 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* = ast.Constant*(iter_node)
if cn_ik.const_kind != ast.CONST_STR:
self.Gen.TypeGenErr.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:
self.Gen.TypeGenErr.fatal_error(iter_node, "for 迭代不支持字典/集合/元组字面量,请使用 range()、t.CArray 数组或列表字面量")
return self._handle_ptr_iter(trans, for_node, var_name)
call: ast.Call* = ast.Call*(iter_node)
# 3. 解析 range 参数: range(stop) / range(start, stop) / range(start, stop, step)
args: list[ast.AST*]* = call.args
if args is None:
return 0
arg_count: sizet = len(args)
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
start_val: llvmlite.Value* = llvmlite.const_int32(pool, 0)
stop_val: llvmlite.Value* = None
step_val: llvmlite.Value* = llvmlite.const_int32(pool, 1)
if arg_count == 0:
# fail-fast: range 无参数,立即终止
self.Gen.TypeGenErr.fatal_error(call, "range 需要至少一个参数", "SyntaxError")
elif arg_count == 1:
stop_val = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, args.get(0), trans._funcs, trans._func_count, trans)
if stop_val is None:
# fail-fast: range 参数翻译失败
self.Gen.TypeGenErr.fatal_error(args.get(0), "range 参数翻译失败", "TypeError")
elif arg_count >= 2:
start_val = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, args.get(0), trans._funcs, trans._func_count, trans)
if start_val is None:
# fail-fast: range 参数翻译失败
self.Gen.TypeGenErr.fatal_error(args.get(0), "range 参数翻译失败", "TypeError")
stop_val = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, args.get(1), trans._funcs, trans._func_count, trans)
if stop_val is None:
# fail-fast: range 参数翻译失败
self.Gen.TypeGenErr.fatal_error(args.get(1), "range 参数翻译失败", "TypeError")
if arg_count >= 3:
step_val = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, args.get(2), trans._funcs, trans._func_count, trans)
if step_val is None:
# fail-fast: range 参数翻译失败
self.Gen.TypeGenErr.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* = 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* = ast.UnaryOp*(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* = ast.Constant*(uop_r.operand)
if uoc_r.int_val > 0:
step_neg_const = 1
elif skn == ast.ASTKind.Constant:
skc_r: ast.Constant* = ast.Constant*(step_arg_node)
if skc_r.int_val < 0:
step_neg_const = 1
# 3.5 循环变量存储位宽随 range 参数类型(uint64→i64 / uint16→i16 / uint8→i8 / 其余→i32),
# 不固定 i32:固定 i32 alloca 会截断 uint64 上界(range(heap_end, new_end, 4096)
# 生成 trunc i64→i32 → 高 32 位丢失 → 映射地址错误)。仅当循环变量尚未声明时生效;
# 已声明变量沿用其 alloca 元素类型(见下方 loop_var_ty 解引用)。
loop_store_ty: llvmlite.LLVMType* = i32_ty
range_arg_bits: int = 0
if arg_count == 1:
if stop_val is not None and stop_val.Ty is not None:
range_arg_bits = self.Gen.ExprGenBase.get_llvm_type_bits(stop_val.Ty)
else:
start_bits_rt: int = 0
stop_bits_rt: int = 0
if start_val is not None and start_val.Ty is not None:
start_bits_rt = self.Gen.ExprGenBase.get_llvm_type_bits(start_val.Ty)
if stop_val is not None and stop_val.Ty is not None:
stop_bits_rt = self.Gen.ExprGenBase.get_llvm_type_bits(stop_val.Ty)
range_arg_bits = start_bits_rt if start_bits_rt > stop_bits_rt else stop_bits_rt
if range_arg_bits == 64:
loop_store_ty = llvmlite.Int64(pool)
elif range_arg_bits == 16:
loop_store_ty = llvmlite.Int16(pool)
elif range_arg_bits == 8:
loop_store_ty = llvmlite.Int8(pool)
# 3.6 循环无符号性:循环变量注解或任一 range 边界为无符号整型 →
# icmp ult/ugt 而非 slt/sgt(复用 ExprGenOps._node_type_unsigned:
# Name 查 SymTab 注解 / Call 转换目标 / Subscript 元素 / BinOp 递归)。
# syscall 的 va 未声明,靠边界 heap_end/new_end(uint64)判定;
# fat32 的 i/s 已声明 uint32/uint8,靠循环变量注解判定。
loop_unsigned: int = 0
if tk == ast.ASTKind.Name:
if self.Gen.ExprGenOps._node_type_unsigned(pool, target, trans) != 0:
loop_unsigned = 1
if loop_unsigned == 0:
args_u: sizet
for args_u in range(arg_count):
if self.Gen.ExprGenOps._node_type_unsigned(pool, args.get(args_u), trans) != 0:
loop_unsigned = 1
break
# 3.7 stop 边界为负数字面量(-1 / -N)→ 撤回无符号谓词,必须用有符号比较。
# 倒序循环条件为 i > stop;stop = -1 在无符号域里是 UINT_MAX,任何 i
# 都 ugt 不过它 → 条件恒假 → 循环体整段变死代码。TPC 的 for 条件只按
# 循环变量注解定符号性(HandlesFor.py L218 `Gen._is_var_unsigned`),
# 未声明循环变量的 range(top - 1, -1, -1) 走有符号 sgt 可正常执行;
# 边界推导(上文 3.6)把「start 边界无符号」也算成无符号,覆盖了负步长的
# SGT(即 step_neg_const 处注释里「修复 _find_provider 的
# range(top-1,-1,-1) 循环体不执行」失效)→ _find_provider 恒返回 NULL
# → with 上下文的 __mbuddy__ 注入不上(FakeDuckTest Test 9 FAIL +
# 后续 _str.upper 解引用 NULL 崩溃)。负数字面量语义上属有符号域,
# 此处无条件退回有符号谓词(slt/sgt),与 3.6 的无符号优化不冲突。
stop_neg_const: int = 0
if arg_count >= 2:
stop_arg_node: ast.AST* = args.get(1)
if stop_arg_node is not None:
stn_k: int = stop_arg_node.kind()
if stn_k == ast.ASTKind.UnaryOp:
stop_uop: ast.UnaryOp* = ast.UnaryOp*(stop_arg_node)
if stop_uop.op == ast.OpKind.USub and stop_uop.operand is not None:
if stop_uop.operand.kind() == ast.ASTKind.Constant:
stop_uc: ast.Constant* = ast.Constant*(stop_uop.operand)
if stop_uc.int_val > 0:
stop_neg_const = 1
elif stn_k == ast.ASTKind.Constant:
stop_c: ast.Constant* = ast.Constant*(stop_arg_node)
if stop_c.int_val < 0:
stop_neg_const = 1
if stop_neg_const != 0:
loop_unsigned = 0
# 4. 创建/查找循环变量 alloca
# 必须用 lookup_current(仅当前作用域):闭包内 lookup_var 会跨函数
# 命中父函数同名变量(如父函数自己的循环计数器 i)→ 循环计数写到
# 父函数存储 → 跨函数 SSA 错乱(llc "instruction expected to be
# numbered",Terminal _cmd_cd 的 for i in range(1,64) 根因)。
var_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_current(trans.SymTab, var_name)
new_vars: int = 0
if var_alloca is None:
# 用 _alloca_at_entry:alloca 放函数入口块,保证支配性
# (内联 build_alloca 若 preheader 是分支块(如 if.then),
# 循环三块跨块使用 → llc "Instruction does not dominate all
# uses!",Terminal _cmd_cd 的 for i in range(1,64) 根因)。
# 闭包跨函数命中父函数变量的根因已由 lookup_current 修复,
# 故 entry 插入路径安全。
# 位宽随 range 参数类型(loop_store_ty),不再固定 i32:
# uint64 上界 → i64 alloca,避免 trunc i64→i32 丢失高位。
var_alloca = self.Gen.VarGen._alloca_at_entry(builder, loop_store_ty)
if self.Gen.VarGen.define_var(trans.SymTab, var_name, var_alloca) == 0:
new_vars = 1
# 获取循环变量的实际元素类型(alloca 是指针类型,需解引用 Pointee)
# 当循环变量已声明为 i64(如 sizet),使用 i64 而非硬编码 i32
# 避免 load i32, i64* / store i32, i64* 类型不匹配
loop_var_ty: llvmlite.LLVMType* = 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 = self.Gen.ExprGenBase.get_llvm_type_bits(loop_var_ty)
# 5. 存储初始值 (类型对齐: start_val 可能是 i32/i64,需对齐到 loop_var_ty)
init_val: llvmlite.Value* = start_val
if start_val is not None and start_val.Ty is not None:
start_bits: int = self.Gen.ExprGenBase.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: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "for.body.%d", cnt)
body_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "for.incr.%d", cnt)
incr_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "for.end.%d", cnt)
end_bb: rawptr[llvmlite.BasicBlock] = 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* = llvmlite.build_load(builder, loop_var_ty, var_alloca)
# 类型对齐: stop_val 可能是 i64 (如 range(strlen(s))),需将 cur_i 提升到 stop_val 类型
cmp_lhs: llvmlite.Value* = cur_i
cmp_rhs: llvmlite.Value* = stop_val
if stop_val is not None and stop_val.Ty is not None:
stop_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(stop_val.Ty)
cur_bits: int = self.Gen.ExprGenBase.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 位宽(如 sizet 循环变量 + range(i32)):应把 cur_i 截断到
# stop_val 类型(低向高才 sext/zext,高向低用 trunc)。反过来把小的 stop_val
# 扩宽会生成非法 IR(llc "invalid cast opcode for cast from 'i32' to 'i64'")。
cmp_lhs = llvmlite.build_trunc(builder, cur_i, stop_val.Ty)
# 有符号基准谓词:step 为负时条件反转(i > stop,SGT);正/缺省 i < stop(SLT)
range_cmp_op: int = llvmlite.ICMP_SLT
if step_neg_const != 0:
range_cmp_op = llvmlite.ICMP_SGT
# 无符号循环:改用无符号谓词(正步长 ult / 负步长 ugt)
if loop_unsigned != 0:
if step_neg_const != 0:
range_cmp_op = llvmlite.ICMP_UGT
else:
range_cmp_op = llvmlite.ICMP_ULT
cond_i1: llvmlite.Value* = 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: rawptr[llvmlite.BasicBlock] = trans._break_bb
old_continue: rawptr[llvmlite.BasicBlock] = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = incr_bb
body: list[ast.AST*]* = for_node.children
if body is not None:
body_count: sizet = len(body)
for bi in range(body_count):
stmt: ast.AST* = body.get(bi)
if stmt is not None:
self.Gen.StmtGen.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* = llvmlite.build_load(builder, loop_var_ty, var_alloca)
# 类型对齐: step_val 可能是 i32/i64,需对齐到 loop_var_ty 与 cur_i2 类型一致
incr_step: llvmlite.Value* = step_val
if step_val is not None and step_val.Ty is not None:
step_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(step_val.Ty)
cur2_bits: int = self.Gen.ExprGenBase.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* = 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
# ============================================================
# 多变量迭代辅助(enumerate / zip,迁移自 ForHandleBase)
#
# 支持迭代源: 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*,
out1: str, out2: str) -> 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*]* = tup.elts
n: sizet = len(elts)
if n < 2:
return 0
e0: ast.AST* = elts.get(0)
e1: ast.AST* = 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* = ast.Name*(e0)
n1: ast.Name* = ast.Name*(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, trans: HT.Translator*,
src: ast.AST*) -> 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* = ast.Call*(src)
fn_s: str = self.Gen.ExprGenBase.get_func_name(cl_s.func)
if fn_s is not None and string.strcmp(fn_s, "range") == 0:
return GenTypes.SEQ_KIND_RANGE
return 0
if k == ast.ASTKind.Constant:
cn_s: ast.Constant* = ast.Constant*(src)
if cn_s is not None and cn_s.const_kind == ast.CONST_STR:
return GenTypes.SEQ_KIND_STR
return 0
if k == ast.ASTKind.Name:
nm_s: ast.Name* = ast.Name*(src)
if nm_s.id is not None and trans is not None:
ve_s: GenTypes.VarEntry* = self.Gen.VarGen.lookup_var_entry(trans.SymTab, nm_s.id)
sq_annot: str = self.Gen.VarGen.var_annot_class_name(ve_s)
if sq_annot is not None:
# [S4] 容器基名精确比较(原 strstr("list") 子串匹配会误命中 playlist 等)
if TSpec.SpecTypeNameBaseIs(sq_annot, "list") != 0:
return GenTypes.SEQ_KIND_LIST
return GenTypes.SEQ_KIND_STR
return 0
def _build_seq_loop(self, trans: HT.Translator*,
for_node: ast.For*,
t1: str, t2: str,
src1: ast.AST*,
src2: ast.AST*,
n_srcs: int) -> int:
"""生成序列迭代循环(enumerate: n_srcs=1 / zip: n_srcs=2)
循环变量 alloca 自动创建或复用;元素类型由源类型决定
(RANGE→i32, STR→i8, LIST→i8*)。索引内部统一 i64。
"""
pool: memhub.MemBuddy* = trans.Pool
builder: llvmlite.IRBuilder* = trans._cur_builder
func: llvmlite.Function* = trans._cur_func
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
# ---- 源 1 准备 ----
kind1: int = self._seq_kind(trans, src1)
if kind1 == 0:
self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: 源 1 类型不支持")
r1_start: llvmlite.Value* = None
r1_stop: llvmlite.Value* = None
r1_step: llvmlite.Value* = None
s1_ptr: llvmlite.Value* = None
l1_count: llvmlite.Value* = None
l1_data: llvmlite.Value* = None
l1_esize: llvmlite.Value* = None
elem1_ty: llvmlite.LLVMType* = i8_ptr_ty
if kind1 == GenTypes.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* = ast.Call*(src1)
cargs1: list[ast.AST*]* = call_src1.args
if cargs1 is not None:
n1: sizet = len(cargs1)
if n1 >= 1:
sv: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, cargs1.get(0),
trans._funcs, trans._func_count, trans)
if sv is None:
# fail-fast: range 参数翻译失败
self.Gen.TypeGenErr.fatal_error(cargs1.get(0), "range 参数翻译失败", "TypeError")
r1_stop = self.Gen.ExprGenBase.coerce_to_type(builder, sv, i64_ty, cargs1.get(0))
if n1 >= 2:
sv2: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, cargs1.get(1), trans._funcs, trans._func_count, trans)
if sv2 is None:
# fail-fast: range 参数翻译失败
self.Gen.TypeGenErr.fatal_error(cargs1.get(1), "range 参数翻译失败", "TypeError")
r1_start = self.Gen.ExprGenBase.coerce_to_type(builder, sv2, i64_ty, cargs1.get(1))
if n1 >= 3:
sv3: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, cargs1.get(2), trans._funcs, trans._func_count, trans)
if sv3 is None:
# fail-fast: range 参数翻译失败
self.Gen.TypeGenErr.fatal_error(cargs1.get(2), "range 参数翻译失败", "TypeError")
r1_step = self.Gen.ExprGenBase.coerce_to_type(builder, sv3, i64_ty, cargs1.get(2))
elif kind1 == GenTypes.SEQ_KIND_STR:
elem1_ty = i8_ty
s1_ptr = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, src1, trans._funcs, trans._func_count, trans)
if s1_ptr is None:
self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: 字符串源翻译失败")
elif kind1 == GenTypes.SEQ_KIND_LIST:
elem1_ty = i8_ptr_ty
l1_obj: llvmlite.Value* = self.Gen.ExprGen.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 self.Gen.ExprGenBase.is_ptr_type(l1_obj.Ty) == 0:
self.Gen.TypeGenErr.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* = elem1_ty
s2_ptr: llvmlite.Value* = None
l2_count: llvmlite.Value* = None
l2_data: llvmlite.Value* = None
l2_esize: llvmlite.Value* = None
r2_start: llvmlite.Value* = None
r2_stop: llvmlite.Value* = None
r2_step: llvmlite.Value* = None
if n_srcs >= 2:
kind2 = self._seq_kind(trans, src2)
if kind2 == 0:
self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: 源 2 类型不支持")
if kind2 == GenTypes.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* = ast.Call*(src2)
cargs2: list[ast.AST*]* = call_src2.args
if cargs2 is not None:
n2: sizet = len(cargs2)
if n2 >= 1:
svz: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, cargs2.get(0), trans._funcs, trans._func_count, trans)
if svz is None:
# fail-fast: range 参数翻译失败
self.Gen.TypeGenErr.fatal_error(cargs2.get(0), "range 参数翻译失败", "TypeError")
r2_stop = self.Gen.ExprGenBase.coerce_to_type(builder, svz, i64_ty, cargs2.get(0))
if n2 >= 2:
svz2: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, cargs2.get(1), trans._funcs, trans._func_count, trans)
if svz2 is None:
# fail-fast: range 参数翻译失败
self.Gen.TypeGenErr.fatal_error(cargs2.get(1), "range 参数翻译失败", "TypeError")
r2_start = self.Gen.ExprGenBase.coerce_to_type(builder, svz2, i64_ty, cargs2.get(1))
if n2 >= 3:
svz3: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, cargs2.get(2), trans._funcs, trans._func_count, trans)
if svz3 is None:
# fail-fast: range 参数翻译失败
self.Gen.TypeGenErr.fatal_error(cargs2.get(2), "range 参数翻译失败", "TypeError")
r2_step = self.Gen.ExprGenBase.coerce_to_type(builder, svz3, i64_ty, cargs2.get(2))
elif kind2 == GenTypes.SEQ_KIND_STR:
elem2_ty = i8_ty
s2_ptr = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, src2, trans._funcs, trans._func_count, trans)
if s2_ptr is None:
self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: 字符串源 2 翻译失败")
elif kind2 == GenTypes.SEQ_KIND_LIST:
elem2_ty = i8_ptr_ty
l2_obj: llvmlite.Value* = self.Gen.ExprGen.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 self.Gen.ExprGenBase.is_ptr_type(l2_obj.Ty) == 0:
self.Gen.TypeGenErr.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* = self.Gen.VarGen.lookup_var(trans.SymTab, t1)
new_vars: int = 0
if t1_alloca is None:
if n_srcs == 1:
t1_alloca = self.Gen.VarGen._alloca_at_entry(builder, i32_ty)
else:
t1_alloca = self.Gen.VarGen._alloca_at_entry(builder, elem1_ty)
if t1_alloca is not None:
if self.Gen.VarGen.define_var(trans.SymTab, t1, t1_alloca) == 0:
new_vars += 1
# t2: 源 2 元素(enumerate 时 = 源 1 元素)
t2_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, t2)
if t2_alloca is None:
t2_alloca = self.Gen.VarGen._alloca_at_entry(builder, elem2_ty)
if t2_alloca is not None:
if self.Gen.VarGen.define_var(trans.SymTab, t2, t2_alloca) == 0:
new_vars += 1
# 隐式 index 变量 (i64)
idx_alloca: llvmlite.Value* = self.Gen.VarGen._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: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "seq.body.%d", cnt)
body_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "seq.incr.%d", cnt)
incr_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "seq.end.%d", cnt)
end_bb: rawptr[llvmlite.BasicBlock] = 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* = llvmlite.build_load(builder, i64_ty, idx_alloca)
done1: llvmlite.Value* = None
if kind1 == GenTypes.SEQ_KIND_RANGE:
done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, r1_stop)
elif kind1 == GenTypes.SEQ_KIND_STR:
ch_ptr1: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, s1_ptr, cur_idx)
ch1: llvmlite.Value* = llvmlite.build_load(builder, i8_ty, ch_ptr1)
zero1: llvmlite.Value* = llvmlite.const_int(pool, 8, 0)
done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, ch1, zero1)
elif kind1 == GenTypes.SEQ_KIND_LIST:
done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, l1_count)
cont: llvmlite.Value* = done1
if n_srcs >= 2:
done2: llvmlite.Value* = None
if kind2 == GenTypes.SEQ_KIND_RANGE:
done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, r2_stop)
elif kind2 == GenTypes.SEQ_KIND_STR:
ch_ptr2: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, s2_ptr, cur_idx)
ch2: llvmlite.Value* = llvmlite.build_load(builder, i8_ty, ch_ptr2)
zero2: llvmlite.Value* = llvmlite.const_int(pool, 8, 0)
done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, ch2, zero2)
elif kind2 == GenTypes.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* = None
if kind1 == GenTypes.SEQ_KIND_RANGE:
step1: llvmlite.Value* = llvmlite.build_mul(builder, cur_idx, r1_step)
v1 = llvmlite.build_add(builder, r1_start, step1)
elif kind1 == GenTypes.SEQ_KIND_STR:
ch_ptr1b: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, s1_ptr, cur_idx)
v1 = llvmlite.build_load(builder, i8_ty, ch_ptr1b)
elif kind1 == GenTypes.SEQ_KIND_LIST:
off1: llvmlite.Value* = llvmlite.build_mul(builder, cur_idx, l1_esize)
addr1: llvmlite.Value* = 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* = t1_alloca.Ty.Pointee
if n_srcs == 1:
# enumerate: t1 = 序号(trunc i64 → i32)
idx32: llvmlite.Value* = 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* = t2_alloca.Ty.Pointee
v1c: llvmlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, v1, t2_ty, src1)
llvmlite.build_store(builder, v1c, t2_alloca)
else:
if v1 is not None:
v1c: llvmlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, v1, t1_ty, src1)
llvmlite.build_store(builder, v1c, t1_alloca)
# 源 2 元素 → t2
v2: llvmlite.Value* = None
if kind2 == GenTypes.SEQ_KIND_RANGE:
step2: llvmlite.Value* = llvmlite.build_mul(builder, cur_idx, r2_step)
v2 = llvmlite.build_add(builder, r2_start, step2)
elif kind2 == GenTypes.SEQ_KIND_STR:
ch_ptr2b: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, s2_ptr, cur_idx)
v2 = llvmlite.build_load(builder, i8_ty, ch_ptr2b)
elif kind2 == GenTypes.SEQ_KIND_LIST:
off2: llvmlite.Value* = llvmlite.build_mul(builder, cur_idx, l2_esize)
addr2: llvmlite.Value* = 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* = t2_alloca.Ty.Pointee
v2c: llvmlite.Value* = self.Gen.ExprGenBase.coerce_to_type(builder, v2, t2_ty2, src2)
llvmlite.build_store(builder, v2c, t2_alloca)
# 保存旧循环上下文,设置 break/continue 目标
old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
old_continue: rawptr[llvmlite.BasicBlock] = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = incr_bb
body: list[ast.AST*]* = for_node.children
if body is not None:
body_count: sizet = len(body)
for bi in range(body_count):
stmt: ast.AST* = body.get(bi)
if stmt is not None:
self.Gen.StmtGen.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* = llvmlite.const_int64(pool, 1)
next_idx: llvmlite.Value* = 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
# ============================================================
# _handle_ptr_iter - 指针迭代: for x in ptr:(迁移自 ForHandleIter)
# 遍历指针,依赖隐式 index,直到解引用为空(null 终止符)
#
# 生成 IR 结构:
# %idx = alloca i32
# store i32 0, i32* %idx
# br label %cond
# cond:
# %i = load i32, i32* %idx
# %ep = getelementptr elem_ty, ptr_ty %ptr, i32 %i
# %ev = load elem_ty, elem_ty* %ep
# %null = icmp eq elem_ty %ev, 0
# br i1 %null, label %end, label %body
# body:
# store elem_ty %ev, elem_ty* %var
# ... 循环体 ...
# br label %incr
# incr:
# %next = add i32 %i, 1
# store i32 %next, i32* %idx
# br label %cond
# end:
# ============================================================
def _handle_ptr_iter(self, trans: HT.Translator*,
for_node: ast.For*,
var_name: str) -> int:
"""指针迭代: for x in ptr: 直到解引用为空"""
pool: memhub.MemBuddy* = trans.Pool
builder: llvmlite.IRBuilder* = trans._cur_builder
func: llvmlite.Function* = trans._cur_func
# 翻译迭代器表达式,获取指针值
ptr_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, for_node.iter, trans._funcs, trans._func_count, trans)
if ptr_val is None:
self.Gen.TypeGenErr.fatal_error(for_node, "指针迭代: 无法翻译迭代器表达式")
# 检查迭代器类型
if self.Gen.ExprGenBase.is_ptr_type(ptr_val.Ty) == 0:
# 数组迭代:for k in arr(定长数组按长度迭代,元素可为任意类型)
if self.Gen.ExprGenBase.is_array_type(ptr_val.Ty) != 0:
return self._handle_array_iter(trans, for_node, var_name, ptr_val)
self.Gen.TypeGenErr.fatal_error(for_node, "指针迭代: 迭代器不是指针类型")
# 获取元素类型
elem_ty: llvmlite.LLVMType* = ptr_val.Ty.Pointee
if elem_ty is None:
self.Gen.TypeGenErr.fatal_error(for_node, "指针迭代: 无法获取元素类型")
# 元素类型是数组(Ptr([N x T]),如 t.CArray 变量退化指针):
# load 出数组值后走数组迭代(按长度,非 null 终止)
if self.Gen.ExprGenBase.is_array_type(elem_ty) != 0:
arr_v2: llvmlite.Value* = llvmlite.build_load(builder, elem_ty, ptr_val)
if arr_v2 is not None:
return self._handle_array_iter(trans, for_node, var_name, arr_v2)
# 元素类型决定"空值"判定(用户语义:解引用后为空即终止):
# 整数 → ==0;指针(如 i8** 遍历的元素 i8*)→ ==null;浮点 → ==0.0
elem_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(elem_ty)
elem_is_ptr2: int = self.Gen.ExprGenBase.is_ptr_type(elem_ty)
elem_fbits2: int = self.Gen.ExprGenBase.get_llvm_float_bits(elem_ty)
if elem_bits == 0 and elem_is_ptr2 == 0 and elem_fbits2 == 0:
self.Gen.TypeGenErr.fatal_error(for_node, "指针迭代: 元素类型不是整数/指针/浮点,无法检查空终止符")
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
# 创建循环变量 alloca(存储元素值)
var_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, var_name)
new_vars: int = 0
if var_alloca is None:
var_alloca = self.Gen.VarGen._alloca_at_entry(builder, elem_ty)
if self.Gen.VarGen.define_var(trans.SymTab, var_name, var_alloca) == 0:
new_vars = 1
# 创建隐式 index 变量,初始为 0
idx_alloca: llvmlite.Value* = self.Gen.VarGen._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: str = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "ptr.cond.%d", cnt)
cond_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "ptr.body.%d", cnt)
body_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "ptr.incr.%d", cnt)
incr_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "ptr.end.%d", cnt)
end_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
# 跳转到 cond
llvmlite.build_br(builder, cond_bb)
# cond 块: load index, GEP, load elem, 空值判定(整数==0 / 指针==null / 浮点==0.0)
llvmlite.position_at_end(builder, cond_bb)
cur_idx: llvmlite.Value* = llvmlite.build_load(builder, i32_ty, idx_alloca)
elem_ptr: llvmlite.Value* = llvmlite.build_gep(builder, elem_ty, ptr_val, cur_idx)
cur_elem: llvmlite.Value* = llvmlite.build_load(builder, elem_ty, elem_ptr)
is_null: llvmlite.Value* = None
if elem_is_ptr2 != 0:
null_p: llvmlite.Value* = llvmlite.ConstNull(pool, elem_ty, "null")
if null_p is not None:
is_null = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, cur_elem, null_p)
elif elem_fbits2 != 0:
zero_f2: llvmlite.Value* = llvmlite.ConstFloat(pool, elem_ty, 0.0)
if zero_f2 is not None:
is_null = llvmlite.build_fcmp(builder, llvmlite.FCMP_OEQ, cur_elem, zero_f2)
else:
null_val: llvmlite.Value* = llvmlite.const_int(pool, elem_bits, 0)
is_null = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, cur_elem, null_val)
if is_null is None:
is_null = llvmlite.const_int(pool, 1, 0)
llvmlite.build_cond_br(builder, is_null, end_bb, body_bb)
# body 块: store elem to var, 翻译循环体
llvmlite.position_at_end(builder, body_bb)
llvmlite.build_store(builder, cur_elem, var_alloca)
# 保存旧循环上下文,设置 break/continue 目标
old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
old_continue: rawptr[llvmlite.BasicBlock] = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = incr_bb
body: list[ast.AST*]* = for_node.children
if body is not None:
body_count: sizet = len(body)
for bi in range(body_count):
stmt: ast.AST* = body.get(bi)
if stmt is not None:
self.Gen.StmtGen.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++, br cond
llvmlite.position_at_end(builder, incr_bb)
one_val: llvmlite.Value* = llvmlite.const_int32(pool, 1)
next_idx: llvmlite.Value* = 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
# ============================================================
# _handle_array_iter - 数组迭代: for x in arr:(迁移自 ForHandleIter)
# 定长数组按长度迭代(元素可为任意类型,不做 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, trans: HT.Translator*,
for_node: ast.For*,
var_name: str,
array_val: llvmlite.Value*) -> int:
"""数组迭代: for x in arr: 按数组长度迭代"""
pool: memhub.MemBuddy* = trans.Pool
builder: llvmlite.IRBuilder* = trans._cur_builder
func: llvmlite.Function* = trans._cur_func
# 解析数组类型 [N x elem_ty]
arr_ty: llvmlite.LLVMType* = array_val.Ty
elem_ty: llvmlite.LLVMType* = 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:
self.Gen.TypeGenErr.fatal_error(for_node, "数组迭代: 无法解析数组类型")
# 数组值 → 临时 alloca(数组值不是指针,需拷贝后 GEP 迭代)
# 必须在 entry 块创建:非 entry alloca 会被 LLVM 当动态 alloca → 运行时 sub rsp 大数组,
# 调用栈深时 rsp 骤降踩未映射页 → 概率性 #PF。
arr_tmp: llvmlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, arr_ty)
if arr_tmp is None:
self.Gen.TypeGenErr.fatal_error(for_node, "数组迭代: 临时存储分配失败")
llvmlite.build_store(builder, array_val, arr_tmp)
i32_ty: llvmlite.LLVMType* = llvmlite.Int32(pool)
# 循环变量 alloca(存储元素值)
var_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, var_name)
new_vars: int = 0
if var_alloca is None:
var_alloca = self.Gen.VarGen._alloca_at_entry(builder, elem_ty)
if self.Gen.VarGen.define_var(trans.SymTab, var_name, var_alloca) == 0:
new_vars = 1
# 隐式 index 变量,初始为 0
idx_alloca: llvmlite.Value* = self.Gen.VarGen._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: str = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "arr.cond.%d", cnt)
cond_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "arr.elem.%d", cnt)
elem_check_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "arr.body.%d", cnt)
body_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "arr.incr.%d", cnt)
incr_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "arr.end.%d", cnt)
end_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
llvmlite.build_br(builder, cond_bb)
# cond 块: 先查越界(idx < count,越界时不能 GEP+load 判空)
llvmlite.position_at_end(builder, cond_bb)
cur_idx: llvmlite.Value* = llvmlite.build_load(builder, i32_ty, idx_alloca)
count_val: llvmlite.Value* = llvmlite.const_int32(pool, elem_count)
in_bounds: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, count_val)
llvmlite.build_cond_br(builder, in_bounds, elem_check_bb, end_bb)
# elem_check 块: GEP(0, idx) → load elem → 空值判定(NULL 终止)
# 用户语义:整数/指针/浮点元素按"解引用为空"提前终止(如 split 尾哨兵
# 的 str 数组),同时保留长度上限防越界读;聚合元素只按长度迭代。
llvmlite.position_at_end(builder, elem_check_bb)
elem_ptr: llvmlite.Value* = llvmlite.build_gep_array(builder, arr_ty, elem_ty, arr_tmp, cur_idx)
cur_elem: llvmlite.Value* = llvmlite.build_load(builder, elem_ty, elem_ptr)
elem_bits_a: int = self.Gen.ExprGenBase.get_llvm_type_bits(elem_ty)
elem_ptr_a: int = self.Gen.ExprGenBase.is_ptr_type(elem_ty)
elem_fbits_a: int = self.Gen.ExprGenBase.get_llvm_float_bits(elem_ty)
if elem_bits_a != 0 or elem_ptr_a != 0 or elem_fbits_a != 0:
is_empty_a: llvmlite.Value* = None
if elem_ptr_a != 0:
null_ap: llvmlite.Value* = llvmlite.ConstNull(pool, elem_ty, "null")
if null_ap is not None:
is_empty_a = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, cur_elem, null_ap)
elif elem_fbits_a != 0:
zero_af: llvmlite.Value* = llvmlite.ConstFloat(pool, elem_ty, 0.0)
if zero_af is not None:
is_empty_a = llvmlite.build_fcmp(builder, llvmlite.FCMP_OEQ, cur_elem, zero_af)
else:
zero_ai: llvmlite.Value* = llvmlite.const_int(pool, elem_bits_a, 0)
is_empty_a = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, cur_elem, zero_ai)
if is_empty_a is not None:
llvmlite.build_cond_br(builder, is_empty_a, end_bb, body_bb)
else:
llvmlite.build_br(builder, body_bb)
else:
llvmlite.build_br(builder, body_bb)
# body 块: store elem to var → 循环体
llvmlite.position_at_end(builder, body_bb)
llvmlite.build_store(builder, cur_elem, var_alloca)
old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
old_continue: rawptr[llvmlite.BasicBlock] = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = incr_bb
body: list[ast.AST*]* = for_node.children
if body is not None:
body_count: sizet = len(body)
for bi in range(body_count):
stmt: ast.AST* = body.get(bi)
if stmt is not None:
self.Gen.StmtGen.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* = llvmlite.const_int32(pool, 1)
next_idx: llvmlite.Value* = 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
# ============================================================
# _handle_list_literal_iter - 列表字面量迭代: for x in [a, b, c]:(迁移自 ForHandleIter)
# 把列表字面量转成定长数组值,再复用数组迭代(按长度迭代)。
#
# 元素类型取第一个元素的值类型,其余元素 coerce 到该类型。
# ============================================================
def _handle_list_literal_iter(self, trans: HT.Translator*,
for_node: ast.For*,
var_name: str,
list_node: ast.AST*) -> int:
"""列表字面量迭代: for x in [a, b, c]: 按元素顺序迭代"""
pool: memhub.MemBuddy* = trans.Pool
builder: llvmlite.IRBuilder* = trans._cur_builder
lst: ast.List* = ast.List*(list_node)
if lst is None or lst.elts is None:
self.Gen.TypeGenErr.fatal_error(for_node, "列表字面量迭代: 空列表")
elts: list[ast.AST*]* = lst.elts
elts_count: sizet = len(elts)
if elts_count <= 0:
self.Gen.TypeGenErr.fatal_error(for_node, "列表字面量迭代: 空列表")
# 翻译第一个元素,确定元素类型
first_el: ast.AST* = elts.get(0)
# 显式判空(本仓硬约定:指针判空一律 `is None`;整型字面量 0 比较不是本仓判空写法
# ——`x == 0` 实测同样编译为 `icmp eq <ptr>, null`,逐字证据见
# AssignGenMixin.vp:1126-1145 记录的反例现场):
# 列表元素计数 > 实际填充 ⇒ 该槽为裸 0 ⇒ 上层某处产生了空 AST 元素。
# 不给下游 translate_value 的守卫吞掉(那会静默跳过 store、产出错值),此处响亮失败。
if first_el is None:
self.Gen.TypeGenErr.fatal_error(for_node,
f"列表字面量迭代遇到空 AST 元素:第 0 个元素为裸空指针(0),"
f"但元素计数为 {elts_count}(元素与计数不一致);上层某处产生了空 AST 元素,已终止编译。",
"ValueError")
# 对象有效性校验(vptr 非 0,硬约定与证据见 AssignGenMixin.vp:1174-1183):
# @t.CVTable 类对象首字即 vptr,为 0 时下游任意虚调用(kind()/dump())都会
# `load [0+slot]` ⇒ ASan READ at 0x0。读首字的唯一可用写法是 c.Deref((uint64*)(p))。
if c.Deref((uint64*)(first_el)) == 0:
self.Gen.TypeGenErr.fatal_error(for_node,
f"列表字面量迭代遇到【对象无效】的 AST 元素(vptr 为 0):第 0 个元素指针非 0"
f"(地址 {uint64(first_el)})但其对象首字(vtable 指针)为 0,元素计数 {elts_count};"
f"上层某处产生了「未初始化 vptr 的 AST 节点」(典型源:深拷贝只搬字段未搬 vptr),已终止编译。",
"ValueError")
first_val: llvmlite.Value* = self.Gen.ExprGen.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:
self.Gen.TypeGenErr.fatal_error(first_el, "列表字面量迭代: 无法确定元素类型")
elem_ty: llvmlite.LLVMType* = first_val.Ty
# 构建 [N x elem_ty] 数组值:临时 alloca 逐元素写入后 load
# 同样必须在 entry 块创建,避免非 entry alloca 被降为动态 alloca(见 _handle_array_iter)
arr_ty: llvmlite.LLVMType* = llvmlite.Array(pool, elem_ty, elts_count)
tmp_alloca: llvmlite.Value* = self.Gen.VarGen._alloca_at_entry(builder, arr_ty)
if tmp_alloca is None:
self.Gen.TypeGenErr.fatal_error(for_node, "列表字面量迭代: 临时数组分配失败")
first_ptr: llvmlite.Value* = 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: sizet = 1
while i < elts_count:
el_node: ast.AST* = elts.get(i)
# 显式判空(同上,用 `is None`):不得让空元素被 translate_value 的 None 守卫静默吞掉。
if el_node is None:
self.Gen.TypeGenErr.fatal_error(for_node,
f"列表字面量迭代遇到空 AST 元素:第 {i} 个元素为裸空指针(0),"
f"但元素计数为 {elts_count}(元素与计数不一致);上层某处产生了空 AST 元素,已终止编译。",
"ValueError")
# 对象有效性校验(vptr 非 0),同第 0 元素处:同族"取元素后即用"路径。
if c.Deref((uint64*)(el_node)) == 0:
self.Gen.TypeGenErr.fatal_error(for_node,
f"列表字面量迭代遇到【对象无效】的 AST 元素(vptr 为 0):第 {i} 个元素指针非 0"
f"(地址 {uint64(el_node)})但其对象首字(vtable 指针)为 0,元素计数 {elts_count};"
f"上层某处产生了「未初始化 vptr 的 AST 节点」(典型源:深拷贝只搬字段未搬 vptr),已终止编译。",
"ValueError")
el_val: llvmlite.Value* = self.Gen.ExprGen.translate_value(builder, pool, trans.Module, el_node, trans._funcs, trans._func_count, trans)
if el_val is not None:
el_val = self.Gen.ExprGenBase.coerce_to_type(builder, el_val, elem_ty, el_node)
el_ptr: llvmlite.Value* = 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* = llvmlite.build_load(builder, arr_ty, tmp_alloca)
if arr_val is None:
self.Gen.TypeGenErr.fatal_error(for_node, "列表字面量迭代: 数组加载失败")
return self._handle_array_iter(trans, for_node, var_name, arr_val)
# ============================================================
# _handle_list_iter - list[T] 容器迭代: for v in lst:(迁移自 ForHandleIter)
# 按 __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, trans: HT.Translator*,
for_node: ast.For*,
var_name: str,
list_val: llvmlite.Value*) -> int:
"""list[T] 容器迭代: for v in lst: 按 __count__ 动态长度迭代"""
pool: memhub.MemBuddy* = trans.Pool
builder: llvmlite.IRBuilder* = trans._cur_builder
func: llvmlite.Function* = trans._cur_func
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
# 读取 __count__ (偏移 8, GEP index 1)
cnt_ptr: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, list_val, llvmlite.const_int64(pool, 1))
if cnt_ptr is None:
self.Gen.TypeGenErr.fatal_error(for_node, "list 迭代: 无法定位 __count__")
count_val: llvmlite.Value* = llvmlite.build_load(builder, i64_ty, cnt_ptr)
# 循环变量 alloca(元素类型 i8*,与 list.get 内联一致)
var_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, var_name)
new_vars: int = 0
if var_alloca is None:
var_alloca = self.Gen.VarGen._alloca_at_entry(builder, i8_ptr_ty)
if self.Gen.VarGen.define_var(trans.SymTab, var_name, var_alloca) == 0:
new_vars = 1
# 隐式 index 变量 (i64,与 __count__ 类型对齐)
idx_alloca: llvmlite.Value* = self.Gen.VarGen._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, "lst.cond.%d", cnt)
cond_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "lst.body.%d", cnt)
body_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "lst.incr.%d", cnt)
incr_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "lst.end.%d", cnt)
end_bb: rawptr[llvmlite.BasicBlock] = 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* = llvmlite.build_load(builder, i64_ty, idx_alloca)
in_bounds: llvmlite.Value* = 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* = llvmlite.build_gep(builder, i64_ty, list_val, llvmlite.const_int64(pool, 0))
data_ptr: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, dpp)
epp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, list_val, llvmlite.const_int64(pool, 4))
esize: llvmlite.Value* = llvmlite.build_load(builder, i64_ty, epp)
offset: llvmlite.Value* = llvmlite.build_mul(builder, cur_idx, esize)
elem_addr: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, data_ptr, offset)
cur_elem: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, elem_addr)
llvmlite.build_store(builder, cur_elem, var_alloca)
# 保存旧循环上下文,设置 break/continue 目标
old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
old_continue: rawptr[llvmlite.BasicBlock] = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = incr_bb
body: list[ast.AST*]* = for_node.children
if body is not None:
body_count: sizet = len(body)
for bi in range(body_count):
stmt: ast.AST* = body.get(bi)
if stmt is not None:
self.Gen.StmtGen.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* = llvmlite.const_int64(pool, 1)
next_idx: llvmlite.Value* = 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
def _handle_dict_iter(self, trans: HT.Translator*,
for_node: ast.For*,
var_name: str,
dict_val: llvmlite.Value*) -> int:
"""dict 容器迭代: for key in d: 按 __count__/__keys__ 布局迭代
_dict.vp 布局(8 字节槽):__keys__@0, __values__@1, __count__@2,
__capacity__@3, __mbuddy__@4, __iter_index__@5。
__iter__ 协议(__iter__ 重置 iter_index + __next__ 取 key)内联为
循环:iter_idx < __count__ → key = __keys__[iter_idx]。
"""
pool: memhub.MemBuddy* = trans.Pool
builder: llvmlite.IRBuilder* = trans._cur_builder
func: llvmlite.Function* = trans._cur_func
i64_ty: llvmlite.LLVMType* = llvmlite.Int64(pool)
i8_ty: llvmlite.LLVMType* = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType* = llvmlite.Ptr(pool, i8_ty)
# 读取 __count__(槽 2,字节偏移 16)
cnt_ptr: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, dict_val, llvmlite.const_int64(pool, 2))
if cnt_ptr is None:
self.Gen.TypeGenErr.fatal_error(for_node, "dict 迭代: 无法定位 __count__")
count_val: llvmlite.Value* = llvmlite.build_load(builder, i64_ty, cnt_ptr)
# 循环变量 alloca(元素类型 i8*,与 dict.__next__ 返回 str 一致)
var_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, var_name)
new_vars: int = 0
if var_alloca is None:
var_alloca = self.Gen.VarGen._alloca_at_entry(builder, i8_ptr_ty)
if self.Gen.VarGen.define_var(trans.SymTab, var_name, var_alloca) == 0:
new_vars = 1
# 隐式 index 变量 (i64,与 __count__ 类型对齐)
idx_alloca: llvmlite.Value* = self.Gen.VarGen._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, "dict.cond.%d", cnt)
cond_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "dict.body.%d", cnt)
body_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "dict.incr.%d", cnt)
incr_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "dict.end.%d", cnt)
end_bb: rawptr[llvmlite.BasicBlock] = 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* = llvmlite.build_load(builder, i64_ty, idx_alloca)
in_bounds: llvmlite.Value* = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, count_val)
llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb)
# body 块: __keys__ + idx*8 → load key (i8*) → store to var
llvmlite.position_at_end(builder, body_bb)
kpp: llvmlite.Value* = llvmlite.build_gep(builder, i64_ty, dict_val, llvmlite.const_int64(pool, 0))
keys_ptr: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, kpp)
eight_val: llvmlite.Value* = llvmlite.const_int64(pool, 8)
key_offset: llvmlite.Value* = llvmlite.build_mul(builder, cur_idx, eight_val)
key_addr: llvmlite.Value* = llvmlite.build_gep(builder, i8_ty, keys_ptr, key_offset)
cur_key: llvmlite.Value* = llvmlite.build_load(builder, i8_ptr_ty, key_addr)
llvmlite.build_store(builder, cur_key, var_alloca)
# 保存旧循环上下文,设置 break/continue 目标
old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
old_continue: rawptr[llvmlite.BasicBlock] = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = incr_bb
body: list[ast.AST*]* = for_node.children
if body is not None:
body_count: sizet = len(body)
for bi in range(body_count):
stmt: ast.AST* = body.get(bi)
if stmt is not None:
self.Gen.StmtGen.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* = llvmlite.const_int64(pool, 1)
next_idx: llvmlite.Value* = 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
# ============================================================
# _handle_oop_iter - OOP 迭代协议: for x in obj:(迁移自 ForHandleIter)
# obj 的类有 __iter__/__next__ 方法时调用协议迭代
# (对齐 TPC HandlesFor.py _HandleForIterLlvm L599-663)
#
# 生成 IR 结构:
# %it = call {Class}.__iter__(obj)
# %flag = alloca i1 ; store 0
# br %cond
# cond:
# store 0, %flag
# %v = call {Class}.__next__(%it, %flag)
# %stop = load i1, %flag
# br i1 %stop==0, %body, %end
# body:
# store %v, %var
# ... 循环体 ...
# br %step
# step:
# br %cond
# end:
#
# __next__ 的隐藏参数 __stop_iter_flag__(i1*)由 ClassGenMixin
# _translate_method 注入,raise StopIteration 时置 1(translate_raise);
# VpiReader stub 声明同步该参数(_inject_method_declare)。
# ============================================================
def _handle_oop_iter(self, trans: HT.Translator*,
for_node: ast.For*,
var_name: str,
class_name: str,
obj_val: llvmlite.Value*) -> int:
"""OOP iter 协议: for x in obj: 调用 __iter__/__next__ 迭代"""
pool: memhub.MemBuddy* = trans.Pool
builder: llvmlite.IRBuilder* = trans._cur_builder
func: llvmlite.Function* = trans._cur_func
mod: llvmlite.LLVMModule* = trans.Module
if builder is None or func is None or mod is None:
return 0
if obj_val is None or obj_val.Ty is None:
self.Gen.TypeGenErr.fatal_error(for_node, "OOP 迭代: 迭代源对象类型未知")
if self.Gen.ExprGenBase.is_ptr_type(obj_val.Ty) == 0:
self.Gen.TypeGenErr.fatal_error(for_node, "OOP 迭代: 迭代源对象不是指针类型")
# 1. 查找 {Class}.__iter__ 并调用,得到迭代器
iter_lookup: str = pool.alloc(128)
if iter_lookup is None:
return 0
viperlib.snprintf(iter_lookup, 128, "%s.__iter__", class_name)
iter_fn: llvmlite.Function* = self.Gen.CallGenBase.find_func_in_module(mod, iter_lookup)
if iter_fn is None:
self.Gen.TypeGenErr.fatal_error(for_node, f"OOP 迭代: 类 '{class_name}' 没有 __iter__ 方法")
iter_ret_ty: llvmlite.LLVMType* = llvmlite.function_get_ret_ty(iter_fn)
iter_fn_name: str = llvmlite.function_get_name(iter_fn)
if iter_ret_ty is None or iter_fn_name is None:
return 0
# self 参数按 __iter__ 首参类型对齐(stub 声明 self 可能是 i8*)
iter_self: llvmlite.Value* = obj_val
iter_first: llvmlite.Param* = llvmlite.function_get_param_head(iter_fn)
if iter_first is not None:
iter_self_ty: llvmlite.LLVMType* = llvmlite.param_get_ty(iter_first)
if iter_self_ty is not None:
iter_self = llvmlite.build_bitcast(builder, obj_val, iter_self_ty)
if iter_self is None:
return 0
iter_self.Next = None
iter_result: llvmlite.Value* = llvmlite.build_call(builder, iter_fn_name, iter_self, 1, iter_ret_ty, 0)
if iter_result is None:
return 0
# 2. 查找 {Class}.__next__(带隐藏 __stop_iter_flag__ i1* 参数)
next_lookup: str = pool.alloc(128)
if next_lookup is None:
return 0
viperlib.snprintf(next_lookup, 128, "%s.__next__", class_name)
next_fn: llvmlite.Function* = self.Gen.CallGenBase.find_func_in_module(mod, next_lookup)
if next_fn is None:
self.Gen.TypeGenErr.fatal_error(for_node, f"OOP 迭代: 类 '{class_name}' 没有 __next__ 方法")
next_ret_ty: llvmlite.LLVMType* = llvmlite.function_get_ret_ty(next_fn)
next_fn_name: str = llvmlite.function_get_name(next_fn)
if next_ret_ty is None or next_fn_name is None:
return 0
# 3. 循环变量 alloca(元素类型 = __next__ 返回类型)
var_alloca: llvmlite.Value* = self.Gen.VarGen.lookup_var(trans.SymTab, var_name)
new_vars: int = 0
if var_alloca is None:
var_alloca = self.Gen.VarGen._alloca_at_entry(builder, next_ret_ty)
if var_alloca is not None:
if self.Gen.VarGen.define_var(trans.SymTab, var_name, var_alloca) == 0:
new_vars = 1
# 4. stop flag alloca(i1,初始 0)
i1_ty: llvmlite.LLVMType* = llvmlite.Int1(pool)
flag_alloca: llvmlite.Value* = llvmlite.build_alloca(builder, i1_ty)
if flag_alloca is None:
return 0
flag_zero: llvmlite.Value* = llvmlite.ConstInt(pool, i1_ty, 0, "0")
if flag_zero is not None:
llvmlite.build_store(builder, flag_zero, flag_alloca)
# 5. 创建基本块: cond / body / step / end
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: str = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "oop.cond.%d", cnt)
cond_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "oop.body.%d", cnt)
body_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "oop.step.%d", cnt)
step_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "oop.end.%d", cnt)
end_bb: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, func, name_buf)
if cond_bb is None or body_bb is None or step_bb is None or end_bb is None:
return 0
llvmlite.build_br(builder, cond_bb)
# 6. cond 块: 重置 flag → 调 __next__(iter, flag) → 检查 flag 判结束
llvmlite.position_at_end(builder, cond_bb)
if flag_zero is not None:
llvmlite.build_store(builder, flag_zero, flag_alloca)
# __next__ 参数 1:迭代器(按首参类型 bitcast)
next_self: llvmlite.Value* = iter_result
next_first: llvmlite.Param* = llvmlite.function_get_param_head(next_fn)
if next_first is not None:
next_self_ty: llvmlite.LLVMType* = llvmlite.param_get_ty(next_first)
if next_self_ty is not None and iter_result.Ty is not None:
next_self = llvmlite.build_bitcast(builder, iter_result, next_self_ty)
if next_self is None:
return 0
# 参数链表: arg1(iter).Next = arg2(flag);flag 独立 null 结尾防自链接
next_self.Next = flag_alloca
flag_alloca.Next = None
next_val: llvmlite.Value* = llvmlite.build_call(builder, next_fn_name, next_self, 2, next_ret_ty, 0)
if next_val is None:
return 0
stop_val: llvmlite.Value* = llvmlite.build_load(builder, i1_ty, flag_alloca)
if stop_val is None:
return 0
flag_zero2: llvmlite.Value* = llvmlite.ConstInt(pool, i1_ty, 0, "0")
continue_i1: llvmlite.Value* = None
if flag_zero2 is not None:
continue_i1 = llvmlite.build_icmp(builder, llvmlite.ICMP_EQ, stop_val, flag_zero2)
if continue_i1 is None:
return 0
llvmlite.build_cond_br(builder, continue_i1, body_bb, end_bb)
# 7. body 块: store 元素 → 翻译循环体 → br step
llvmlite.position_at_end(builder, body_bb)
if var_alloca is not None:
llvmlite.build_store(builder, next_val, var_alloca)
old_break: rawptr[llvmlite.BasicBlock] = trans._break_bb
old_continue: rawptr[llvmlite.BasicBlock] = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = step_bb
body: list[ast.AST*]* = for_node.children
if body is not None:
body_count: sizet = len(body)
for bi in range(body_count):
stmt: ast.AST* = body.get(bi)
if stmt is not None:
self.Gen.StmtGen.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, step_bb)
# 8. step 块 → cond;定位到 end 块
llvmlite.position_at_end(builder, step_bb)
llvmlite.build_br(builder, cond_bb)
llvmlite.position_at_end(builder, end_bb)
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
trans._ctrl_merge_reachable = 1
return new_vars
def _handle_enumerate_iter(self, trans: HT.Translator*,
for_node: ast.For*,
t1: str, t2: str,
call: ast.Call*) -> int:
"""enumerate 迭代: for i, v in enumerate(x)"""
if call is None or call.args is None:
return 0
cargs: list[ast.AST*]* = call.args
if len(cargs) < 1:
self.Gen.TypeGenErr.fatal_error(for_node, "enumerate 需要至少一个参数")
return self._build_seq_loop(trans, for_node, t1, t2, cargs.get(0), None, 1)
def _handle_zip_iter(self, trans: HT.Translator*,
for_node: ast.For*,
t1: str, t2: str,
call: ast.Call*) -> int:
"""zip 迭代: for a, b in zip(x, y)"""
if call is None or call.args is None:
# fail-fast: zip 参数缺失
self.Gen.TypeGenErr.fatal_error(call, "zip 参数缺失", "SyntaxError")
cargs: list[ast.AST*]* = call.args
if len(cargs) < 2:
self.Gen.TypeGenErr.fatal_error(for_node, "zip 需要至少两个参数")
return self._build_seq_loop(trans, for_node, t1, t2, cargs.get(0), cargs.get(1), 2)
def InitStmtGen(self) -> int:
"""初始化 StmtGen 族字段(构造时由 Generator 调用)"""
if self is None:
return 1
self.CifEvalOk = 0
self.EnumTable = None
self.EnumCount = 0
self.DiagStmtCount = 0
return 0