Files
ViperC/App/lib/core/Gen/StmtGenCifMixin.vp
T
TermiNexus a12dcafed2 fix(tpv): 泛型类型参数 SHA1 规范化 + 自举链接修复
- 类型参数统一 "{定义模块SHA1}.{Class}"(ast.AST/AST → f467978339422f32.AST),
  消除跨模块特化名分裂导致的 undefined symbol(list[AST|t.CPtr].set 根因)
- TypeGenResolve 新增 _norm_type_arg_name/_is_sha1_prefixed/_concat_sha1_class;
  resolve_annotation_type 兼容 "{16hex}.Class" Attribute 形态(跳过
  imported_modules 检查,优先完整名命中定义侧 struct)
- CallGenCtor._extract_type_args_from_slice / extract_class_name_from_annotation
  新增 from_imports 参数,8 处调用方传 trans._from_imports 保持注册/查找一致
- 修复模块级函数链式调用推断(get_perm_pool() 联合返回 → .alloc() 裸名 alloc)
- 跨模块方法 declare self 改为类指针 %"sha1.Class"*,调用侧按形参 coerce bitcast
- 撤销泛型特化双 SHA1 前缀,恢复单前缀(模板 SHA1)
- 新增 --phase2command xxx.bat:不执行 llc/链接,命令写入 bat
2026-08-23 12:00:04 +08:00

2516 lines
127 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.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.CompilerFactory as CompilerFactory
import lib.Projectrans.Config as Config
# ============================================================
# StmtGenCifMixin - StmtGen 拆分 1/3:CIf 编译期求值 + NewXxxHandle 工厂
#
# 按功能域从 StmtGenMixin.vp 拆出(500~1500 行/文件架构重构,试点):
# 簇 B(CIf 宏求值)+ NewIfHandle/NewWhileHandle/NewForHandle/
# NewReturnHandle/NewMatchHandle 工厂。
# 全部字段保留在本最底层父类(顺序 CifEvalOk->EnumTable->EnumCount->
# DiagStmtCount 与 Generator 组合布局一致,见下方字段注释)。
#
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
# ============================================================
# ============================================================
# StmtGenCifMixin - CIf 求值 + 工厂(最底层父类)
# ============================================================
@t.NoVTable
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 | t.CPtr
CifEvalOk: t.CSizeT
# --- 枚举注册表(原 HandlesEnum._enum_table/_enum_count) ---
EnumTable: GenTypes.EnumEntry | t.CPtr
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 | t.CPtr) -> int:
"""检查 test 是否为 c.CIf(...)/c.CIfdef(...)/c.CIfndef(...)(或裸 CIf 系)调用"""
if node is None or node.kind() != ast.ASTKind.Call:
return 0
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
if cl.func is None:
return 0
fk: int = cl.func.kind()
if fk == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(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 | t.CPtr = (ast.Name | t.CPtr)(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 | t.CPtr = (ast.Name | t.CPtr)(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 | t.CPtr,
trans: HT.Translator | t.CPtr,
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 | t.CPtr,
trans: HT.Translator | t.CPtr,
at: ast.Attribute | t.CPtr) -> 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 | t.CPtr = (ast.Name | t.CPtr)(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: t.CSizeT = 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: t.CSizeT = 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 | t.CPtr,
trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> 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 | t.CPtr = (ast.Constant | t.CPtr)(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 | t.CPtr = (ast.Name | t.CPtr)(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 | t.CPtr = (ast.Attribute | t.CPtr)(node)
return self._cif_attr_value(pool, trans, at)
if k == ast.ASTKind.UnaryOp:
uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(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: ast.BoolOp | t.CPtr = (ast.BoolOp | t.CPtr)(node)
vals: list[ast.AST | t.CPtr] | t.CPtr = bo.values
if vals is None:
self.CifEvalOk = 0
return 0
bn: t.CSizeT = 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: ast.Compare | t.CPtr = (ast.Compare | t.CPtr)(node)
lv: int = self._cif_eval_node(pool, trans, cmp.left)
if self.CifEvalOk == 0:
return 0
ops_list: list[t.CInt] | t.CPtr = (list[t.CInt] | t.CPtr)(cmp.ops)
comps: list[ast.AST | t.CPtr] | t.CPtr = cmp.comparators
if ops_list is None or comps is None:
self.CifEvalOk = 0
return 0
cc: t.CSizeT = len(comps)
ci: t.CSizeT
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 | t.CPtr = (ast.BinOp | t.CPtr)(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: GenTypes.SymbolTable | t.CPtr,
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 | t.CPtr = self.Gen.VarGen.lookup_var(symtab, name)
if v is None or v.Ty is None:
return -1
pointee: llvmlite.LLVMType | t.CPtr = 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 | t.CPtr,
trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> 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 | t.CPtr = (ast.Call | t.CPtr)(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 | t.CPtr = (ast.Attribute | t.CPtr)(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 | t.CPtr = (ast.Name | t.CPtr)(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 | t.CPtr] | t.CPtr = cl.args
if cargs is None or len(cargs) < 1:
self.CifEvalOk = 0
return 0
arg0: ast.AST | t.CPtr = cargs.get(0)
if arg0 is None or arg0.kind() != ast.ASTKind.Name:
self.CifEvalOk = 0
return 0
nm0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(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 | t.CPtr,
trans: HT.Translator | t.CPtr,
test: ast.AST | t.CPtr) -> int:
"""求值 CIf 调用(test 必须是 c.CIf 系调用)。
成功: 置 self.CifEvalOk=1,返回条件值(0/1)
失败(运行时变量/未知结构): 置 self.CifEvalOk=0,返回 0
"""
self.CifEvalOk = 0
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(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 | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
kind = at.attr
elif fk == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl.func)
kind = nm.id
if kind is None:
return 0
cargs: list[ast.AST | t.CPtr] | t.CPtr = cl.args
if cargs is None or len(cargs) < 1:
return 0
arg0: ast.AST | t.CPtr = 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 | t.CPtr = (ast.Name | t.CPtr)(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 | t.CPtr = (ast.Constant | t.CPtr)(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 | t.CPtr = (ast.Attribute | t.CPtr)(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 | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译 Return 语句"""
rt: ast.Return | t.CPtr = (ast.Return | t.CPtr)(node)
if rt is None:
return 0
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
val: llvmlite.Value | t.CPtr = None
if rt.value is not None:
# return a, b → 打包匿名 struct 值(多返回值,函数返回类型 tuple[T1,T2])
if rt.value.kind() == ast.ASTKind.Tuple:
rtp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(rt.value)
rtp_elts: list[ast.AST | t.CPtr] | t.CPtr = rtp.elts
rt_n: t.CSizeT = 0
if rtp_elts is not None:
rt_n = len(rtp_elts)
if rt_n > 0 and rt_n <= 16:
rt_vals: t.CSizeT | t.CPtr = pool.alloc(8 * 16)
if rt_vals is not None:
rt_val_ok: int = 1
rt_head: llvmlite.ParamNode | t.CPtr = None
rt_tail: llvmlite.ParamNode | t.CPtr = None
rvi: t.CSizeT
for rvi in range(rt_n):
ev_i: llvmlite.Value | t.CPtr = 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] = t.CSizeT(ev_i)
if rt_val_ok != 0:
# 构建匿名 struct 类型(字段类型 = 元素值类型)
rvi2: t.CSizeT
for rvi2 in range(rt_n):
rv_i: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)(
t.CVoid(rt_vals[rvi2], t.CPtr))
if rv_i is None or rv_i.Ty is None:
rt_val_ok = 0
break
rn: llvmlite.ParamNode | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = None
if rt_struct_ty is not None:
rt_tmp = llvmlite.build_alloca(builder, rt_struct_ty)
if rt_tmp is not None:
rvi3: t.CSizeT
for rvi3 in range(rt_n):
rv3: llvmlite.Value | t.CPtr = (llvmlite.Value | t.CPtr)(
t.CVoid(rt_vals[rvi3], t.CPtr))
rfp: llvmlite.Value | t.CPtr = 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 | t.CPtr = (ast.Name | t.CPtr)(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 | t.CPtr = self.Gen.VarGen.lookup_var(
trans.SymTab, "self")
if self_ptr is not None:
# 检查 self_ptr 是否是 Ptr(Ptr(...))(alloca 存储指针)
self_pointee_ty: llvmlite.LLVMType | t.CPtr = 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:
val = self.Gen.ExprGen.translate_value(
builder, pool, mod, rt.value,
trans._funcs, trans._func_count, trans)
# 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 | t.CPtr = trans._cur_func
is_void_ret: int = 0
is_ptr_ret: int = 0
is_float_ret: int = 0
ret_ty: llvmlite.LLVMType | t.CPtr = 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 | t.CPtr = llvmlite.ConstNull(pool, ret_ty, "null")
llvmlite.build_ret(builder, null_val)
return 0
if is_float_ret != 0:
zero_f: llvmlite.Value | t.CPtr = 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 | t.CPtr = trans._cur_func
ret_ty_rt: llvmlite.LLVMType | t.CPtr = 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)
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:
val = self.Gen.ExprGenBase.coerce_to_type(builder, val, ret_ty_rt, node)
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 | t.CPtr = None
ret_pointee: llvmlite.LLVMType | t.CPtr = 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 t.CUInt64T(val_pointee) != t.CUInt64T(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:
val = self.Gen.ExprGenBase.coerce_to_type(builder, val, ret_ty_rt, node)
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 | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译 if/elif/else 语句"""
if node is None:
return 0
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
if builder is None or func is None:
return 0
if_node: ast.If | t.CPtr = (ast.If | t.CPtr)(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 | t.CPtr] | t.CPtr = if_node.children
if body_cif is not None:
bc_cif: t.CSizeT = len(body_cif)
bi_cif: t.CSizeT
for bi_cif in range(bc_cif):
stmt_cif: ast.AST | t.CPtr = 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 | t.CPtr] | t.CPtr = if_node.orelse
if orelse_cif is not None and len(orelse_cif) == 1:
sub_cif: ast.AST | t.CPtr = 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: t.CSizeT = len(orelse_cif)
oi_cif: t.CSizeT
for oi_cif in range(oc_cif):
stmt_cif2: ast.AST | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = llvmlite.ConstNull(pool, cond_val.Ty, "null")
cond_i1 = llvmlite.build_icmp(
builder, llvmlite.ICMP_NE, cond_val, null_cond)
else:
zero: llvmlite.Value | t.CPtr = 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: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "if.end.%d", cnt)
merge_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
# 检查是否有 else 分支
has_else: int = 0
orelse_list: list[ast.AST | t.CPtr] | t.CPtr = if_node.orelse
if orelse_list is not None:
if len(orelse_list) > 0:
has_else = 1
else_bb: llvmlite.BasicBlock | t.CPtr = 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 | t.CPtr] | t.CPtr = if_node.children
if body is not None:
body_count: t.CSizeT = len(body)
for bi in range(body_count):
stmt: ast.AST | t.CPtr = body.get(bi)
if stmt is not None:
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: t.CSizeT = len(orelse_list)
for ei in range(else_count):
stmt: ast.AST | t.CPtr = 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 块可达性(追加90,末句控制流收尾判定用):
# 无 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 | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译 while 循环语句"""
if node is None:
return 0
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
if builder is None or func is None:
return 0
while_node: ast.While | t.CPtr = (ast.While | t.CPtr)(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: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "while.body.%d", cnt)
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "while.end.%d", cnt)
end_bb: llvmlite.BasicBlock | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = llvmlite.ConstNull(pool, cond_val.Ty, "null")
cond_i1 = llvmlite.build_icmp(
builder, llvmlite.ICMP_NE, cond_val, null_cond)
else:
zero: llvmlite.Value | t.CPtr = 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: llvmlite.BasicBlock | t.CPtr = trans._break_bb
old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = cond_bb
body: list[ast.AST | t.CPtr] | t.CPtr = while_node.children
if body is not None:
body_count: t.CSizeT = len(body)
for bi in range(body_count):
stmt: ast.AST | t.CPtr = body.get(bi)
if stmt is not None:
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 | t.CPtr) -> int:
"""while 条件为常量真(1 / True)返回 1"""
if test is None:
return 0
if test.kind() == ast.ASTKind.Constant:
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(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 | t.CPtr) -> int:
"""递归扫描节点子树(跳过嵌套 While/For 子树),含 Break 返回 1"""
if node is None:
return 0
ch: list[ast.AST | t.CPtr] | t.CPtr = node.children
if ch is not None:
n: t.CSizeT = len(ch)
for bi in range(n):
c: ast.AST | t.CPtr = 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 | t.CPtr] | t.CPtr) -> int:
"""语句列表是否含本层 break(嵌套循环的 break 归内层)"""
if body is None:
return 0
n: t.CSizeT = len(body)
for bi in range(n):
s: ast.AST | t.CPtr = 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 | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译 for i in range(...) 循环语句"""
if node is None:
return 0
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
if builder is None or func is None:
return 0
for_node: ast.For | t.CPtr = (ast.For | t.CPtr)(node)
# 1. 获取循环变量(Name 单变量 / Tuple 多变量)
target: ast.AST | t.CPtr = for_node.target
if target is None:
return 0
tk: int = target.kind()
if tk != ast.ASTKind.Name and tk != ast.ASTKind.Tuple:
return 0
var_name: str = None
if tk == ast.ASTKind.Name:
target_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
var_name = target_nm.id
if var_name is None:
return 0
# 2. 解析迭代器:支持 range() 和指针迭代
iter_node: ast.AST | t.CPtr = for_node.iter
if iter_node is None:
return 0
# 检查是否是 range() 调用
is_range_iter: int = 0
if iter_node.kind() == ast.ASTKind.Call:
call_pre: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node)
fn_pre: str = 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 | t.CPtr = (ast.Call | t.CPtr)(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 | t.CPtr = (ast.Tuple | t.CPtr)(target)
t1_buf_ie: bytes = pool.alloc(128)
t2_buf_ie: bytes = pool.alloc(128)
if t1_buf_ie is None or t2_buf_ie is None:
return 0
t1_buf_ie[0] = '\0'
t2_buf_ie[0] = '\0'
if self._extract_tuple_names(tup_ie, t1_buf_ie, t2_buf_ie) == 0:
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 | t.CPtr = (ast.Tuple | t.CPtr)(target)
t1_buf_iz: bytes = pool.alloc(128)
t2_buf_iz: bytes = pool.alloc(128)
if t1_buf_iz is None or t2_buf_iz is None:
return 0
t1_buf_iz[0] = '\0'
t2_buf_iz[0] = '\0'
if self._extract_tuple_names(tup_iz, t1_buf_iz, t2_buf_iz) == 0:
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 | t.CPtr = (ast.Name | t.CPtr)(iter_node)
if nm_lst.id is not None:
ve_lst: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry(
trans.SymTab, nm_lst.id)
if ve_lst is not None and ve_lst.AnnotClassName is not None:
# dict 容器变量:按 __count__/__keys__ 布局迭代(__iter__ 协议内联)
if string.strstr(ve_lst.AnnotClassName, "dict") is not None:
lst_val: llvmlite.Value | t.CPtr = 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)
if string.strstr(ve_lst.AnnotClassName, "list") is not None:
lst_val: llvmlite.Value | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = (ast.Constant | t.CPtr)(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 | t.CPtr = (ast.Call | t.CPtr)(iter_node)
# 3. 解析 range 参数: range(stop) / range(start, stop) / range(start, stop, step)
args: list[ast.AST | t.CPtr] | t.CPtr = call.args
if args is None:
return 0
arg_count: t.CSizeT = len(args)
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
start_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
stop_val: llvmlite.Value | t.CPtr = None
step_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1)
if arg_count == 0:
# fail-fast: range 无参数,立即终止
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 | t.CPtr = args.get(2)
if step_arg_node is not None:
skn: int = step_arg_node.kind()
if skn == ast.ASTKind.UnaryOp:
uop_r: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(step_arg_node)
if uop_r.op == ast.OpKind.USub and uop_r.operand is not None:
if uop_r.operand.kind() == ast.ASTKind.Constant:
uoc_r: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(uop_r.operand)
if uoc_r.int_val > 0:
step_neg_const = 1
elif skn == ast.ASTKind.Constant:
skc_r: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(step_arg_node)
if skc_r.int_val < 0:
step_neg_const = 1
# 4. 创建/查找循环变量 alloca
var_alloca: llvmlite.Value | t.CPtr = 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, i32_ty)
if self.Gen.VarGen.define_var(
trans.SymTab, var_name, var_alloca) == 0:
new_vars = 1
# 获取循环变量的实际元素类型(alloca 是指针类型,需解引用 Pointee)
# 当循环变量已声明为 i64(如 t.CSizeT),使用 i64 而非硬编码 i32
# 避免 load i32, i64* / store i32, i64* 类型不匹配
loop_var_ty: llvmlite.LLVMType | t.CPtr = i32_ty
if var_alloca is not None and var_alloca.Ty is not None:
match var_alloca.Ty:
case llvmlite.LLVMType.Ptr(pointee_ty):
if pointee_ty is not None:
loop_var_ty = pointee_ty
loop_var_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(loop_var_ty)
# 5. 存储初始值 (类型对齐: start_val 可能是 i32/i64,需对齐到 loop_var_ty)
init_val: llvmlite.Value | t.CPtr = start_val
if start_val is not None and start_val.Ty is not None:
start_bits: int = 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: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "for.body.%d", cnt)
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "for.incr.%d", cnt)
incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "for.end.%d", cnt)
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
# 7. 跳转到 cond 块
llvmlite.build_br(builder, cond_bb)
# 8. cond 块: load i, icmp slt i, stop, cond_br body/end
llvmlite.position_at_end(builder, cond_bb)
cur_i: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, loop_var_ty, var_alloca)
# 类型对齐: stop_val 可能是 i64 (如 range(strlen(s))),需将 cur_i 提升到 stop_val 类型
cmp_lhs: llvmlite.Value | t.CPtr = cur_i
cmp_rhs: llvmlite.Value | t.CPtr = stop_val
if stop_val is not None and stop_val.Ty is not None:
stop_bits: int = 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 位宽(如 t.CSizeT 循环变量 + range(i32)):
# 应把 cur_i 截断到 stop_val 类型(低向高才 sext/zext,高向低用
# trunc)。原实现反了——把小的 stop_val trunc 到大的 loop_var_ty,
# 生成 `trunc i32 to i64` 扩宽非法 IR,llc 报
# "invalid cast opcode for cast from 'i32' to 'i64'"
# (VpiReader.vp range(arg_count) 追加86 根因)。
cmp_lhs = llvmlite.build_trunc(builder, cur_i, stop_val.Ty)
# step 为负时条件反转:i > stop(ICMP_SGT);正/缺省 step 保持 i < stop
range_cmp_op: int = llvmlite.ICMP_SLT
if step_neg_const != 0:
range_cmp_op = llvmlite.ICMP_SGT
cond_i1: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
builder, range_cmp_op, cmp_lhs, cmp_rhs)
llvmlite.build_cond_br(builder, cond_i1, body_bb, end_bb)
# 9. body 块: 翻译循环体,跳到 incr
llvmlite.position_at_end(builder, body_bb)
# 保存旧循环上下文,设置 break/continue 目标
old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb
old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = incr_bb
body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children
if body is not None:
body_count: t.CSizeT = len(body)
for bi in range(body_count):
stmt: ast.AST | t.CPtr = body.get(bi)
if stmt is not None:
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 | t.CPtr = llvmlite.build_load(builder, loop_var_ty, var_alloca)
# 类型对齐: step_val 可能是 i32/i64,需对齐到 loop_var_ty 与 cur_i2 类型一致
incr_step: llvmlite.Value | t.CPtr = step_val
if step_val is not None and step_val.Ty is not None:
step_bits: int = 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 | t.CPtr = llvmlite.build_add(builder, cur_i2, incr_step)
llvmlite.build_store(builder, next_i, var_alloca)
llvmlite.build_br(builder, cond_bb)
# 11. 定位到 end 块
llvmlite.position_at_end(builder, end_bb)
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
trans._ctrl_merge_reachable = 1
return new_vars
# ============================================================
# 多变量迭代辅助(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 | t.CPtr,
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 | t.CPtr] | t.CPtr = tup.elts
n: t.CSizeT = len(elts)
if n < 2:
return 0
e0: ast.AST | t.CPtr = elts.get(0)
e1: ast.AST | t.CPtr = elts.get(1)
if e0 is None or e1 is None:
return 0
if e0.kind() != ast.ASTKind.Name or e1.kind() != ast.ASTKind.Name:
return 0
n0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(e0)
n1: ast.Name | t.CPtr = (ast.Name | t.CPtr)(e1)
if n0.id is None or n1.id is None:
return 0
string.strcpy(out1, n0.id)
string.strcpy(out2, n1.id)
return 1
def _seq_kind(self, trans: HT.Translator | t.CPtr,
src: ast.AST | t.CPtr) -> int:
"""判断迭代源类型: SEQ_KIND_RANGE / STR / LIST,不支持返回 0"""
if src is None:
return 0
k: int = src.kind()
if k == ast.ASTKind.Call:
cl_s: ast.Call | t.CPtr = (ast.Call | t.CPtr)(src)
fn_s: str = 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 | t.CPtr = (ast.Constant | t.CPtr)(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 | t.CPtr = (ast.Name | t.CPtr)(src)
if nm_s.id is not None and trans is not None:
ve_s: GenTypes.VarEntry | t.CPtr = self.Gen.VarGen.lookup_var_entry(
trans.SymTab, nm_s.id)
if ve_s is not None and ve_s.AnnotClassName is not None:
if string.strstr(ve_s.AnnotClassName, "list") is not None:
return GenTypes.SEQ_KIND_LIST
return GenTypes.SEQ_KIND_STR
return 0
def _build_seq_loop(self, trans: HT.Translator | t.CPtr,
for_node: ast.For | t.CPtr,
t1: str, t2: str,
src1: ast.AST | t.CPtr,
src2: ast.AST | t.CPtr,
n_srcs: int) -> int:
"""生成序列迭代循环(enumerate: n_srcs=1 / zip: n_srcs=2)
循环变量 alloca 自动创建或复用;元素类型由源类型决定
(RANGE→i32, STR→i8, LIST→i8*)。索引内部统一 i64。
"""
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
# ---- 源 1 准备 ----
kind1: int = self._seq_kind(trans, src1)
if kind1 == 0:
self.Gen.TypeGenErr.fatal_error(for_node, "序列迭代: 源 1 类型不支持")
r1_start: llvmlite.Value | t.CPtr = None
r1_stop: llvmlite.Value | t.CPtr = None
r1_step: llvmlite.Value | t.CPtr = None
s1_ptr: llvmlite.Value | t.CPtr = None
l1_count: llvmlite.Value | t.CPtr = None
l1_data: llvmlite.Value | t.CPtr = None
l1_esize: llvmlite.Value | t.CPtr = None
elem1_ty: llvmlite.LLVMType | t.CPtr = i8_ptr_ty
if kind1 == 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 | t.CPtr = (ast.Call | t.CPtr)(src1)
cargs1: list[ast.AST | t.CPtr] | t.CPtr = call_src1.args
if cargs1 is not None:
n1: t.CSizeT = len(cargs1)
if n1 >= 1:
sv: llvmlite.Value | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = elem1_ty
s2_ptr: llvmlite.Value | t.CPtr = None
l2_count: llvmlite.Value | t.CPtr = None
l2_data: llvmlite.Value | t.CPtr = None
l2_esize: llvmlite.Value | t.CPtr = None
r2_start: llvmlite.Value | t.CPtr = None
r2_stop: llvmlite.Value | t.CPtr = None
r2_step: llvmlite.Value | t.CPtr = None
if n_srcs >= 2:
kind2 = self._seq_kind(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 | t.CPtr = (ast.Call | t.CPtr)(src2)
cargs2: list[ast.AST | t.CPtr] | t.CPtr = call_src2.args
if cargs2 is not None:
n2: t.CSizeT = len(cargs2)
if n2 >= 1:
svz: llvmlite.Value | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "seq.body.%d", cnt)
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "seq.incr.%d", cnt)
incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "seq.end.%d", cnt)
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
llvmlite.build_br(builder, cond_bb)
# cond 块: 源 1 done 检查(zip 需源 2 也 done)
llvmlite.position_at_end(builder, cond_bb)
cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, idx_alloca)
done1: llvmlite.Value | t.CPtr = None
if kind1 == 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 | t.CPtr = llvmlite.build_gep(builder, i8_ty, s1_ptr, cur_idx)
ch1: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ty, ch_ptr1)
zero1: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, 8, 0)
done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, ch1, zero1)
elif kind1 == GenTypes.SEQ_KIND_LIST:
done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, l1_count)
cont: llvmlite.Value | t.CPtr = done1
if n_srcs >= 2:
done2: llvmlite.Value | t.CPtr = None
if kind2 == 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 | t.CPtr = llvmlite.build_gep(builder, i8_ty, s2_ptr, cur_idx)
ch2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ty, ch_ptr2)
zero2: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, 8, 0)
done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, ch2, zero2)
elif kind2 == 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 | t.CPtr = None
if kind1 == GenTypes.SEQ_KIND_RANGE:
step1: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, r1_step)
v1 = llvmlite.build_add(builder, r1_start, step1)
elif kind1 == GenTypes.SEQ_KIND_STR:
ch_ptr1b: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s1_ptr, cur_idx)
v1 = llvmlite.build_load(builder, i8_ty, ch_ptr1b)
elif kind1 == GenTypes.SEQ_KIND_LIST:
off1: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, l1_esize)
addr1: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, l1_data, off1)
v1 = llvmlite.build_load(builder, i8_ptr_ty, addr1)
# store t1 / t2
if t1_alloca is not None and t1_alloca.Ty is not None:
t1_ty: llvmlite.LLVMType | t.CPtr = t1_alloca.Ty.Pointee
if n_srcs == 1:
# enumerate: t1 = 序号(trunc i64 → i32)
idx32: llvmlite.Value | t.CPtr = llvmlite.build_trunc(builder, cur_idx, i32_ty)
llvmlite.build_store(builder, idx32, t1_alloca)
if t2_alloca is not None and t2_alloca.Ty is not None and v1 is not None:
t2_ty: llvmlite.LLVMType | t.CPtr = t2_alloca.Ty.Pointee
v1c: llvmlite.Value | t.CPtr = 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 | t.CPtr = self.Gen.ExprGenBase.coerce_to_type(builder, v1, t1_ty, src1)
llvmlite.build_store(builder, v1c, t1_alloca)
# 源 2 元素 → t2
v2: llvmlite.Value | t.CPtr = None
if kind2 == GenTypes.SEQ_KIND_RANGE:
step2: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, r2_step)
v2 = llvmlite.build_add(builder, r2_start, step2)
elif kind2 == GenTypes.SEQ_KIND_STR:
ch_ptr2b: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s2_ptr, cur_idx)
v2 = llvmlite.build_load(builder, i8_ty, ch_ptr2b)
elif kind2 == GenTypes.SEQ_KIND_LIST:
off2: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, l2_esize)
addr2: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, l2_data, off2)
v2 = llvmlite.build_load(builder, i8_ptr_ty, addr2)
if t2_alloca is not None and t2_alloca.Ty is not None and v2 is not None:
t2_ty2: llvmlite.LLVMType | t.CPtr = t2_alloca.Ty.Pointee
v2c: llvmlite.Value | t.CPtr = self.Gen.ExprGenBase.coerce_to_type(builder, v2, t2_ty2, src2)
llvmlite.build_store(builder, v2c, t2_alloca)
# 保存旧循环上下文,设置 break/continue 目标
old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb
old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = incr_bb
body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children
if body is not None:
body_count: t.CSizeT = len(body)
for bi in range(body_count):
stmt: ast.AST | t.CPtr = body.get(bi)
if stmt is not None:
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 | t.CPtr = llvmlite.const_int64(pool, 1)
next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val)
llvmlite.build_store(builder, next_idx, idx_alloca)
llvmlite.build_br(builder, cond_bb)
# 定位到 end 块
llvmlite.position_at_end(builder, end_bb)
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
trans._ctrl_merge_reachable = 1
return new_vars
# ============================================================
# _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 | t.CPtr,
for_node: ast.For | t.CPtr,
var_name: str) -> int:
"""指针迭代: for x in ptr: 直到解引用为空"""
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
# 翻译迭代器表达式,获取指针值
ptr_val: llvmlite.Value | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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)
# 元素类型必须是整数(用于 icmp eq 0 检查 null 终止符)
elem_bits: int = self.Gen.ExprGenBase.get_llvm_type_bits(elem_ty)
if elem_bits == 0:
self.Gen.TypeGenErr.fatal_error(for_node, "指针迭代: 元素类型不是整数,无法检查 null 终止符")
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
# 创建循环变量 alloca(存储元素值)
var_alloca: llvmlite.Value | t.CPtr = 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 | t.CPtr = 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: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "ptr.body.%d", cnt)
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "ptr.incr.%d", cnt)
incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "ptr.end.%d", cnt)
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
# 跳转到 cond
llvmlite.build_br(builder, cond_bb)
# cond 块: load index, GEP, load elem, icmp eq 0
llvmlite.position_at_end(builder, cond_bb)
cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, idx_alloca)
elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, elem_ty, ptr_val, cur_idx)
cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, elem_ptr)
null_val: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, elem_bits, 0)
is_null: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
builder, llvmlite.ICMP_EQ, cur_elem, null_val)
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: llvmlite.BasicBlock | t.CPtr = trans._break_bb
old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = incr_bb
body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children
if body is not None:
body_count: t.CSizeT = len(body)
for bi in range(body_count):
stmt: ast.AST | t.CPtr = body.get(bi)
if stmt is not None:
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 | t.CPtr = llvmlite.const_int32(pool, 1)
next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val)
llvmlite.build_store(builder, next_idx, idx_alloca)
llvmlite.build_br(builder, cond_bb)
# 定位到 end 块
llvmlite.position_at_end(builder, end_bb)
# 追加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 | t.CPtr,
for_node: ast.For | t.CPtr,
var_name: str,
array_val: llvmlite.Value | t.CPtr) -> int:
"""数组迭代: for x in arr: 按数组长度迭代"""
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
# 解析数组类型 [N x elem_ty]
arr_ty: llvmlite.LLVMType | t.CPtr = array_val.Ty
elem_ty: llvmlite.LLVMType | t.CPtr = None
elem_count: int = 0
match arr_ty:
case llvmlite.LLVMType.Array(et, n):
elem_ty = et
elem_count = n
if elem_ty is None or elem_count <= 0:
self.Gen.TypeGenErr.fatal_error(for_node, "数组迭代: 无法解析数组类型")
# 数组值 → 临时 alloca(数组值不是指针,需拷贝后 GEP 迭代)
arr_tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(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 | t.CPtr = llvmlite.Int32(pool)
# 循环变量 alloca(存储元素值)
var_alloca: llvmlite.Value | t.CPtr = 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 | t.CPtr = 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: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "arr.body.%d", cnt)
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "arr.incr.%d", cnt)
incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "arr.end.%d", cnt)
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
llvmlite.build_br(builder, cond_bb)
# cond 块: load index, icmp slt idx, elem_count
llvmlite.position_at_end(builder, cond_bb)
cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i32_ty, idx_alloca)
count_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, elem_count)
in_bounds: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
builder, llvmlite.ICMP_SLT, cur_idx, count_val)
llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb)
# body 块: GEP(0, idx) → load elem → store to var → 循环体
llvmlite.position_at_end(builder, body_bb)
elem_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
builder, arr_ty, elem_ty, arr_tmp, cur_idx)
cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, elem_ty, elem_ptr)
llvmlite.build_store(builder, cur_elem, var_alloca)
old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb
old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = incr_bb
body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children
if body is not None:
body_count: t.CSizeT = len(body)
for bi in range(body_count):
stmt: ast.AST | t.CPtr = 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 | t.CPtr = llvmlite.const_int32(pool, 1)
next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val)
llvmlite.build_store(builder, next_idx, idx_alloca)
llvmlite.build_br(builder, cond_bb)
# 定位到 end 块
llvmlite.position_at_end(builder, end_bb)
# 追加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 | t.CPtr,
for_node: ast.For | t.CPtr,
var_name: str,
list_node: ast.AST | t.CPtr) -> int:
"""列表字面量迭代: for x in [a, b, c]: 按元素顺序迭代"""
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
lst: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node)
if lst is None or lst.elts is None:
self.Gen.TypeGenErr.fatal_error(for_node, "列表字面量迭代: 空列表")
elts: list[ast.AST | t.CPtr] | t.CPtr = lst.elts
elts_count: t.CSizeT = len(elts)
if elts_count <= 0:
self.Gen.TypeGenErr.fatal_error(for_node, "列表字面量迭代: 空列表")
# 翻译第一个元素,确定元素类型
first_el: ast.AST | t.CPtr = elts.get(0)
first_val: llvmlite.Value | t.CPtr = 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 | t.CPtr = first_val.Ty
# 构建 [N x elem_ty] 数组值:临时 alloca 逐元素写入后 load
arr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, elem_ty, elts_count)
tmp_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, arr_ty)
if tmp_alloca is None:
self.Gen.TypeGenErr.fatal_error(for_node, "列表字面量迭代: 临时数组分配失败")
first_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
builder, arr_ty, elem_ty, tmp_alloca, llvmlite.const_int32(pool, 0))
if first_ptr is not None:
llvmlite.build_store(builder, first_val, first_ptr)
# 写其余元素(coerce 到 elem_ty)
i: t.CSizeT = 1
while i < elts_count:
el_node: ast.AST | t.CPtr = elts.get(i)
el_val: llvmlite.Value | t.CPtr = 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 | t.CPtr = llvmlite.build_gep_array(
builder, arr_ty, elem_ty, tmp_alloca,
llvmlite.const_int32(pool, i))
if el_ptr is not None:
llvmlite.build_store(builder, el_val, el_ptr)
i += 1
# load 回数组值,复用数组迭代
arr_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, arr_ty, tmp_alloca)
if arr_val is None:
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 | t.CPtr,
for_node: ast.For | t.CPtr,
var_name: str,
list_val: llvmlite.Value | t.CPtr) -> int:
"""list[T] 容器迭代: for v in lst: 按 __count__ 动态长度迭代"""
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
# 读取 __count__ (偏移 8, GEP index 1)
cnt_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, i64_ty, list_val, llvmlite.const_int64(pool, 1))
if cnt_ptr is None:
self.Gen.TypeGenErr.fatal_error(for_node, "list 迭代: 无法定位 __count__")
count_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, cnt_ptr)
# 循环变量 alloca(元素类型 i8*,与 list.get 内联一致)
var_alloca: llvmlite.Value | t.CPtr = 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 | t.CPtr = 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: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "lst.body.%d", cnt)
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "lst.incr.%d", cnt)
incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "lst.end.%d", cnt)
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
llvmlite.build_br(builder, cond_bb)
# cond 块: load index, icmp slt idx, count
llvmlite.position_at_end(builder, cond_bb)
cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, idx_alloca)
in_bounds: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
builder, llvmlite.ICMP_SLT, cur_idx, count_val)
llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb)
# body 块: __data__ + idx*__elem_size__ → load 元素 → store to var
llvmlite.position_at_end(builder, body_bb)
dpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, i64_ty, list_val, llvmlite.const_int64(pool, 0))
data_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, dpp)
epp: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, i64_ty, list_val, llvmlite.const_int64(pool, 4))
esize: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, epp)
offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, esize)
elem_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, i8_ty, data_ptr, offset)
cur_elem: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, elem_addr)
llvmlite.build_store(builder, cur_elem, var_alloca)
# 保存旧循环上下文,设置 break/continue 目标
old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb
old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = incr_bb
body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children
if body is not None:
body_count: t.CSizeT = len(body)
for bi in range(body_count):
stmt: ast.AST | t.CPtr = 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 | t.CPtr = llvmlite.const_int64(pool, 1)
next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val)
llvmlite.build_store(builder, next_idx, idx_alloca)
llvmlite.build_br(builder, cond_bb)
# 定位到 end 块
llvmlite.position_at_end(builder, end_bb)
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
trans._ctrl_merge_reachable = 1
return new_vars
def _handle_dict_iter(self, trans: HT.Translator | t.CPtr,
for_node: ast.For | t.CPtr,
var_name: str,
dict_val: llvmlite.Value | t.CPtr) -> 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 | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
# 读取 __count__(槽 2,字节偏移 16)
cnt_ptr: llvmlite.Value | t.CPtr = 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 | t.CPtr = llvmlite.build_load(builder, i64_ty, cnt_ptr)
# 循环变量 alloca(元素类型 i8*,与 dict.__next__ 返回 str 一致)
var_alloca: llvmlite.Value | t.CPtr = 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 | t.CPtr = 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: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "dict.body.%d", cnt)
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "dict.incr.%d", cnt)
incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "dict.end.%d", cnt)
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
llvmlite.build_br(builder, cond_bb)
# cond 块: load index, icmp slt idx, count
llvmlite.position_at_end(builder, cond_bb)
cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, idx_alloca)
in_bounds: llvmlite.Value | t.CPtr = llvmlite.build_icmp(
builder, llvmlite.ICMP_SLT, cur_idx, count_val)
llvmlite.build_cond_br(builder, in_bounds, body_bb, end_bb)
# body 块: __keys__ + idx*8 → load key (i8*) → store to var
llvmlite.position_at_end(builder, body_bb)
kpp: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, i64_ty, dict_val, llvmlite.const_int64(pool, 0))
keys_ptr: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, kpp)
eight_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 8)
key_offset: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, eight_val)
key_addr: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, i8_ty, keys_ptr, key_offset)
cur_key: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ptr_ty, key_addr)
llvmlite.build_store(builder, cur_key, var_alloca)
# 保存旧循环上下文,设置 break/continue 目标
old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb
old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = incr_bb
body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children
if body is not None:
body_count: t.CSizeT = len(body)
for bi in range(body_count):
stmt: ast.AST | t.CPtr = 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 | t.CPtr = llvmlite.const_int64(pool, 1)
next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val)
llvmlite.build_store(builder, next_idx, idx_alloca)
llvmlite.build_br(builder, cond_bb)
# 定位到 end 块
llvmlite.position_at_end(builder, end_bb)
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
trans._ctrl_merge_reachable = 1
return new_vars
# ============================================================
# _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 | t.CPtr,
for_node: ast.For | t.CPtr,
var_name: str,
class_name: str,
obj_val: llvmlite.Value | t.CPtr) -> int:
"""OOP iter 协议: for x in obj: 调用 __iter__/__next__ 迭代"""
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
mod: llvmlite.LLVMModule | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = obj_val
iter_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(iter_fn)
if iter_first is not None:
iter_self_ty: llvmlite.LLVMType | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = llvmlite.Int1(pool)
flag_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, i1_ty)
if flag_alloca is None:
return 0
flag_zero: llvmlite.Value | t.CPtr = 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: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "oop.body.%d", cnt)
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "oop.step.%d", cnt)
step_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "oop.end.%d", cnt)
end_bb: llvmlite.BasicBlock | t.CPtr = 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 | t.CPtr = iter_result
next_first: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(next_fn)
if next_first is not None:
next_self_ty: llvmlite.LLVMType | t.CPtr = 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 | t.CPtr = 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 | t.CPtr = llvmlite.build_load(builder, i1_ty, flag_alloca)
if stop_val is None:
return 0
flag_zero2: llvmlite.Value | t.CPtr = llvmlite.ConstInt(pool, i1_ty, 0, "0")
continue_i1: llvmlite.Value | t.CPtr = 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: llvmlite.BasicBlock | t.CPtr = trans._break_bb
old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = step_bb
body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children
if body is not None:
body_count: t.CSizeT = len(body)
for bi in range(body_count):
stmt: ast.AST | t.CPtr = body.get(bi)
if stmt is not None:
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 | t.CPtr,
for_node: ast.For | t.CPtr,
t1: str, t2: str,
call: ast.Call | t.CPtr) -> int:
"""enumerate 迭代: for i, v in enumerate(x)"""
if call is None or call.args is None:
return 0
cargs: list[ast.AST | t.CPtr] | t.CPtr = call.args
if 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 | t.CPtr,
for_node: ast.For | t.CPtr,
t1: str, t2: str,
call: ast.Call | t.CPtr) -> int:
"""zip 迭代: for a, b in zip(x, y)"""
if call is None or call.args is None:
# fail-fast: zip 参数缺失
self.Gen.TypeGenErr.fatal_error(call, "zip 参数缺失", "SyntaxError")
cargs: list[ast.AST | t.CPtr] | t.CPtr = 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