refactor(gen): 完成 P6 机械化迁移——Handler 类并入 Gen Mixin,语句实现单层化

- 10 个 Handler 类主方法迁入 Gen:Assign/AnnAssign/AugAssign→AssignGenMixin,
  If/While/For/Return→StmtGenCifMixin,Match→新建 MatchGenMixin(注册 Generator MRO),
  Imports→ImportsGenMixin;方法体 self.Trans→trans,签名加 trans 首参
- 分派改:StmtGenMixin.translate_stmt 同链 self.translate_xxx + 跨链经 Handles 委托壳
  (NoVTable 静态绑定约束);ExprCall 分派改走 ExprCallCall 壳
- 清理:HandlesTranslator 删 11 个 Handler 字段与 _init_state 创建段;
  StmtGenCifMixin 删 5 个 NewXxxHandle 工厂;main/BuildPipeline 补 HandlesAssign._g_gen 注入
- 委托壳保留:跨 Mixin 桥(Assign/AnnAssign/AugAssign/Match/Imports)待编译器缺陷修复后删
This commit is contained in:
TermiNexus committed 2026-08-20 06:40:37 +08:00
1 parent e07ea491a5
commit 9f396f4874
22 files changed
+5239 -5438

No files matched your search

+2
View File
@@ -34,6 +34,7 @@ import lib.core.Handles.HandlesMatch as HandlesMatch
import lib.core.Handles.HandlesEnum as HandlesEnum
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
import lib.core.Handles.HandlesAugAssign as HandlesAugAssign
import lib.core.Handles.HandlesAssign as HandlesAssign
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesMain as HandlesMain
import lib.core.StubMerger as StubMerger
@@ -194,6 +195,7 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
HandlesEnum._g_gen = gen
HandlesAnnAssign._g_gen = gen
HandlesAugAssign._g_gen = gen
HandlesAssign._g_gen = gen
HandlesVar._g_gen = gen
HandlesTranslator._g_gen = gen
HandlesMain._g_gen = gen
File diff suppressed because it is too large. Load diff
+3 -1
View File
@@ -42,6 +42,7 @@ import lib.core.Gen.ClassGenVTable as ClassGenVTable
import lib.core.Gen.ClassGenDef as ClassGenDef
import lib.core.Gen.ImportsGenMixin as ImportsGenMixin
import lib.core.Gen.StmtGenMixin as StmtGenMixin
import lib.core.Gen.MatchGenMixin as MatchGenMixin
import lib.core.Gen.AssignGenMixin as AssignGenMixin
import lib.core.Gen.VarGenMixin as VarGenMixin
import lib.core.Gen.TranslatorGenMixin as TranslatorGenMixin
@@ -83,7 +84,8 @@ class Generator(BaseGenMixin.BaseGenMixin, TypeGenMixin.TypeGenMixin,
ClassGenEnum.ClassGenEnum, ClassGenGeneric.ClassGenGeneric,
ClassGenVTable.ClassGenVTable, ClassGenDef.ClassGenDef,
ImportsGenMixin.ImportsGenMixin,
StmtGenMixin.StmtGenMixin, AssignGenMixin.AssignGenMixin,
StmtGenMixin.StmtGenMixin, MatchGenMixin.MatchGenMixin,
AssignGenMixin.AssignGenMixin,
VarGenMixin.VarGenMixin, TranslatorGenMixin.TranslatorGenMixin):
"""生成器:多继承 Mixin 组合(对象化迁移宿主)"""
+118
View File
@@ -11,6 +11,8 @@ import w32.fileio as fileio
import lib.core.StubMerger as StubMerger
import lib.core.CompilerFactory as CompilerFactory
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.StubMergerStore as StubMergerStore
@@ -632,3 +634,119 @@ class ImportsGenMixin:
else:
self._report_import_error(node, "导入模块 SHA1 未注册(includes 扫描未找到该模块)")
return 1
# ============================================================
# translate_import - 处理 import 语句,更新 trans._imported_modules
# (迁移自 HandlesImports.ImportsHandle.HandleImport)
# ============================================================
def translate_import(self, trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""处理 import 语句,返回 0"""
imp: ast.Import | t.CPtr = (ast.Import | t.CPtr)(node)
if imp is None:
return 0
names: list[ast.AST | t.CPtr] | t.CPtr = imp.names
if names is None:
return 0
nn: t.CSizeT = len(names)
for ni in range(nn):
alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni))
if alias is not None and alias.name is not None:
# 导入时立即校验模块 SHA1 是否注册(fast-fail,仅全量翻译时检查)
# declare_only=1/2 是 struct 预注册/import 扫描阶段:此时 SHA1 表
# 尚未包含后续才追加的模块(如 App 源文件),检查会造成误报
if trans._declare_only == 0:
self._check_import_sha1(node, alias.name)
pool_val: memhub.MemBuddy | t.CPtr = trans.Pool
im_val: str = trans._imported_modules
trans._imported_modules = self.add_imported_module(
pool_val, im_val, alias.name)
# 别名也加入导入模块列表(用于模块限定构造器检查 Module.Class())
if alias.asname is not None:
trans._imported_modules = self.add_imported_module(
pool_val, trans._imported_modules, alias.asname)
# 别名也加入 from_imports(asname:fullname),
# 使 HT.func() 跨模块调用能通过 from_imports 查找别名→完整模块名→SHA1
# 否则 _lookup_module_sha1("HT") 找不到(mod_arr 只存文件名 HandlesTranslator)
trans._from_imports = self.add_from_import(
pool_val, trans._from_imports, alias.asname, alias.name)
else:
# 无别名时(import a.b.c),将顶层包名 "a" 也加入 _imported_modules,
# 使 a.b.c 作为属性访问的 base 被翻译时能通过 is_module_imported("a") 检查
dot_ptr: str = string.strstr(alias.name, '.')
if dot_ptr is not None:
pkg_len: t.CSizeT = t.CSizeT(t.CUInt64T(dot_ptr) - t.CUInt64T(alias.name))
if pkg_len > 0 and pkg_len < 256:
pkg_buf: bytes = pool_val.alloc(pkg_len + 1)
if pkg_buf is not None:
string.strncpy(pkg_buf, alias.name, pkg_len)
pkg_buf[pkg_len] = '\0'
trans._imported_modules = self.add_imported_module(
pool_val, trans._imported_modules, pkg_buf)
return 0
# ============================================================
# translate_import_from_module - 处理 from X import Y 的模块部分
# (迁移自 HandlesImports.ImportsHandle.HandleImportFromModule)
#
# 对相对导入(level > 0),使用 trans.CurrentPackage 解析为
# 完整模块名(如 __types → llvmlite.__types),确保 .deps.txt
# 记录的模块名与 SHA1 映射表一致。
# ============================================================
def translate_import_from_module(self, trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""处理 from X import Y 的模块部分,更新 trans._imported_modules"""
impf: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(node)
if impf is None:
return 0
# 解析模块名:相对导入需补充包前缀
resolved: str = self._resolve_relative_module(
trans.Pool, trans.CurrentPackage,
impf.level, impf.module)
if resolved is not None:
# 导入时立即校验模块 SHA1 是否注册(fast-fail,仅全量翻译时检查)
if trans._declare_only == 0:
self._check_import_sha1(node, resolved)
trans._imported_modules = self.add_imported_module(
trans.Pool, trans._imported_modules, resolved)
return 0
# ============================================================
# translate_import_from_names - 处理 from X import Y 的名称部分
# (迁移自 HandlesImports.ImportsHandle.HandleImportFromNames)
#
# 同样使用解析后的完整模块名,确保 from-import 映射
# (如 LLVMType:llvmlite.__types)能正确查到 SHA1。
# ============================================================
def translate_import_from_names(self, trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""处理 from X import Y 的名称部分,更新 trans._from_imports"""
impf: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(node)
if impf is None:
return 0
# 解析模块名:相对导入需补充包前缀
resolved: str = self._resolve_relative_module(
trans.Pool, trans.CurrentPackage,
impf.level, impf.module)
if resolved is not None:
names: list[ast.AST | t.CPtr] | t.CPtr = impf.names
if names is not None:
nn: t.CSizeT = len(names)
for ni in range(nn):
alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni))
if alias is not None and alias.name is not None:
local_name: str = alias.name
orig_name: str = None
if alias.asname is not None:
local_name = alias.asname
orig_name = alias.name
trans._from_imports = self.add_from_import(
trans.Pool, trans._from_imports,
local_name, resolved, orig_name)
# 命名空间隔离:from-import 的名称标记为可见结构体
HandlesStruct.add_visible_struct(trans.Pool, local_name)
# 注册 re-export 映射:当前模块 re-export 了 local_name,源模块为 resolved
# 使跨模块调用 module.func() 能解析到正确的源模块 SHA1
if trans.ModuleSha1 is not None:
self.register_reexport(trans.ModuleSha1, local_name, resolved)
return 0
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+10 -4
View File
@@ -24,9 +24,11 @@ import lib.core.Handles.HandlesReturn as HandlesReturn
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.HandlesMatch as HandlesMatch
import lib.core.Handles.HandlesEnum as HandlesEnum
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
import lib.core.CompilerFactory as CompilerFactory
import lib.Projectrans.Config as Config
import lib.core.Gen.StmtGenCifMixin as StmtGenCifMixin
import lib.core.Handles.ExprCallCall as ExprCallCall
# ============================================================
@@ -132,12 +134,16 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
# printf / print 走特殊路径(print 是类型感知格式化,不映射到 printf)
if string.strcmp(func_name, "printf") == 0:
trans.ExprCallH.HandlePrintfCall(cl)
ExprCallCall.translate_printf_call(
trans.Pool, trans._cur_builder, trans.Module, cl, trans)
elif string.strcmp(func_name, "print") == 0:
trans.ExprCallH.HandlePrintCall(cl)
ExprCallCall.translate_print_call(
trans.Pool, trans._cur_builder, trans.Module, cl, trans)
else:
# 通用函数调用(返回值丢弃)
trans.ExprCallH.HandleCall(call_node)
ExprCallCall.translate_call(
trans.Pool, trans._cur_builder, trans.Module, call_node,
trans._funcs, trans._func_count, trans)
return 0
def pre_scan_allocas(self, trans: HT.Translator | t.CPtr,
@@ -148,7 +154,7 @@ class StmtGenDeclMixin(StmtGenCifMixin.StmtGenCifMixin):
"""
if node is None:
return 0
return trans.AnnAssignH.PreScan(node)
return HandlesAnnAssign.translate_annassign_prescan(trans, node)
def pre_scan_scope_decls(self, trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
+14 -11
View File
@@ -29,6 +29,9 @@ import lib.Projectrans.Config as Config
import lib.core.Gen.StmtGenDeclMixin as StmtGenDeclMixin
import lib.core.Handles.ExprCallBase as ExprCallBase
import lib.core.Handles.ExprCallCtor as ExprCallCtor
import lib.core.Handles.HandlesAssign as HandlesAssign
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
import lib.core.Handles.HandlesAugAssign as HandlesAugAssign
# ============================================================
@@ -61,29 +64,29 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
if k == ast.ASTKind.Expr:
return self.translate_expr_stmt(trans, node)
elif k == ast.ASTKind.Assign:
return trans.AssignH.Handle(node)
return HandlesAssign.translate_assign(trans, node)
elif k == ast.ASTKind.AnnAssign:
return trans.AnnAssignH.Handle(node)
return HandlesAnnAssign.translate_annassign(trans, node)
elif k == ast.ASTKind.FunctionDef:
# 嵌套函数定义:提升为顶层函数 + 创建闭包
return HandlesFunctions.translate_nested_function_def(trans, node)
elif k == ast.ASTKind.Return:
return trans.ReturnH.Handle(node)
return self.translate_return(trans, node)
elif k == ast.ASTKind.If:
return trans.IfH.Handle(node)
return self.translate_if(trans, node)
elif k == ast.ASTKind.While:
return trans.WhileH.Handle(node)
return self.translate_while(trans, node)
elif k == ast.ASTKind.AugAssign:
return trans.AugAssignH.Handle(node)
return HandlesAugAssign.translate_augassign(trans, node)
elif k == ast.ASTKind.For:
return trans.ForH.Handle(node)
return self.translate_for(trans, node)
elif k == ast.ASTKind.ClassDef:
return HandlesClassDef.translate_class_def(trans, node)
elif k == ast.ASTKind.Import:
return trans.ImportsH.HandleImport(node)
return HandlesImports.translate_import(trans, node)
elif k == ast.ASTKind.ImportFrom:
trans.ImportsH.HandleImportFromModule(node)
return trans.ImportsH.HandleImportFromNames(node)
HandlesImports.translate_import_from_module(trans, node)
return HandlesImports.translate_import_from_names(trans, node)
elif k == ast.ASTKind.Global:
return self.translate_global(trans, node)
elif k == ast.ASTKind.Nonlocal:
@@ -95,7 +98,7 @@ class StmtGenMixin(StmtGenDeclMixin.StmtGenDeclMixin):
elif k == ast.ASTKind.Continue:
return self.translate_continue(trans)
elif k == ast.ASTKind.Match:
return trans.MatchH.Handle(node)
return HandlesMatch.translate_match(trans, node)
elif k == ast.ASTKind.Delete:
return self.translate_delete(trans, node)
elif k == ast.ASTKind.Raise:
+3 -3
View File
@@ -119,10 +119,10 @@ class TranslatorGenMixin:
if trans._declare_only == 0 and (kd == ast.ASTKind.Import or kd == ast.ASTKind.ImportFrom):
continue
if kd == ast.ASTKind.Import:
trans.ImportsH.HandleImport(child)
HandlesImports.translate_import(trans, child)
elif kd == ast.ASTKind.ImportFrom:
trans.ImportsH.HandleImportFromModule(child)
trans.ImportsH.HandleImportFromNames(child)
HandlesImports.translate_import_from_module(trans, child)
HandlesImports.translate_import_from_names(trans, child)
elif kd == ast.ASTKind.FunctionDef:
# Phase 1a 声明模式:只注册 CExport/State 函数到全局表(解决翻译顺序依赖)
# Phase 1b 全量翻译:正常翻译函数体
+10 -386
View File
@@ -1,394 +1,18 @@
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdio
import viperlib
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesBody as HandlesBody
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.ExprCallBase as ExprCallBase
from lib.core.Handles.HandlesFor import SEQ_KIND_RANGE, SEQ_KIND_STR, SEQ_KIND_LIST
import lib.core.Gen.Generator as Generator
# ============================================================
# ForHandleBase - HandlesFor 拆分(阶段 E):ForHandleBase
# ForHandleBase - HandlesFor 拆分(迁移完成,仅保留 _g_gen 单例)
#
# 类方法拆 Mixin:self 调用按 1 级父类解析(TPV 限制)。
# @t.NoVTable:静态绑定。
# P6 机械化迁移:ForHandleBase 全部方法(_extract_tuple_names/
# _seq_kind/_build_seq_loop)→ StmtGenCifMixin 方法。
# main/BuildPipeline 仍注入 _g_gen,不可删。
# ============================================================
@t.NoVTable
class ForHandleBase(HandlesBase.Mixin):
"""ForHandleBase"""
def __init__(self, trans: HT.Translator | t.CPtr):
self.Trans = trans
# ============================================================
# 多变量迭代(enumerate / zip)
#
# 支持迭代源: range(start, stop, step) / 字符串(常量|变量) / list[T]
# enumerate(x) → for i, v in enumerate(x):i 为序号,v 为元素
# zip(a, b) → for x, y in zip(a, b):任一源耗尽即终止
# ============================================================
def _extract_tuple_names(self, tup: ast.Tuple | t.CPtr,
out1: str | t.CPtr, out2: str | t.CPtr) -> int:
"""从 Tuple target 提取前两个 Name 变量名,写入 out1/out2,成功返回 1"""
if tup is None or tup.elts is None or out1 is None or out2 is None:
return 0
elts: list[ast.AST | t.CPtr] | t.CPtr = tup.elts
n: t.CSizeT = len(elts)
if n < 2:
return 0
e0: ast.AST | t.CPtr = elts.get(0)
e1: ast.AST | t.CPtr = elts.get(1)
if e0 is None or e1 is None:
return 0
if e0.kind() != ast.ASTKind.Name or e1.kind() != ast.ASTKind.Name:
return 0
n0: ast.Name | t.CPtr = (ast.Name | t.CPtr)(e0)
n1: ast.Name | t.CPtr = (ast.Name | t.CPtr)(e1)
if n0.id is None or n1.id is None:
return 0
string.strcpy(out1, n0.id)
string.strcpy(out2, n1.id)
return 1
def _seq_kind(self, src: ast.AST | t.CPtr) -> int:
"""判断迭代源类型: SEQ_KIND_RANGE / STR / LIST,不支持返回 0"""
if src is None:
return 0
k: int = src.kind()
if k == ast.ASTKind.Call:
cl_s: ast.Call | t.CPtr = (ast.Call | t.CPtr)(src)
fn_s: str = HandlesExpr.get_func_name(cl_s.func)
if fn_s is not None and string.strcmp(fn_s, "range") == 0:
return SEQ_KIND_RANGE
return 0
if k == ast.ASTKind.Constant:
cn_s: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(src)
if cn_s is not None and cn_s.const_kind == ast.CONST_STR:
return SEQ_KIND_STR
return 0
if k == ast.ASTKind.Name:
nm_s: ast.Name | t.CPtr = (ast.Name | t.CPtr)(src)
if nm_s.id is not None and self.Trans is not None:
ve_s: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
self.Trans.SymTab, nm_s.id)
if ve_s is not None and ve_s.AnnotClassName is not None:
if string.strstr(ve_s.AnnotClassName, "list") is not None:
return SEQ_KIND_LIST
return SEQ_KIND_STR
return 0
def _build_seq_loop(self, for_node: ast.For | t.CPtr,
t1: str, t2: str,
src1: ast.AST | t.CPtr,
src2: ast.AST | t.CPtr,
n_srcs: int) -> int:
"""生成序列迭代循环(enumerate: n_srcs=1 / zip: n_srcs=2)
循环变量 alloca 自动创建或复用;元素类型由源类型决定
(RANGE→i32, STR→i8, LIST→i8*)。索引内部统一 i64。
"""
trans: HT.Translator | t.CPtr = self.Trans
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
# ---- 源 1 准备 ----
kind1: int = self._seq_kind(src1)
if kind1 == 0:
HandlesType.fatal_error(for_node, "序列迭代: 源 1 类型不支持")
r1_start: llvmlite.Value | t.CPtr = None
r1_stop: llvmlite.Value | t.CPtr = None
r1_step: llvmlite.Value | t.CPtr = None
s1_ptr: llvmlite.Value | t.CPtr = None
l1_count: llvmlite.Value | t.CPtr = None
l1_data: llvmlite.Value | t.CPtr = None
l1_esize: llvmlite.Value | t.CPtr = None
elem1_ty: llvmlite.LLVMType | t.CPtr = i8_ptr_ty
if kind1 == SEQ_KIND_RANGE:
elem1_ty = i32_ty
r1_start = llvmlite.const_int64(pool, 0)
r1_step = llvmlite.const_int64(pool, 1)
r1_stop = llvmlite.const_int64(pool, 0)
# 先赋中间变量再取 args(cast 链式属性访问会推断错字段偏移)
call_src1: ast.Call | t.CPtr = (ast.Call | t.CPtr)(src1)
cargs1: list[ast.AST | t.CPtr] | t.CPtr = call_src1.args
if cargs1 is not None:
n1: t.CSizeT = len(cargs1)
if n1 >= 1:
sv: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, cargs1.get(0),
trans._funcs, trans._func_count, trans)
if sv is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(cargs1.get(0), "range 参数翻译失败", "TypeError")
r1_stop = HandlesExpr.coerce_to_type(builder, sv, i64_ty, cargs1.get(0))
if n1 >= 2:
sv2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, cargs1.get(1),
trans._funcs, trans._func_count, trans)
if sv2 is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(cargs1.get(1), "range 参数翻译失败", "TypeError")
r1_start = HandlesExpr.coerce_to_type(builder, sv2, i64_ty, cargs1.get(1))
if n1 >= 3:
sv3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, cargs1.get(2),
trans._funcs, trans._func_count, trans)
if sv3 is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(cargs1.get(2), "range 参数翻译失败", "TypeError")
r1_step = HandlesExpr.coerce_to_type(builder, sv3, i64_ty, cargs1.get(2))
elif kind1 == SEQ_KIND_STR:
elem1_ty = i8_ty
s1_ptr = HandlesExpr.translate_value(
builder, pool, trans.Module, src1,
trans._funcs, trans._func_count, trans)
if s1_ptr is None:
HandlesType.fatal_error(for_node, "序列迭代: 字符串源翻译失败")
elif kind1 == SEQ_KIND_LIST:
elem1_ty = i8_ptr_ty
l1_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, src1,
trans._funcs, trans._func_count, trans)
if l1_obj is None or l1_obj.Ty is None \
or HandlesExpr.is_ptr_type(l1_obj.Ty) == 0:
HandlesType.fatal_error(for_node, "序列迭代: list 源不是指针类型")
l1_count = llvmlite.build_load(builder, i64_ty,
llvmlite.build_gep(builder, i64_ty, l1_obj, llvmlite.const_int64(pool, 1)))
l1_data = llvmlite.build_load(builder, i8_ptr_ty,
llvmlite.build_gep(builder, i64_ty, l1_obj, llvmlite.const_int64(pool, 0)))
l1_esize = llvmlite.build_load(builder, i64_ty,
llvmlite.build_gep(builder, i64_ty, l1_obj, llvmlite.const_int64(pool, 4)))
# ---- 源 2 准备(zip)----
kind2: int = 0
elem2_ty: llvmlite.LLVMType | t.CPtr = elem1_ty
s2_ptr: llvmlite.Value | t.CPtr = None
l2_count: llvmlite.Value | t.CPtr = None
l2_data: llvmlite.Value | t.CPtr = None
l2_esize: llvmlite.Value | t.CPtr = None
r2_start: llvmlite.Value | t.CPtr = None
r2_stop: llvmlite.Value | t.CPtr = None
r2_step: llvmlite.Value | t.CPtr = None
if n_srcs >= 2:
kind2 = self._seq_kind(src2)
if kind2 == 0:
HandlesType.fatal_error(for_node, "序列迭代: 源 2 类型不支持")
if kind2 == SEQ_KIND_RANGE:
elem2_ty = i32_ty
r2_start = llvmlite.const_int64(pool, 0)
r2_step = llvmlite.const_int64(pool, 1)
r2_stop = llvmlite.const_int64(pool, 0)
# 先赋中间变量再取 args(cast 链式属性访问会推断错字段偏移)
call_src2: ast.Call | t.CPtr = (ast.Call | t.CPtr)(src2)
cargs2: list[ast.AST | t.CPtr] | t.CPtr = call_src2.args
if cargs2 is not None:
n2: t.CSizeT = len(cargs2)
if n2 >= 1:
svz: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, cargs2.get(0),
trans._funcs, trans._func_count, trans)
if svz is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(cargs2.get(0), "range 参数翻译失败", "TypeError")
r2_stop = HandlesExpr.coerce_to_type(builder, svz, i64_ty, cargs2.get(0))
if n2 >= 2:
svz2: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, cargs2.get(1),
trans._funcs, trans._func_count, trans)
if svz2 is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(cargs2.get(1), "range 参数翻译失败", "TypeError")
r2_start = HandlesExpr.coerce_to_type(builder, svz2, i64_ty, cargs2.get(1))
if n2 >= 3:
svz3: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, cargs2.get(2),
trans._funcs, trans._func_count, trans)
if svz3 is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(cargs2.get(2), "range 参数翻译失败", "TypeError")
r2_step = HandlesExpr.coerce_to_type(builder, svz3, i64_ty, cargs2.get(2))
elif kind2 == SEQ_KIND_STR:
elem2_ty = i8_ty
s2_ptr = HandlesExpr.translate_value(
builder, pool, trans.Module, src2,
trans._funcs, trans._func_count, trans)
if s2_ptr is None:
HandlesType.fatal_error(for_node, "序列迭代: 字符串源 2 翻译失败")
elif kind2 == SEQ_KIND_LIST:
elem2_ty = i8_ptr_ty
l2_obj: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, src2,
trans._funcs, trans._func_count, trans)
if l2_obj is None or l2_obj.Ty is None \
or HandlesExpr.is_ptr_type(l2_obj.Ty) == 0:
HandlesType.fatal_error(for_node, "序列迭代: list 源 2 不是指针类型")
l2_count = llvmlite.build_load(builder, i64_ty,
llvmlite.build_gep(builder, i64_ty, l2_obj, llvmlite.const_int64(pool, 1)))
l2_data = llvmlite.build_load(builder, i8_ptr_ty,
llvmlite.build_gep(builder, i64_ty, l2_obj, llvmlite.const_int64(pool, 0)))
l2_esize = llvmlite.build_load(builder, i64_ty,
llvmlite.build_gep(builder, i64_ty, l2_obj, llvmlite.const_int64(pool, 4)))
# ---- 循环变量 alloca ----
# t1: enumerate → 序号 (i32);zip → 源 1 元素
t1_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, t1)
new_vars: int = 0
if t1_alloca is None:
if n_srcs == 1:
t1_alloca = HandlesVar._alloca_at_entry(builder, i32_ty)
else:
t1_alloca = HandlesVar._alloca_at_entry(builder, elem1_ty)
if t1_alloca is not None:
if HandlesVar.define_var(trans.SymTab, t1, t1_alloca) == 0:
new_vars += 1
# t2: 源 2 元素(enumerate 时 = 源 1 元素)
t2_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(trans.SymTab, t2)
if t2_alloca is None:
t2_alloca = HandlesVar._alloca_at_entry(builder, elem2_ty)
if t2_alloca is not None:
if HandlesVar.define_var(trans.SymTab, t2, t2_alloca) == 0:
new_vars += 1
# 隐式 index 变量 (i64)
idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i64_ty)
llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), idx_alloca)
# 基本块: cond / body / incr / end
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: str = pool.alloc(32)
viperlib.snprintf(name_buf, 32, "seq.cond.%d", cnt)
cond_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "seq.body.%d", cnt)
body_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "seq.incr.%d", cnt)
incr_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
viperlib.snprintf(name_buf, 32, "seq.end.%d", cnt)
end_bb: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(pool, func, name_buf)
llvmlite.build_br(builder, cond_bb)
# cond 块: 源 1 done 检查(zip 需源 2 也 done)
llvmlite.position_at_end(builder, cond_bb)
cur_idx: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, idx_alloca)
done1: llvmlite.Value | t.CPtr = None
if kind1 == SEQ_KIND_RANGE:
done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, r1_stop)
elif kind1 == SEQ_KIND_STR:
ch_ptr1: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s1_ptr, cur_idx)
ch1: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ty, ch_ptr1)
zero1: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, 8, 0)
done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, ch1, zero1)
elif kind1 == SEQ_KIND_LIST:
done1 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, l1_count)
cont: llvmlite.Value | t.CPtr = done1
if n_srcs >= 2:
done2: llvmlite.Value | t.CPtr = None
if kind2 == SEQ_KIND_RANGE:
done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, r2_stop)
elif kind2 == SEQ_KIND_STR:
ch_ptr2: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s2_ptr, cur_idx)
ch2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i8_ty, ch_ptr2)
zero2: llvmlite.Value | t.CPtr = llvmlite.const_int(pool, 8, 0)
done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_NE, ch2, zero2)
elif kind2 == SEQ_KIND_LIST:
done2 = llvmlite.build_icmp(builder, llvmlite.ICMP_SLT, cur_idx, l2_count)
cont = llvmlite.build_and(builder, done1, done2)
llvmlite.build_cond_br(builder, cont, body_bb, end_bb)
# body 块: 获取元素 → store → 循环体
llvmlite.position_at_end(builder, body_bb)
# 源 1 元素
v1: llvmlite.Value | t.CPtr = None
if kind1 == SEQ_KIND_RANGE:
step1: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, r1_step)
v1 = llvmlite.build_add(builder, r1_start, step1)
elif kind1 == SEQ_KIND_STR:
ch_ptr1b: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s1_ptr, cur_idx)
v1 = llvmlite.build_load(builder, i8_ty, ch_ptr1b)
elif kind1 == SEQ_KIND_LIST:
off1: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, l1_esize)
addr1: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, l1_data, off1)
v1 = llvmlite.build_load(builder, i8_ptr_ty, addr1)
# store t1 / t2
if t1_alloca is not None and t1_alloca.Ty is not None:
t1_ty: llvmlite.LLVMType | t.CPtr = t1_alloca.Ty.Pointee
if n_srcs == 1:
# enumerate: t1 = 序号(trunc i64 → i32)
idx32: llvmlite.Value | t.CPtr = llvmlite.build_trunc(builder, cur_idx, i32_ty)
llvmlite.build_store(builder, idx32, t1_alloca)
if t2_alloca is not None and t2_alloca.Ty is not None and v1 is not None:
t2_ty: llvmlite.LLVMType | t.CPtr = t2_alloca.Ty.Pointee
v1c: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, v1, t2_ty, src1)
llvmlite.build_store(builder, v1c, t2_alloca)
else:
if v1 is not None:
v1c: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, v1, t1_ty, src1)
llvmlite.build_store(builder, v1c, t1_alloca)
# 源 2 元素 → t2
v2: llvmlite.Value | t.CPtr = None
if kind2 == SEQ_KIND_RANGE:
step2: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, r2_step)
v2 = llvmlite.build_add(builder, r2_start, step2)
elif kind2 == SEQ_KIND_STR:
ch_ptr2b: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, s2_ptr, cur_idx)
v2 = llvmlite.build_load(builder, i8_ty, ch_ptr2b)
elif kind2 == SEQ_KIND_LIST:
off2: llvmlite.Value | t.CPtr = llvmlite.build_mul(builder, cur_idx, l2_esize)
addr2: llvmlite.Value | t.CPtr = llvmlite.build_gep(builder, i8_ty, l2_data, off2)
v2 = llvmlite.build_load(builder, i8_ptr_ty, addr2)
if t2_alloca is not None and t2_alloca.Ty is not None and v2 is not None:
t2_ty2: llvmlite.LLVMType | t.CPtr = t2_alloca.Ty.Pointee
v2c: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(builder, v2, t2_ty2, src2)
llvmlite.build_store(builder, v2c, t2_alloca)
# 保存旧循环上下文,设置 break/continue 目标
old_break: llvmlite.BasicBlock | t.CPtr = trans._break_bb
old_continue: llvmlite.BasicBlock | t.CPtr = trans._continue_bb
trans._break_bb = end_bb
trans._continue_bb = incr_bb
body: list[ast.AST | t.CPtr] | t.CPtr = for_node.children
if body is not None:
body_count: t.CSizeT = len(body)
for bi in range(body_count):
stmt: ast.AST | t.CPtr = body.get(bi)
if stmt is not None:
HandlesBody.translate_stmt(trans, stmt)
trans._break_bb = old_break
trans._continue_bb = old_continue
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, incr_bb)
# incr 块: index++
llvmlite.position_at_end(builder, incr_bb)
one_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1)
next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val)
llvmlite.build_store(builder, next_idx, idx_alloca)
llvmlite.build_br(builder, cond_bb)
# 定位到 end 块
llvmlite.position_at_end(builder, end_bb)
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
trans._ctrl_merge_reachable = 1
return new_vars
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
# ============================================================
_g_gen: Generator.Generator | t.CPtr = None
+11 -811
View File
@@ -1,820 +1,20 @@
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdio
import viperlib
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesBody as HandlesBody
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.ExprCallBase as ExprCallBase
import lib.core.Gen.Generator as Generator
import lib.core.Handles.ForHandleBase as ForHandleBase
# ============================================================
# ForHandleIter - HandlesFor 拆分(阶段 E):ForHandleIter
# ForHandleIter - HandlesFor 拆分(迁移完成,仅保留 _g_gen 单例)
#
# 类方法拆 Mixin:self 调用按 1 级父类解析(TPV 限制)。
# @t.NoVTable:静态绑定。
# P6 机械化迁移:ForHandleIter 全部方法(_handle_ptr_iter/
# _handle_array_iter/_handle_list_literal_iter/_handle_list_iter/
# _handle_dict_iter/_handle_oop_iter/_handle_enumerate_iter/
# _handle_zip_iter)→ StmtGenCifMixin 方法。
# main/BuildPipeline 仍注入 _g_gen,不可删。
# ============================================================
@t.NoVTable
class ForHandleIter(ForHandleBase.ForHandleBase):
"""ForHandleIter"""
# ============================================================
# _handle_ptr_iter - 指针迭代: for x in ptr:
# 遍历指针,依赖隐式 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, for_node: ast.For | t.CPtr,
var_name: str) -> int:
"""指针迭代: for x in ptr: 直到解引用为空"""
trans: HT.Translator | t.CPtr = self.Trans
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
# 翻译迭代器表达式,获取指针值
ptr_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, for_node.iter,
trans._funcs, trans._func_count, trans)
if ptr_val is None:
HandlesType.fatal_error(for_node, "指针迭代: 无法翻译迭代器表达式")
# 检查迭代器类型
if HandlesExpr.is_ptr_type(ptr_val.Ty) == 0:
# 数组迭代:for k in arr(定长数组按长度迭代,元素可为任意类型)
if HandlesExpr.is_array_type(ptr_val.Ty) != 0:
return self._handle_array_iter(for_node, var_name, ptr_val)
HandlesType.fatal_error(for_node, "指针迭代: 迭代器不是指针类型")
# 获取元素类型
elem_ty: llvmlite.LLVMType | t.CPtr = ptr_val.Ty.Pointee
if elem_ty is None:
HandlesType.fatal_error(for_node, "指针迭代: 无法获取元素类型")
# 元素类型是数组(Ptr([N x T]),如 t.CArray 变量退化指针):
# load 出数组值后走数组迭代(按长度,非 null 终止)
if HandlesExpr.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(for_node, var_name, arr_v2)
# 元素类型必须是整数(用于 icmp eq 0 检查 null 终止符)
elem_bits: int = HandlesExpr.get_llvm_type_bits(elem_ty)
if elem_bits == 0:
HandlesType.fatal_error(for_node, "指针迭代: 元素类型不是整数,无法检查 null 终止符")
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
# 创建循环变量 alloca(存储元素值)
var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, var_name)
new_vars: int = 0
if var_alloca is None:
var_alloca = HandlesVar._alloca_at_entry(builder, elem_ty)
if HandlesVar.define_var(
trans.SymTab, var_name, var_alloca) == 0:
new_vars = 1
# 创建隐式 index 变量,初始为 0
idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i32_ty)
llvmlite.build_store(builder, llvmlite.const_int32(pool, 0), idx_alloca)
# 创建基本块: cond / body / incr / end
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: 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:
HandlesBody.translate_stmt(trans, stmt)
# 恢复旧循环上下文
trans._break_bb = old_break
trans._continue_bb = old_continue
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, incr_bb)
# incr 块: index++, 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:
# 定长数组按长度迭代(元素可为任意类型,不做 null 终止符检查)
#
# 数组值是数组类型而非指针(如局部 t.CArray 修复后),
# 先拷到临时 alloca 获得地址,再按 [0, N) 迭代。
#
# 生成 IR 结构:
# %tmp = alloca [N x elem_ty]
# store [N x elem_ty] %arr_val, [N x elem_ty]* %tmp
# %idx = alloca i32 ; store 0
# br %cond
# cond:
# %i = load i32, i32* %idx
# %c = icmp slt i32 %i, N
# br i1 %c, %body, %end
# body:
# %ep = getelementptr [N x elem_ty], [N x elem_ty]* %tmp, i32 0, i32 %i
# %ev = load elem_ty, elem_ty* %ep
# store elem_ty %ev, elem_ty* %var
# ... 循环体 ...
# br %incr
# incr:
# %n = add i32 %i, 1 ; store %n ; br %cond
# end:
# ============================================================
def _handle_array_iter(self, for_node: ast.For | t.CPtr,
var_name: str,
array_val: llvmlite.Value | t.CPtr) -> int:
"""数组迭代: for x in arr: 按数组长度迭代"""
trans: HT.Translator | t.CPtr = self.Trans
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
# 解析数组类型 [N x elem_ty]
arr_ty: llvmlite.LLVMType | t.CPtr = array_val.Ty
elem_ty: llvmlite.LLVMType | t.CPtr = None
elem_count: int = 0
match arr_ty:
case llvmlite.LLVMType.Array(et, n):
elem_ty = et
elem_count = n
if elem_ty is None or elem_count <= 0:
HandlesType.fatal_error(for_node, "数组迭代: 无法解析数组类型")
# 数组值 → 临时 alloca(数组值不是指针,需拷贝后 GEP 迭代)
arr_tmp: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, arr_ty)
if arr_tmp is None:
HandlesType.fatal_error(for_node, "数组迭代: 临时存储分配失败")
llvmlite.build_store(builder, array_val, arr_tmp)
i32_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
# 循环变量 alloca(存储元素值)
var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, var_name)
new_vars: int = 0
if var_alloca is None:
var_alloca = HandlesVar._alloca_at_entry(builder, elem_ty)
if HandlesVar.define_var(
trans.SymTab, var_name, var_alloca) == 0:
new_vars = 1
# 隐式 index 变量,初始为 0
idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i32_ty)
llvmlite.build_store(builder, llvmlite.const_int32(pool, 0), idx_alloca)
# 基本块: cond / body / incr / end
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: 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:
HandlesBody.translate_stmt(trans, stmt)
trans._break_bb = old_break
trans._continue_bb = old_continue
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, incr_bb)
# incr 块: index++
llvmlite.position_at_end(builder, incr_bb)
one_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 1)
next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val)
llvmlite.build_store(builder, next_idx, idx_alloca)
llvmlite.build_br(builder, cond_bb)
# 定位到 end 块
llvmlite.position_at_end(builder, end_bb)
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
trans._ctrl_merge_reachable = 1
return new_vars
# ============================================================
# _handle_list_literal_iter - 列表字面量迭代: for x in [a, b, c]:
# 把列表字面量转成定长数组值,再复用数组迭代(按长度迭代)。
#
# 元素类型取第一个元素的值类型,其余元素 coerce 到该类型。
# ============================================================
def _handle_list_literal_iter(self, for_node: ast.For | t.CPtr,
var_name: str,
list_node: ast.AST | t.CPtr) -> int:
"""列表字面量迭代: for x in [a, b, c]: 按元素顺序迭代"""
trans: HT.Translator | t.CPtr = self.Trans
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
lst: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node)
if lst is None or lst.elts is None:
HandlesType.fatal_error(for_node, "列表字面量迭代: 空列表")
elts: list[ast.AST | t.CPtr] | t.CPtr = lst.elts
elts_count: t.CSizeT = len(elts)
if elts_count <= 0:
HandlesType.fatal_error(for_node, "列表字面量迭代: 空列表")
# 翻译第一个元素,确定元素类型
first_el: ast.AST | t.CPtr = elts.get(0)
first_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, first_el,
trans._funcs, trans._func_count, trans)
if first_val is None or first_val.Ty is None:
HandlesType.fatal_error(first_el, "列表字面量迭代: 无法确定元素类型")
elem_ty: llvmlite.LLVMType | t.CPtr = first_val.Ty
# 构建 [N x elem_ty] 数组值:临时 alloca 逐元素写入后 load
arr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Array(pool, elem_ty, elts_count)
tmp_alloca: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, arr_ty)
if tmp_alloca is None:
HandlesType.fatal_error(for_node, "列表字面量迭代: 临时数组分配失败")
first_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
builder, arr_ty, elem_ty, tmp_alloca, llvmlite.const_int32(pool, 0))
if first_ptr is not None:
llvmlite.build_store(builder, first_val, first_ptr)
# 写其余元素(coerce 到 elem_ty)
i: t.CSizeT = 1
while i < elts_count:
el_node: ast.AST | t.CPtr = elts.get(i)
el_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, el_node,
trans._funcs, trans._func_count, trans)
if el_val is not None:
el_val = HandlesExpr.coerce_to_type(builder, el_val, elem_ty, el_node)
el_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep_array(
builder, arr_ty, elem_ty, tmp_alloca,
llvmlite.const_int32(pool, i))
if el_ptr is not None:
llvmlite.build_store(builder, el_val, el_ptr)
i += 1
# load 回数组值,复用数组迭代
arr_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, arr_ty, tmp_alloca)
if arr_val is None:
HandlesType.fatal_error(for_node, "列表字面量迭代: 数组加载失败")
return self._handle_array_iter(for_node, var_name, arr_val)
# ============================================================
# _handle_list_iter - list[T] 容器迭代: for v in lst:
# 按 __count__ 动态长度迭代(元素任意类型,不做 null 终止符检查)
#
# list 结构布局 (6 字段 × 8 字节):
# __data__(0) __count__(8) __capacity__(16) __pool__(24)
# __elem_size__(32) __iter_index__(40)
#
# 生成 IR 结构:
# %count = load __count__
# %idx = alloca i64 ; store 0
# br %cond
# cond:
# %i = load i64, %idx
# %c = icmp slt i64 %i, %count
# br i1 %c, %body, %end
# body:
# %data = load __data__ (i8*)
# %es = load __elem_size__ (i64)
# %off = mul i64 %i, %es
# %addr = getelementptr i8, i8* %data, i64 %off
# %el = load i8*, i8** %addr
# store i8* %el, i8** %var
# ... 循环体 ...
# br %incr
# incr:
# %n = add i64 %i, 1 ; store ; br %cond
# end:
# ============================================================
def _handle_list_iter(self, for_node: ast.For | t.CPtr,
var_name: str,
list_val: llvmlite.Value | t.CPtr) -> int:
"""list[T] 容器迭代: for v in lst: 按 __count__ 动态长度迭代"""
trans: HT.Translator | t.CPtr = self.Trans
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
# 读取 __count__ (偏移 8, GEP index 1)
cnt_ptr: llvmlite.Value | t.CPtr = llvmlite.build_gep(
builder, i64_ty, list_val, llvmlite.const_int64(pool, 1))
if cnt_ptr is None:
HandlesType.fatal_error(for_node, "list 迭代: 无法定位 __count__")
count_val: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, i64_ty, cnt_ptr)
# 循环变量 alloca(元素类型 i8*,与 list.get 内联一致)
var_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
trans.SymTab, var_name)
new_vars: int = 0
if var_alloca is None:
var_alloca = HandlesVar._alloca_at_entry(builder, i8_ptr_ty)
if HandlesVar.define_var(
trans.SymTab, var_name, var_alloca) == 0:
new_vars = 1
# 隐式 index 变量 (i64,与 __count__ 类型对齐)
idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i64_ty)
llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), idx_alloca)
# 基本块: cond / body / incr / end
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: 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:
HandlesBody.translate_stmt(trans, stmt)
trans._break_bb = old_break
trans._continue_bb = old_continue
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, incr_bb)
# incr 块: index++
llvmlite.position_at_end(builder, incr_bb)
one_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1)
next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val)
llvmlite.build_store(builder, next_idx, idx_alloca)
llvmlite.build_br(builder, cond_bb)
# 定位到 end 块
llvmlite.position_at_end(builder, end_bb)
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
trans._ctrl_merge_reachable = 1
return new_vars
def _handle_dict_iter(self, 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]。
"""
trans: HT.Translator | t.CPtr = self.Trans
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
i64_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int64(pool)
i8_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int8(pool)
i8_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, i8_ty)
# 读取 __count__(槽 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:
HandlesType.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 = HandlesVar.lookup_var(
trans.SymTab, var_name)
new_vars: int = 0
if var_alloca is None:
var_alloca = HandlesVar._alloca_at_entry(builder, i8_ptr_ty)
if HandlesVar.define_var(
trans.SymTab, var_name, var_alloca) == 0:
new_vars = 1
# 隐式 index 变量 (i64,与 __count__ 类型对齐)
idx_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, i64_ty)
llvmlite.build_store(builder, llvmlite.const_int64(pool, 0), idx_alloca)
# 基本块: cond / body / incr / end
cnt: int = trans._label_counter
trans._label_counter = cnt + 1
name_buf: 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:
HandlesBody.translate_stmt(trans, stmt)
trans._break_bb = old_break
trans._continue_bb = old_continue
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, incr_bb)
# incr 块: index++
llvmlite.position_at_end(builder, incr_bb)
one_val: llvmlite.Value | t.CPtr = llvmlite.const_int64(pool, 1)
next_idx: llvmlite.Value | t.CPtr = llvmlite.build_add(builder, cur_idx, one_val)
llvmlite.build_store(builder, next_idx, idx_alloca)
llvmlite.build_br(builder, cond_bb)
# 定位到 end 块
llvmlite.position_at_end(builder, end_bb)
# 追加90:for 循环正常结束路径 br 到 end_bb → merge 恒可达(需正常收尾)
trans._ctrl_merge_reachable = 1
return new_vars
# ============================================================
# _handle_oop_iter - OOP 迭代协议: for x in obj:
# 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, 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__ 迭代"""
trans: HT.Translator | t.CPtr = self.Trans
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
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:
HandlesType.fatal_error(for_node, "OOP 迭代: 迭代源对象类型未知")
if HandlesExpr.is_ptr_type(obj_val.Ty) == 0:
HandlesType.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 = ExprCallBase.find_func_in_module(
mod, iter_lookup)
if iter_fn is None:
HandlesType.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 = ExprCallBase.find_func_in_module(
mod, next_lookup)
if next_fn is None:
HandlesType.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 = HandlesVar.lookup_var(
trans.SymTab, var_name)
new_vars: int = 0
if var_alloca is None:
var_alloca = HandlesVar._alloca_at_entry(builder, next_ret_ty)
if var_alloca is not None:
if HandlesVar.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:
HandlesBody.translate_stmt(trans, stmt)
trans._break_bb = old_break
trans._continue_bb = old_continue
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, 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, 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:
HandlesType.fatal_error(for_node, "enumerate 需要至少一个参数")
return self._build_seq_loop(for_node, t1, t2, cargs.get(0), None, 1)
def _handle_zip_iter(self, for_node: ast.For | t.CPtr,
t1: str, t2: str,
call: ast.Call | t.CPtr) -> int:
"""zip 迭代: for a, b in zip(x, y)"""
if call is None or call.args is None:
# fail-fast: zip 参数缺失
HandlesType.fatal_error(call, "zip 参数缺失", "SyntaxError")
cargs: list[ast.AST | t.CPtr] | t.CPtr = call.args
if len(cargs) < 2:
HandlesType.fatal_error(for_node, "zip 需要至少两个参数")
return self._build_seq_loop(for_node, t1, t2, cargs.get(0), cargs.get(1), 2)
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
# ============================================================
_g_gen: Generator.Generator | t.CPtr = None
+33 -526
View File
@@ -22,17 +22,22 @@ import lib.core.Handles.ExprCallCtor as ExprCallCtor
import lib.core.Gen.Generator as Generator
# ============================================================
# HandlesAnnAssign - AnnAssign 语句处理(迁移完成,保留跨 Mixin 委托壳)
#
# P6 机械化迁移:AnnAssignHandle 类 → AssignGenMixin.translate_annassign /
# translate_annassign_prescan。分派中枢(StmtGenMixin/StmtGenDeclMixin)经
# 本壳跨链调用(Viper @t.NoVTable 静态绑定下跨 Mixin self. 调用 mangle
# 失败,须经模块级委托壳桥回 gen 单例)。迁移收尾后统一删除。
# ============================================================
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
# ============================================================
_g_gen: Generator.Generator | t.CPtr = None
# ============================================================
# HandlesAnnAssign - AnnAssign 语句处理(Mixin 继承模式)
# ============================================================
# ============================================================
# is_cdefine_annotation - 检测注解是否为 t.CDefine(模块级函数)
#
@@ -153,58 +158,6 @@ def _is_ptr_element_annotation(annot: ast.AST | t.CPtr) -> int:
return 0
# ============================================================
# _is_single_param_carray_annot - 检查注解是否为单参 t.CArray[elem_ty]
#
# 单参形式(t.CArray[elem_ty])与 count=None 形式(t.CArray[elem_ty, None])
# 都解析为 Ptr(elem_ty)。当 RHS 是列表字面量时,按 TPC 语义应推断为
# 静态数组 [len x elem_ty](对齐 TPC ParseListAnnotation 的 is_pointer 分支:
# "单参数 list[type] → 指针,但如果有列表字面量初始化值则按数组 list[type, N] 处理")。
# ============================================================
def _is_single_param_carray_annot(annot: ast.AST | t.CPtr) -> int:
"""检查注解是否为单参/None 长度 t.CArray[...],返回 1=是 0=否
支持两种书写形式:
1. 模块限定 t.CArray[...](Attribute value)
2. 裸名 CArray[...](from t import * 后使用,如 Termination4K3 core.vp
的 `__python_suffix__: CArray[str] = ["py", ...]`)
"""
if annot is None or annot.kind() != ast.ASTKind.Subscript:
return 0
sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot)
if sub.value is None or sub.slice is None:
return 0
if sub.value.kind() == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(sub.value)
if at.attr is None or string.strcmp(at.attr, "CArray") != 0:
return 0
if at.value is None or at.value.kind() != ast.ASTKind.Name:
return 0
mv: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at.value)
if mv.id is None or string.strcmp(mv.id, "t") != 0:
return 0
elif sub.value.kind() == ast.ASTKind.Name:
# 裸名 CArray(from t import *):与 t.CArray 等价
bn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value)
if bn.id is None or string.strcmp(bn.id, "CArray") != 0:
return 0
else:
return 0
# 单参形式:slice 非 Tuple(如 t.CArray[u64] / CArray[str])
if sub.slice.kind() != ast.ASTKind.Tuple:
return 1
# 双参形式:count=None(t.CArray[u64, None])→ 等价单参
tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(sub.slice)
if tup.elts is None or len(tup.elts) < 2:
return 0
cnt_node: ast.AST | t.CPtr = tup.elts.get(1)
if cnt_node is not None and cnt_node.kind() == ast.ASTKind.Constant:
cn0: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(cnt_node)
if cn0.const_kind == ast.CONST_NONE:
return 1
return 0
# ============================================================
# _infer_static_array_ty_from_literal - 单参 CArray + 列表字面量 → 静态数组
#
@@ -213,21 +166,17 @@ def _is_single_param_carray_annot(annot: ast.AST | t.CPtr) -> int:
# 避免误走动态 list 构造(_find_pool_var 兜底引用外部 @_mbuddy → 链接期
# undefined)。PreScan 与 Handle 都调用(PreScan 预创建 alloca 的类型必须
# 与 Handle 一致,否则 get_or_create_sym 复用旧 alloca 使推断失效)。
# 真实实现已迁移至 gen._infer_static_array_ty_from_literal,本壳保留供
# ClassGenDef(Gen 侧字段类型推断)等跨模块调用方使用。
# ============================================================
def _infer_static_array_ty_from_literal(pool: memhub.MemBuddy | t.CPtr,
annot: ast.AST | t.CPtr,
value: ast.AST | t.CPtr,
resolved_ty: llvmlite.LLVMType | t.CPtr) -> llvmlite.LLVMType | t.CPtr:
"""单参 CArray + 列表字面量 → Array(elem_ty, len);否则返回原类型"""
if value is not None and value.kind() == ast.ASTKind.List and resolved_ty is not None:
if _is_single_param_carray_annot(annot) != 0:
elem_ty_arr: llvmlite.LLVMType | t.CPtr = resolved_ty.Pointee
lst_arr: ast.List | t.CPtr = (ast.List | t.CPtr)(value)
cnt_arr: int = 0
if lst_arr.elts is not None:
cnt_arr = len(lst_arr.elts)
if elem_ty_arr is not None and cnt_arr > 0:
return llvmlite.Array(pool, elem_ty_arr, cnt_arr)
"""单参 CArray + 列表字面量 → Array(elem_ty, len);否则返回原类型(委托到 gen._infer_static_array_ty_from_literal)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._infer_static_array_ty_from_literal(pool, annot, value, resolved_ty)
return resolved_ty
@@ -261,467 +210,25 @@ def _init_global_array_from_list(builder: llvmlite.IRBuilder | t.CPtr,
return 0
@t.NoVTable
class AnnAssignHandle(HandlesBase.Mixin):
"""AnnAssign 语句处理器:继承 Mixin 获得 Trans 回指针"""
def __init__(self, trans: HT.Translator | t.CPtr):
self.Trans = trans
# ============================================================
# PreScan - 预扫描 AnnAssign,为有类型注解的变量提前创建 alloca
#
# 返回新增的变量数
# ============================================================
def PreScan(self, node: ast.AST | t.CPtr) -> int:
"""预扫描 AnnAssign,提前创建 alloca 到 entry block 顶部"""
if node is None:
return 0
k: int = node.kind()
if k != ast.ASTKind.AnnAssign:
return 0
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
if aa is None or aa.target is None:
return 0
target: ast.AST | t.CPtr = aa.target
if target.kind() != ast.ASTKind.Name:
return 0
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
if nm.id is None:
return 0
# CDefine 注解: 不创建 alloca,但注册常量到全局表
# 供后续 t.CArray[elem_ty, NAME] 编译期解析使用
# 浮点/整数自动识别(与 Handle/handle_module_level_var 路径一致)
if is_cdefine_annotation(aa.annotation) != 0:
pool_ps: memhub.MemBuddy | t.CPtr = self.Trans.Pool
_register_cdefine_from_value(pool_ps, nm.id, aa.value)
return 0
# CTypedef 注解: 类型别名(ScanCTypedefDeclarations 已注册到 CTypedef 表),
# 不创建全局/局部存储——否则 stdint.vp 的 float64_t: t.CTypedef = t.CFloat64T
# 等生成 @float64_t 符号,链接 duplicate symbol warning
if is_ctypedef_annotation(aa.annotation) != 0:
return 0
# global/nonlocal 变量不需要局部 alloca
if HT.is_global_name(self.Trans, nm.id) != 0:
return 0
if HT.is_nonlocal_name(self.Trans, nm.id) != 0:
return 0
# 模块级全局变量已由 handle_module_level_var 注册到模块作用域。
# Python 语义:仅模块级代码(Current == Root)时跳过局部 alloca;
# 函数内无 global 声明时应创建局部变量(不遮蔽全局)。
if HandlesVar.is_module_scope(self.Trans.SymTab) != 0:
if HandlesVar.lookup_module_var(self.Trans.SymTab, nm.id) is not None:
return 0
# 检查是否已存在
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current(
self.Trans.SymTab, nm.id)
if existing is not None:
return 0
pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder
# 从 annotation 推断类型(修复:原硬编码 i32 导致 str 等类型错误)
var_ty: llvmlite.LLVMType | t.CPtr = None
annot: ast.AST | t.CPtr = aa.annotation
if annot is not None:
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, annot, self.Trans._imported_modules, self.Trans._from_imports, self.Trans)
if resolved is None:
# 尝试特化泛型类注解(如 list[str])
# resolve_annotation_type 返回 None 可能是因为泛型类未特化
if annot.kind() == ast.ASTKind.Subscript:
sub_annot: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(annot)
if sub_annot.value is not None and sub_annot.value.kind() == ast.ASTKind.Name:
sub_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_annot.value)
if sub_nm.id is not None:
template_cd: ast.ClassDef | t.CPtr = HandlesClassDef._find_generic_template(sub_nm.id)
spec_name_ps: str = None
if template_cd is not None:
type_args_ps: list[str] | t.CPtr = ExprCallCtor._extract_type_args_from_slice(pool, sub_annot.slice)
if type_args_ps is not None and len(type_args_ps) > 0:
spec_name_ps = HandlesClassDef._specialize_generic_class(
self.Trans, sub_nm.id, type_args_ps)
if spec_name_ps is not None:
resolved = HandlesType.resolve_annotation_type(
pool, annot, self.Trans._imported_modules, self.Trans._from_imports, self.Trans)
if resolved is not None:
var_ty = resolved
# 单参 t.CArray[elem_ty] + 列表字面量 → 静态数组(与 Handle 推断一致)。
# PreScan 预创建的 alloca 类型必须与 Handle 期望一致,否则 Handle 的
# get_or_create_sym 复用旧 alloca,数组推断失效仍走动态 list → _mbuddy。
var_ty = _infer_static_array_ty_from_literal(pool, annot, aa.value, var_ty)
else:
# fast-fail: 注解类型解析失败,Python traceback 立即终止(不静默回退 i32)
HandlesType.fatal_error(
aa,
f"变量类型注解解析失败,变量名: {nm.id}",
"TypeError")
else:
# fail-fast: AnnAssign 必须有 annotation,缺少时立即终止(禁止兜底 i32)
HandlesType.fatal_error(
aa,
f"AnnAssign 缺少类型注解,变量名: {nm.id}",
"SyntaxError")
# 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间)
HandlesStruct.ensure_struct_def_in_module(pool, self.Trans.Module, var_ty)
alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(builder, var_ty)
if alloca is not None:
if HandlesVar.define_var(
self.Trans.SymTab, nm.id, alloca) == 0:
# 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体)
# 传 pool:泛型 Subscript 返回 mangled name(GSList[BasicBlock] → 特化
# struct 名),否则 pool=None 只返回裸类名(GSList → 泛型模板未注册
# → 属性访问 lookup_field_by_class("GSList") 报"类未注册",LLVMLiteTest
# __function.vp blocks.Tail 根因;对齐 ClassGenMixin L3159 BUG 1 方案3)
if annot is not None:
cls_nm_ps: str = HandlesType.extract_class_name_from_annotation(
annot, self.Trans._imported_modules, pool)
if cls_nm_ps is not None:
HandlesVar.set_var_annot_class_name(
self.Trans.SymTab, nm.id, cls_nm_ps)
# 检查是否为 bytes|t.CPtr 或 str|t.CPtr(i8** 语义,8 字节步长)
if _is_ptr_element_annotation(annot) != 0:
HandlesVar.set_var_ptr_element(
self.Trans.SymTab, nm.id)
return 0
return 0
# ============================================================
# Handle - 翻译 AnnAssign 语句
#
# 返回新增的变量数
# ============================================================
def Handle(self, node: ast.AST | t.CPtr) -> int:
"""翻译 AnnAssign(target=Name, annotation=..., value=expr)"""
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
if aa is None:
return 0
target: ast.AST | t.CPtr = aa.target
if target is None or target.kind() != ast.ASTKind.Name:
return 0
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
if nm.id is None:
return 0
# CDefine 注解: 编译期常量,不生成运行时代码
# 注册到全局 CDefine 表供 t.CArray[elem_ty, NAME] 解析
# 注: PreScan 已注册过,此处保证即使跳过 PreScan 也能正确注册
if is_cdefine_annotation(aa.annotation) != 0:
pool_cd: memhub.MemBuddy | t.CPtr = self.Trans.Pool
_register_cdefine_from_value(pool_cd, nm.id, aa.value)
return 0
# CTypedef 注解: 类型别名(mode_t: t.CTypedef = t.CUInt32T 等)。
# 翻译期 CTypedef 表已被 clear_ctypedefs 清空(每文件隔离;表字符串
# pool 分配,reset_to(mark1) 回收后悬空,不能跨文件累积),必须在此
# 按需注册,否则 posix.vp S_ISREG(mode: mode_t) 等普通函数参数注解
# 解析查表失败 → NameError: mode_t。仅登记类型表达式,不创建全局/
# 局部存储——否则生成 @mode_t 符号,链接 duplicate symbol warning。
if is_ctypedef_annotation(aa.annotation) != 0:
pool_ct: memhub.MemBuddy | t.CPtr = self.Trans.Pool
ctd_str: str = HandlesType._get_type_name_from_annotation(pool_ct, aa.value)
if ctd_str is not None:
HandlesType.register_ctypedef(pool_ct, nm.id, ctd_str)
return 0
pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder
mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module
# 确定类型(从 annotation 推断)
var_ty: llvmlite.LLVMType | t.CPtr = None
annot: ast.AST | t.CPtr = aa.annotation
if annot is not None:
resolved: llvmlite.LLVMType | t.CPtr = HandlesType.resolve_annotation_type(
pool, annot, self.Trans._imported_modules, self.Trans._from_imports, self.Trans)
if resolved is not None:
var_ty = resolved
else:
# fast-fail: 注解类型解析失败,Python traceback 立即终止(不静默回退 i32)
HandlesType.fatal_error(
aa,
f"变量类型注解解析失败,变量名: {nm.id}",
"TypeError")
else:
# fail-fast: AnnAssign 必须有 annotation,缺少时立即终止(禁止兜底 i32)
HandlesType.fatal_error(
aa,
f"AnnAssign 缺少类型注解,变量名: {nm.id}",
"SyntaxError")
# t.Callable 函数指针:注册返回类型签名(供函数指针间接调用精确返回类型)
callable_ret: llvmlite.LLVMType | t.CPtr = HandlesType.try_extract_callable_ret(
pool, annot, self.Trans._imported_modules, self.Trans._from_imports, self.Trans)
if callable_ret is not None:
ExprCallCall.register_func_ptr_sig(nm.id, callable_ret)
# global 变量:写入模块作用域中的全局变量
if HT.is_global_name(self.Trans, nm.id) != 0:
mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
self.Trans.SymTab, nm.id)
if mod_alloca is not None and aa.value is not None:
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, aa.value,
None, 0, self.Trans)
if rhs_val is not None:
target_ty: llvmlite.LLVMType | t.CPtr = None
if mod_alloca.Ty is not None:
target_ty = mod_alloca.Ty.Pointee
if target_ty is not None:
rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty, node)
llvmlite.build_store(builder, rhs_val, mod_alloca)
return 0
# nonlocal 变量:通过闭包 env 写入
if HT.is_nonlocal_name(self.Trans, nm.id) != 0:
if aa.value is not None:
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, aa.value,
None, 0, self.Trans)
if rhs_val is not None:
nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr(
self.Trans, nm.id)
if nl_ptr is not None:
# 从 nl_ptr 的类型推断 nonlocal 变量实际类型,
# 不再强制 i32(会截断指针/结构体/i64 导致闭包数据损坏)
nl_target_ty: llvmlite.LLVMType | t.CPtr = None
if nl_ptr.Ty is not None:
nl_target_ty = nl_ptr.Ty.Pointee
if nl_target_ty is None:
# fast-fail: nl_ptr 类型信息丢失,无法安全 store
VLogger.error(
f"nonlocal 变量类型信息丢失,无法写入: {nm.id}",
"HandlesAnnAssign")
return 0
rhs_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
builder, rhs_val, nl_target_ty, node)
llvmlite.build_store(builder, rhs_coerced, nl_ptr)
return 0
# 模块级全局变量(由 handle_module_level_var 注册到模块作用域)
# Python 语义:仅模块级代码(Current == Root)时修改全局变量;
# 函数内无 global 声明时应创建局部变量(走后面的 get_or_create_sym 路径)。
if HandlesVar.is_module_scope(self.Trans.SymTab) != 0:
mod_glob: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
self.Trans.SymTab, nm.id)
else:
mod_glob = None
if mod_glob is not None:
if aa.value is not None:
# 列表字面量 → 逐元素 GEP + store 初始化数组
if aa.value.kind() == ast.ASTKind.List:
_init_global_array_from_list(
builder, pool, mod, mod_glob, aa.value, self.Trans)
else:
rhs_val_mg: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, aa.value,
None, 0, self.Trans)
if rhs_val_mg is not None:
target_ty_mg: llvmlite.LLVMType | t.CPtr = None
if mod_glob.Ty is not None:
target_ty_mg = mod_glob.Ty.Pointee
if target_ty_mg is not None:
rhs_val_mg = HandlesExpr.coerce_to_type(builder, rhs_val_mg, target_ty_mg, node)
llvmlite.build_store(builder, rhs_val_mg, mod_glob)
return 0
# 单参 t.CArray[elem_ty] + 列表字面量 → 按静态数组处理(count 从字面量长度推断)
# 与 PreScan 推断一致:get_or_create_sym 复用 PreScan 创建的 alloca,
# 类型一致才能命中局部数组快路径,避免 _find_pool_var 兜底引用 @_mbuddy。
var_ty = _infer_static_array_ty_from_literal(pool, annot, aa.value, var_ty)
# 普通局部变量
# 创建 alloca
alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym(
self.Trans.SymTab, pool, builder, nm.id, var_ty)
if alloca is None:
# fail-fast: 存储创建失败,立即终止(禁止静默跳过)
HandlesType.fatal_error(
aa,
f"无法为变量 {nm.id} 创建存储",
"TypeError")
# FakeDuck: str 变量创建影子结构体 {var}__meta__(per-instance 字段存储)
# 仅裸 str 注解(Name("str"))且 _str 已注册时创建;bytes / t.CChar|t.CPtr 不创建。
# a 保持为 i8*(可 printf/len),a__meta__ 存 __data__/__mbuddy__ 等字段,
# 属性读写(fd3)与方法调用(fd5)均通过该影子解析。
fd_str_ty: llvmlite.LLVMType | t.CPtr = None
fd_meta_alloca: llvmlite.Value | t.CPtr = None
fd_meta_name: str = None
if annot is not None and annot.kind() == ast.ASTKind.Name:
fd_annot: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annot)
if fd_annot is not None and fd_annot.id is not None:
if string.strcmp(fd_annot.id, "str") == 0:
fd_str_ty = HandlesStruct.get_struct_type("_str")
if fd_str_ty is not None:
# 确保 _str 完整类型定义在当前模块可用:跨模块结构体默认 opaque,
# 直接 alloca opaque 类型 → llc "Cannot allocate unsized type"
HandlesStruct.ensure_struct_def_in_module(pool, mod, fd_str_ty)
# 影子变量名必须用 pool 持久缓冲:f-string 生成栈缓冲,在 AnnAssign
# 返回后被覆盖,符号表注册的名字内容损坏 → 后续 lookup 找不到。
fd_meta_name = pool.alloc(256)
if fd_meta_name is not None:
viperlib.snprintf(fd_meta_name, 256, "%s__meta__", nm.id)
fd_meta_alloca = HandlesVar.get_or_create_sym(
self.Trans.SymTab, pool, builder, fd_meta_name, fd_str_ty)
if fd_meta_alloca is None:
# fail-fast: 影子存储创建失败,立即终止
HandlesType.fatal_error(
aa,
f"无法为 str 影子变量 {fd_meta_name} 创建存储",
"TypeError")
# 存储原始类型注解的类名(方法调用检测时,Ptr(i8) 回退到类名查找结构体)
# 传 pool:泛型 Subscript 返回 mangled name(对齐 L401 同根因修复)
if annot is not None:
cls_nm_hd: str = HandlesType.extract_class_name_from_annotation(
annot, self.Trans._imported_modules, pool)
if cls_nm_hd is not None:
HandlesVar.set_var_annot_class_name(
self.Trans.SymTab, nm.id, cls_nm_hd)
# 检查是否为 bytes|t.CPtr 或 str|t.CPtr(i8** 语义,8 字节步长)
if _is_ptr_element_annotation(annot) != 0:
HandlesVar.set_var_ptr_element(
self.Trans.SymTab, nm.id)
new_vars: int = 0
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current(
self.Trans.SymTab, nm.id)
if existing is None:
new_vars = 1
# 如果有初始值,store
if aa.value is not None:
# 局部数组:列表字面量 → 逐元素 GEP + store 初始化
# 修复:此前局部 CArray[...] = [x, y] 会走 translate_list_literal,
# 错误触发 list[T] 泛型特化(堆对象)导致崩溃(如 this.vp 的
# t.CArray[t.CChar, 256] = [0])。局部 alloca 未零初始化,
# 先整体置零再写列表元素(与全局数组默认零初始化语义一致)。
local_arr_ty: llvmlite.LLVMType | t.CPtr = None
if aa.value.kind() == ast.ASTKind.List and alloca.Ty is not None:
pt_l: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
if HandlesExpr.is_array_type(pt_l) != 0:
local_arr_ty = pt_l
if local_arr_ty is not None:
zero_arr: llvmlite.Value | t.CPtr = llvmlite.ConstZero(
pool, local_arr_ty)
if zero_arr is not None:
llvmlite.build_store(builder, zero_arr, alloca)
_init_global_array_from_list(
builder, pool, mod, alloca, aa.value, self.Trans)
else:
# 供 c.Deref(i8*) 推断读取宽度:v: int = c.Deref(p) → 读 i32
# CurAssignNode 记录 RHS 节点:translate_c_deref 据此判定 Deref
# 是否为赋值直接 RHS(对齐 TPC _infer_deref_target_type)。
self.Trans.CurAssignAnnot = aa.annotation
self.Trans.CurAssignNode = aa.value
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, aa.value,
None, 0, self.Trans)
if rhs_val is not None:
# 注解退化修复(对齐 TPC 从构造结果推断类型):
# 无实参泛型模板类注解(如 vi: vector.Vector | CPtr,模板
# 未注册 struct → resolve 退化)会让 alloca 类型退化为
# Ptr(i8),但 rhs 构造返回精确结构体指针(如 Ptr(Vector[int]
# 结构))。此时按退化 alloca store 会丢失特化类型,后续
# vi.push 方法调用按 Ptr(i8) 查不到类名 → AnnotClassName
# 回退到模板名(无实参)→ vpi 查不到返回类型 fail-fast。
# 用 rhs 精确类型重建 alloca 并更新符号表注册,使方法调用
# 按精确特化类名解析。旧退化 alloca 行残留为 entry block
# 死代码(文本 IR 即时生成,无法删除,无害)。
precise_rhs_ty: llvmlite.LLVMType | t.CPtr = None
if rhs_val.Ty is not None:
match rhs_val.Ty:
case llvmlite.LLVMType.Ptr(inner_struct):
match inner_struct:
case llvmlite.LLVMType.Struct(_, _, _):
precise_rhs_ty = rhs_val.Ty
case _:
pass
case _:
pass
if precise_rhs_ty is not None and alloca.Ty is not None:
alloca_pt: llvmlite.LLVMType | t.CPtr = alloca.Ty.Pointee
if alloca_pt is not None and \
t.CUInt64T(alloca_pt) != t.CUInt64T(precise_rhs_ty):
new_alloca: llvmlite.Value | t.CPtr = HandlesVar._alloca_at_entry(
builder, precise_rhs_ty)
if new_alloca is not None:
v_entry_rb: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
self.Trans.SymTab, nm.id)
if v_entry_rb is not None:
v_entry_rb.Alloca = new_alloca
alloca = new_alloca
# 类型转换:将 rhs_val 转换为 alloca 的 pointee 类型
# 修复:整数字面量是 i32,但变量可能是 i8/i16/i64,需 trunc/sext
target_ty: llvmlite.LLVMType | t.CPtr = None
if alloca.Ty is not None:
target_ty = alloca.Ty.Pointee
if target_ty is not None:
rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty, node)
llvmlite.build_store(builder, rhs_val, alloca)
# FakeDuck: 初始化影子结构体 __data__ 字段 = 初始字符串指针
# (对齐 TPC HandlesAnnAssign.py: 仅当有初值时写入 __data__)
if fd_str_ty is not None and fd_meta_alloca is not None:
fd_data_fe: HandlesStruct.FieldEntry | t.CPtr = \
HandlesStruct.lookup_field(fd_str_ty, "__data__")
if fd_data_fe is not None:
fd_data_ptr: llvmlite.Value | t.CPtr = \
llvmlite.build_gep_struct(
builder, fd_str_ty, fd_data_fe.Ty,
fd_meta_alloca, fd_data_fe.Index)
if fd_data_ptr is not None:
llvmlite.build_store(builder, rhs_val, fd_data_ptr)
# 清除赋值上下文(防残留):CurAssignAnnot/CurAssignNode 只在该
# AnnAssign 的 RHS 翻译期间有效,否则后续 while 条件/比较等处的
# c.Deref 会被残留注解误判读取宽度(i8* 被 bitcast i32* 读 4 字节)。
self.Trans.CurAssignAnnot = None
self.Trans.CurAssignNode = None
# FakeDuck: __mbuddy__ 字段初始化为 NULL。
# with 上下文提供的 __mbuddy__ 注入由 _inject_requires_fields(fd4)完成,
# 此处仅确保影子结构体初始为空指针(对齐 TPC HandlesAnnAssign.py L667-670)。
if fd_str_ty is not None and fd_meta_alloca is not None:
fd_buddy_fe: HandlesStruct.FieldEntry | t.CPtr = \
HandlesStruct.lookup_field(fd_str_ty, "__mbuddy__")
if fd_buddy_fe is not None and fd_buddy_fe.Ty is not None:
fd_null: llvmlite.Value | t.CPtr = llvmlite.ConstNull(
pool, fd_buddy_fe.Ty, "null")
fd_buddy_ptr: llvmlite.Value | t.CPtr = \
llvmlite.build_gep_struct(
builder, fd_str_ty, fd_buddy_fe.Ty,
fd_meta_alloca, fd_buddy_fe.Index)
if fd_buddy_ptr is not None and fd_null is not None:
llvmlite.build_store(builder, fd_null, fd_buddy_ptr)
# FakeDuck: with 上下文自动注入 requires 字段(如 __mbuddy__)。
# 经全局 gen 单例委托 CallGenMixin._inject_requires_fields。
import lib.core.Gen.Generator as Generator
g_fda: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(
t.CVoid(_g_gen, t.CPtr))
if g_fda is not None:
g_fda._inject_requires_fields(
self.Trans, pool, builder, mod, fd_meta_alloca, "_str")
# ============================================================
# translate_annassign - AnnAssign 语句翻译(委托到 gen.translate_annassign)
# ============================================================
def translate_annassign(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译 AnnAssign 语句,返回新增变量数(委托到 gen.translate_annassign)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.translate_annassign(trans, node)
return 0
# ============================================================
# NewAnnAssignHandle - 工厂函数
# translate_annassign_prescan - AnnAssign 预扫描(委托到 gen.translate_annassign_prescan)
# ============================================================
def NewAnnAssignHandle(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> AnnAssignHandle | t.CPtr:
h: AnnAssignHandle | t.CPtr = pool.alloc(AnnAssignHandle.__sizeof__())
if h is None:
return None
string.memset(h, 0, AnnAssignHandle.__sizeof__())
h.Trans = trans
return h
def translate_annassign_prescan(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""预扫描 AnnAssign,提前创建 alloca 到 entry block 顶部(委托到 gen.translate_annassign_prescan)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.translate_annassign_prescan(trans, node)
return 0
+18 -789
View File
@@ -20,803 +20,32 @@ import lib.core.StubMergerStore as StubMergerStore
import lib.core.Handles.ExprCallBase as ExprCallBase
import lib.core.Handles.ExprCallCall as ExprCallCall
import lib.core.Handles.ExprCallCtor as ExprCallCtor
import lib.core.Gen.Generator as Generator
# ============================================================
# HandlesAssign - Assign 语句处理(Mixin 继承模式)
# HandlesAssign - Assign 语句处理(迁移完成,保留跨 Mixin 委托壳)
#
# 对应 TransPyC 的 class AssignHandle(BaseHandle):
# @t.NoVTable 继承 Mixin 获得 Trans 字段(展平嵌入,无 vtable)
# 通过 self.Trans 访问共享状态(Pool/Module/_cur_builder/SymTab/...)
# 通过 self.Trans.ExprH / self.Trans.IfH 等访问其他 Handle
# P6 机械化迁移:AssignHandle 类 → AssignGenMixin.translate_assign
# (lib.core.Gen.AssignGenMixin)。分派中枢(StmtGenMixin)经本壳跨链
# 调用(Viper @t.NoVTable 静态绑定下跨 Mixin self. 调用 mangle 失败,
# 须经模块级委托壳桥回 gen 单例)。迁移收尾后统一删除。
# ============================================================
@t.NoVTable
class AssignHandle(HandlesBase.Mixin):
"""Assign 语句处理器:继承 Mixin 获得 Trans 回指针 + 共享方法"""
_CurrentClass: str # 模块私有状态
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
# ============================================================
_g_gen: Generator.Generator | t.CPtr = None
def __init__(self, trans: HT.Translator | t.CPtr):
self.Trans = trans
self._CurrentClass = None
# ============================================================
# Handle - 处理 Assign 语句,返回新增变量数(0 或 1)
#
# 对应 TransPyC AssignHandle._HandleAssignLlvm
# 共享状态从 self.Trans 获取,无需 11 个参数
# ============================================================
def Handle(self, node: ast.AST | t.CPtr) -> int:
asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node)
if asgn is None:
VLogger.error("cast failed", "ASGN")
return 0
targets: list[ast.AST | t.CPtr] | t.CPtr = asgn.targets
if targets is None:
VLogger.error("targets is None", "ASGN")
return 0
# 从 self.Trans 取共享状态(替代 11 个参数)
pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder
mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module
# 翻译 RHS 值
# 无注解赋值无目标类型可推断,清空 CurAssignAnnot/CurAssignNode
# (防残留误判 c.Deref 宽度)
self.Trans.CurAssignAnnot = None
self.Trans.CurAssignNode = None
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, asgn.value, None, 0, self.Trans)
if rhs_val is None:
# Phase A 依赖未就绪(_deps_pending=1):跨模块函数/方法因 text.ll
# 未生成返回类型退化为 void/None(CallGenMixin L4493
# g_vta._resolve_attr_field_class 根因)。此时整文件不写盘、下遍重译
# (Phase2.vp L590-599),跳过本语句不报错——否则 fatal 使多遍
# 重试机制永远无法收敛(本语句只是"本遍保持默认类型"的退化结果,
# 下遍依赖已生成即可精确解析)。依赖就绪时 _deps_pending=0,
# 此处仍 fail-fast,不掩盖真实错误。
if self.Trans is not None and self.Trans._deps_pending != 0:
return 0
# 增强错误信息:包含文件名 + lineno + AST 节点详情,便于定位
fb: str = VLogger.fmt_buf()
if fb is not None and asgn.value is not None:
sha1: str = self.Trans.ModuleSha1
val_kind: int = asgn.value.kind()
val_line: t.CInt = asgn.value.lineno
# 通过 sha1 查找文件名(人类可读)
rel_path: str = None
if sha1 is not None:
rel_path = StubMergerStore.LookupSha1RelPath(sha1)
# 根据 AST 节点类型提取详情
if val_kind == ast.ASTKind.Attribute:
at_nv: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(asgn.value)
attr_nm: str = at_nv.attr
target_nm: str = "?"
if at_nv.value is not None:
if at_nv.value.kind() == ast.ASTKind.Name:
tn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(at_nv.value)
target_nm = tn_nm.id
if rel_path is not None:
viperlib.snprintf(fb, 1024,
"赋值右侧为 None: %s:%d '%s.%s' 属性访问失败",
rel_path, val_line, target_nm, attr_nm)
else:
viperlib.snprintf(fb, 1024,
"赋值右侧为 None: sha1=%s:%d '%s.%s' 属性访问失败",
sha1, val_line, target_nm, attr_nm)
elif val_kind == ast.ASTKind.Name:
nm_nv: ast.Name | t.CPtr = (ast.Name | t.CPtr)(asgn.value)
if rel_path is not None:
viperlib.snprintf(fb, 1024,
"赋值右侧为 None: %s:%d 变量 '%s' 未找到",
rel_path, val_line, nm_nv.id)
else:
viperlib.snprintf(fb, 1024,
"赋值右侧为 None: sha1=%s:%d 变量 '%s' 未找到",
sha1, val_line, nm_nv.id)
elif val_kind == ast.ASTKind.Call:
cl_nv: ast.Call | t.CPtr = (ast.Call | t.CPtr)(asgn.value)
func_nm: str = "?"
if cl_nv.func is not None:
if cl_nv.func.kind() == ast.ASTKind.Name:
fn_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(cl_nv.func)
func_nm = fn_nm.id
if rel_path is not None:
viperlib.snprintf(fb, 1024,
"赋值右侧为 None: %s:%d 调用 '%s(...)' 返回 None",
rel_path, val_line, func_nm)
else:
viperlib.snprintf(fb, 1024,
"赋值右侧为 None: sha1=%s:%d 调用 '%s(...)' 返回 None",
sha1, val_line, func_nm)
else:
if rel_path is not None:
viperlib.snprintf(fb, 1024,
"赋值右侧为 None: %s:%d [kind=%d]",
rel_path, val_line, val_kind)
else:
viperlib.snprintf(fb, 1024,
"赋值右侧为 None: sha1=%s:%d [kind=%d]",
sha1, val_line, val_kind)
VLogger.error(fb, "ASGN")
else:
VLogger.error("赋值右侧为 None (asgn.value 为空)", "ASGN")
return 0
new_vars: int = 0
tn: t.CSizeT = len(targets)
for ti in range(tn):
target: ast.AST | t.CPtr = targets.get(ti)
if target is None:
continue
tk: int = target.kind()
# Tuple 赋值: a, b = f() 多返回值解包
# rhs_val 是匿名 struct 值(函数返回 tuple[T1,T2] 打包)→ alloca +
# store + GEP 逐字段 load → store 到各 Name 目标。
if tk == ast.ASTKind.Tuple:
tgt_tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(target)
tgt_elts: list[ast.AST | t.CPtr] | t.CPtr = tgt_tup.elts
# 守卫:rhs 不是 struct(tuple 打包)时跳过本 target
if tgt_elts is None or rhs_val is None or rhs_val.Ty is None:
continue
match rhs_val.Ty:
case llvmlite.LLVMType.Struct(_, _, _):
tgt_n: t.CSizeT = len(tgt_elts)
tmp_s: llvmlite.Value | t.CPtr = llvmlite.build_alloca(builder, rhs_val.Ty)
if tmp_s is not None:
llvmlite.build_store(builder, rhs_val, tmp_s)
fchain: llvmlite.ParamNode | t.CPtr = llvmlite.get_struct_fields(rhs_val.Ty)
fcur: llvmlite.ParamNode | t.CPtr = fchain
fti: t.CSizeT
for fti in range(tgt_n):
tgt_elt: ast.AST | t.CPtr = tgt_elts.get(fti)
if tgt_elt is None or fcur is None:
break
fty: llvmlite.LLVMType | t.CPtr = llvmlite.paramnode_get_ty(fcur)
fcur = llvmlite.paramnode_get_next(fcur)
if fty is None:
# fail-fast: 字段类型缺失,立即终止
HandlesType.fatal_error(target, "元组解包字段类型缺失", "TypeError")
# 守卫:非 Name 元素无法解包,跳过
if tgt_elt.kind() != ast.ASTKind.Name:
continue
tgt_nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(tgt_elt)
if tgt_nm2.id is None:
continue
fp2: llvmlite.Value | t.CPtr = llvmlite.build_gep_struct(
builder, rhs_val.Ty, fty, tmp_s, fti)
if fp2 is None:
continue
fv2: llvmlite.Value | t.CPtr = llvmlite.build_load(builder, fty, fp2)
tgt_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
self.Trans.SymTab, tgt_nm2.id)
if tgt_alloca is None:
tgt_alloca = HandlesVar.get_or_create_sym(
self.Trans.SymTab, pool, builder, tgt_nm2.id, fty)
if tgt_alloca is None:
continue
sval: llvmlite.Value | t.CPtr = fv2
if tgt_alloca.Ty is not None and tgt_alloca.Ty.Pointee is not None:
sval = HandlesExpr.coerce_to_type(
builder, fv2, tgt_alloca.Ty.Pointee, node)
llvmlite.build_store(builder, sval, tgt_alloca)
case _:
pass
continue
# Subscript 赋值: arr[i] = val / ptr[i] = val / list[i] = val
if tk == ast.ASTKind.Subscript:
# 检查是否是 list[T] 类型的 Subscript(泛型类不注册 struct)
# list 的 subscript 赋值走 __setitem__ 内联路径
list_obj: llvmlite.Value | t.CPtr = HandlesExpr.is_list_subscript(
target, self.Trans)
if list_obj is not None:
# list[T] 类型: 内联生成 __setitem__ 逻辑
sub_node: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(target)
if sub_node is not None and sub_node.slice is not None:
list_idx_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, sub_node.slice, None, 0, self.Trans)
if list_idx_val is None:
# fail-fast: list 下标翻译失败,立即终止
HandlesType.fatal_error(target, "list 下标翻译失败", "TypeError")
HandlesExpr.list_setitem_inline(
builder, pool, list_obj, list_idx_val, rhs_val, target)
continue
# 普通 Subscript 赋值
elem_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_subscript_ptr(
builder, pool, mod, target, self.Trans)
if elem_ptr is not None:
store_val: llvmlite.Value | t.CPtr = rhs_val
# 守卫短路:elem 类型完整才做类型转换
if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None:
store_val = HandlesExpr.coerce_to_type(
builder, rhs_val, elem_ptr.Ty.Pointee, node)
llvmlite.build_store(builder, store_val, elem_ptr)
continue
# get_subscript_ptr 返回 None: 尝试 __setitem__ 运算符重载
# 适用于自定义类(如 hashtable[key]=val → hashtable.__setitem__(key, val))
sub_asgn: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(target)
setitem_done: int = 0
if sub_asgn is not None and sub_asgn.value is not None:
if sub_asgn.value.kind() == ast.ASTKind.Name:
sub_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub_asgn.value)
if sub_nm.id is not None:
sub_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_var(
self.Trans.SymTab, sub_nm.id)
if sub_alloca is not None and sub_alloca.Ty is not None \
and sub_alloca.Ty.Pointee is not None \
and HandlesExpr.is_ptr_type(sub_alloca.Ty) != 0:
sub_pointee: llvmlite.LLVMType | t.CPtr = sub_alloca.Ty.Pointee
cls_nm_set: str = HandlesStruct.get_class_name_by_type(pool, sub_pointee)
obj_val_set: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, sub_pointee, sub_alloca)
# 指针类型变量 (X|t.CPtr): sub_pointee 是 Ptr(Struct),
# 需 load 获取 Ptr(Struct) 再检查 inner struct
if cls_nm_set is None and obj_val_set is not None \
and HandlesExpr.is_ptr_type(sub_pointee) != 0 \
and sub_pointee.Pointee is not None:
cls_nm_set = HandlesStruct.get_class_name_by_type(
pool, sub_pointee.Pointee)
if cls_nm_set is not None and obj_val_set is not None:
key_val_set: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, sub_asgn.slice, None, 0, self.Trans)
if key_val_set is not None:
arg_vals_set: t.CSizeT | t.CPtr = pool.alloc(16)
if arg_vals_set is not None:
arg_vals_set[0] = t.CSizeT(key_val_set)
arg_vals_set[1] = t.CSizeT(rhs_val)
ExprCallCtor._call_method_on_ptr(
pool, builder, mod, cls_nm_set, "__setitem__",
obj_val_set, arg_vals_set, 2, self.Trans)
setitem_done = 1
elif sub_asgn.value.kind() == ast.ASTKind.Attribute:
# self._ht[key] = val → self._ht.__setitem__(key, val)
# 通过 get_attribute_ptr 获取字段指针,再调用 __setitem__
field_ptr_set: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
builder, pool, mod, sub_asgn.value, self.Trans)
if field_ptr_set is not None and field_ptr_set.Ty is not None \
and field_ptr_set.Ty.Pointee is not None \
and HandlesExpr.is_ptr_type(field_ptr_set.Ty) != 0:
field_pointee_set: llvmlite.LLVMType | t.CPtr = field_ptr_set.Ty.Pointee
cls_nm_attr: str = HandlesStruct.get_class_name_by_type(pool, field_pointee_set)
obj_val_attr: llvmlite.Value | t.CPtr = field_ptr_set
# field_ptr 是 Ptr(Ptr(Struct)) (X|t.CPtr 字段):
# load 解引用获取 Ptr(Struct)
if cls_nm_attr is None \
and HandlesExpr.is_ptr_type(field_pointee_set) != 0 \
and field_pointee_set.Pointee is not None:
cls_nm_attr = HandlesStruct.get_class_name_by_type(
pool, field_pointee_set.Pointee)
if cls_nm_attr is not None:
obj_val_attr = llvmlite.build_load(
builder, field_pointee_set, field_ptr_set)
if cls_nm_attr is not None and obj_val_attr is not None:
key_val_attr: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, sub_asgn.slice, None, 0, self.Trans)
if key_val_attr is not None:
arg_vals_attr: t.CSizeT | t.CPtr = pool.alloc(16)
if arg_vals_attr is not None:
arg_vals_attr[0] = t.CSizeT(key_val_attr)
arg_vals_attr[1] = t.CSizeT(rhs_val)
ExprCallCtor._call_method_on_ptr(
pool, builder, mod, cls_nm_attr, "__setitem__",
obj_val_attr, arg_vals_attr, 2, self.Trans)
setitem_done = 1
if setitem_done == 0:
# 通用 fallback: 翻译 sub.value 并尝试 __setitem__ 或直接 GEP+store
# 处理 Name/Attribute 之外的节点以及 SymTab 查找失败的情况
if sub_asgn is not None and sub_asgn.value is not None:
obj_val_gen: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, sub_asgn.value, None, 0, self.Trans)
key_val_gen: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, sub_asgn.slice, None, 0, self.Trans)
if obj_val_gen is not None and key_val_gen is not None \
and obj_val_gen.Ty is not None:
# 内联 _get_custom_struct_cls_nm 逻辑(避免依赖新函数)
cls_nm_gen: str = HandlesStruct.get_class_name_by_type(
pool, obj_val_gen.Ty)
if cls_nm_gen is None and HandlesExpr.is_ptr_type(obj_val_gen.Ty) != 0 \
and obj_val_gen.Ty.Pointee is not None:
cls_nm_gen = HandlesStruct.get_class_name_by_type(
pool, obj_val_gen.Ty.Pointee)
if cls_nm_gen is not None:
# 自定义结构体: 调用 __setitem__
arg_vals_gen: t.CSizeT | t.CPtr = pool.alloc(16)
if arg_vals_gen is not None:
arg_vals_gen[0] = t.CSizeT(key_val_gen)
arg_vals_gen[1] = t.CSizeT(rhs_val)
ExprCallCtor._call_method_on_ptr(
pool, builder, mod, cls_nm_gen, "__setitem__",
obj_val_gen, arg_vals_gen, 2, self.Trans)
setitem_done = 1
elif HandlesExpr.is_ptr_type(obj_val_gen.Ty) != 0 \
and obj_val_gen.Ty.Pointee is not None:
# 非自定义结构体: 直接 GEP + store
# 处理 get_subscript_ptr 因边界情况返回 None 的指针下标
elem_gen: llvmlite.LLVMType | t.CPtr = obj_val_gen.Ty.Pointee
store_val_gen: llvmlite.Value | t.CPtr = rhs_val
elem_ptr_gen: llvmlite.Value | t.CPtr = None
match elem_gen:
case llvmlite.LLVMType.Array(arr_elem_gen, _):
elem_ptr_gen = llvmlite.build_gep_array(
builder, elem_gen, arr_elem_gen,
obj_val_gen, key_val_gen)
case _:
elem_ptr_gen = llvmlite.build_gep(
builder, elem_gen, obj_val_gen, key_val_gen)
if elem_ptr_gen is not None and elem_ptr_gen.Ty is not None:
if elem_ptr_gen.Ty.Pointee is not None:
store_val_gen = HandlesExpr.coerce_to_type(
builder, rhs_val, elem_ptr_gen.Ty.Pointee, node)
llvmlite.build_store(builder, store_val_gen, elem_ptr_gen)
setitem_done = 1
if setitem_done == 0:
HandlesType.fatal_error(target, "subscript ptr is None")
continue
# Attribute 赋值: obj.field = val
if tk == ast.ASTKind.Attribute:
# property setter 拦截: obj.attr = v 且 attr 是 @x.setter 方法时,
# 生成 call Class.attr$set(obj, v),跳过字段存储
# 注意参数顺序:_try_property_setter(pool, builder, mod, ...)——
# 旧代码传 (builder, pool, ...) 导致 pool/builder 错位,pool 参数
# 实际是 IRBuilder 对象,pool.alloc 虚调用读 IRBuilder[0] 当 vtable
# 跳到垃圾地址崩溃(BuiltinDecoratorTest Phase A 崩溃根因)。
if ExprCallCtor._try_property_setter(
pool, builder, mod, target, rhs_val, self.Trans) == 1:
continue
# FakeDuck: 影子结构体属性写入 (str 变量的 per-instance 字段)
# a.__data__ = v → GEP {a}__meta__[field] 并 store
# 对齐 TPC HandlesAssign.py L67-76:对象是 Name 变量且存在
# {var}__meta__ 影子(fd2 创建)时,属性写入改走影子结构体。
fd_an: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(target)
if fd_an is not None and fd_an.value is not None and fd_an.attr is not None:
if fd_an.value.kind() == ast.ASTKind.Name:
fd_obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(fd_an.value)
if fd_obj_nm.id is not None:
# pool 持久缓冲(f-string 栈缓冲在函数返回后失效)
fd_meta_w: str = pool.alloc(256)
if fd_meta_w is not None:
viperlib.snprintf(fd_meta_w, 256, "%s__meta__", fd_obj_nm.id)
fd_meta_vw: llvmlite.Value | t.CPtr = HandlesVar.lookup_current(
self.Trans.SymTab, fd_meta_w)
if fd_meta_vw is not None:
fd_sty_w: llvmlite.LLVMType | t.CPtr = \
HandlesStruct.get_struct_type("_str")
if fd_sty_w is not None:
fd_fe_w: HandlesStruct.FieldEntry | t.CPtr = \
HandlesStruct.lookup_field(fd_sty_w, fd_an.attr)
if fd_fe_w is not None and fd_fe_w.Ty is not None:
fd_fp_w: llvmlite.Value | t.CPtr = \
llvmlite.build_gep_struct(
builder, fd_sty_w, fd_fe_w.Ty,
fd_meta_vw, fd_fe_w.Index)
if fd_fp_w is not None:
sv_fd: llvmlite.Value | t.CPtr = \
HandlesExpr.coerce_to_type(
builder, rhs_val, fd_fe_w.Ty, node)
llvmlite.build_store(builder, sv_fd, fd_fp_w)
continue
# VTABLE 直接写入:obj.method = func(serial0_file.open = serial0_open)
# vtable 方法不是数据字段(FieldEntry),get_attribute_ptr 查不到会
# fatal_error;此处对齐 TPC HandlesAssign.py L905-949 的写时复制,
# 检测到 vtable 方法时直接生成槽位写入并跳过字段路径。
import lib.core.Gen.Generator as Generator
g_vtw: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(
t.CVoid(HandlesExpr._g_gen, t.CPtr))
if g_vtw is not None:
if g_vtw._write_vtable_attr(
builder, pool, mod, target, rhs_val, self.Trans) == 1:
continue
field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
builder, pool, mod, target, self.Trans)
if field_ptr is not None:
# 获取字段类型,对 rhs_val 进行类型转换(如 i32 → i64)
store_val: llvmlite.Value | t.CPtr = rhs_val
if field_ptr.Ty is not None and field_ptr.Ty.Pointee is not None:
store_val = HandlesExpr.coerce_to_type(
builder, rhs_val, field_ptr.Ty.Pointee, node)
llvmlite.build_store(builder, store_val, field_ptr)
continue
# 守卫:field_ptr 为 None → 构造详细错误信息
# Phase A 依赖未就绪(_deps_pending):get_attribute_ptr 已因
# 父类/依赖类未注册跳过字段,此处同样跳过不报错,整文件下遍重译
# (对齐 HandlesAssign L69-78 与 get_attribute_ptr 的 pending 容忍)
if self.Trans is not None and self.Trans._deps_pending != 0:
continue
attr_node: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(target)
attr_name: str = "(unknown)"
obj_name: str = "(unknown)"
if attr_node is not None:
attr_name = attr_node.attr
if attr_node.value is not None and attr_node.value.kind() == ast.ASTKind.Name:
obj_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(attr_node.value)
obj_name = obj_nm.id
err_buf: str = pool.alloc(256)
if err_buf is not None:
viperlib.snprintf(err_buf, 256,
"attribute ptr is None: %s.%s",
obj_name, attr_name)
HandlesType.fatal_error(target, err_buf)
else:
HandlesType.fatal_error(target, "attribute ptr is None")
continue
# Name 赋值: var = val
if tk == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
# 守卫:target 名缺失时跳过
if nm.id is None:
continue
# global 变量:写入模块作用域中的全局变量
if HT.is_global_name(self.Trans, nm.id) != 0:
mod_alloca: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
self.Trans.SymTab, nm.id)
if mod_alloca is None:
# fail-fast: global 变量未注册,无法赋值
HandlesType.fatal_error(
target,
f"global 变量 '{nm.id}' 未注册,无法赋值",
"NameError")
target_ty: llvmlite.LLVMType | t.CPtr = None
if mod_alloca.Ty is not None:
target_ty = mod_alloca.Ty.Pointee
if target_ty is not None:
rhs_val = HandlesExpr.coerce_to_type(builder, rhs_val, target_ty, node)
llvmlite.build_store(builder, rhs_val, mod_alloca)
continue
# nonlocal 变量:通过闭包 env 写入
if HT.is_nonlocal_name(self.Trans, nm.id) != 0:
nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr(
self.Trans, nm.id)
if nl_ptr is None:
# fail-fast: nonlocal 变量指针解析失败
HandlesType.fatal_error(
target,
f"nonlocal 变量 '{nm.id}' 指针解析失败",
"NameError")
# 从 nl_ptr 的类型推断 nonlocal 变量实际类型,
# 不再强制 i32(会截断指针/结构体/i64 导致闭包数据损坏)
nl_target_ty: llvmlite.LLVMType | t.CPtr = None
if nl_ptr.Ty is not None:
nl_target_ty = nl_ptr.Ty.Pointee
if nl_target_ty is None:
# fail-fast: nl_ptr 类型信息丢失,无法安全 store
HandlesType.fatal_error(
target,
f"nonlocal 变量 '{nm.id}' 类型信息丢失,无法写入",
"TypeError")
rhs_coerced: llvmlite.Value | t.CPtr = HandlesExpr.coerce_to_type(
builder, rhs_val, nl_target_ty, node)
llvmlite.build_store(builder, rhs_coerced, nl_ptr)
continue
# 拦截:函数内对模块级全局变量赋值但没 global 声明
# 否则静默创建局部变量遮蔽全局,全局保持 null 导致运行时崩溃
# (_mbuddy = mb 缺 global 声明即此类 bug:Int32 解引用 null 崩溃)
if HandlesVar.is_module_scope(self.Trans.SymTab) == 0:
mod_gv: llvmlite.Value | t.CPtr = HandlesVar.lookup_module_var(
self.Trans.SymTab, nm.id)
if mod_gv is not None:
fb_g: str = VLogger.fmt_buf()
msg_g: str = "global 声明缺失"
if fb_g is not None:
viperlib.snprintf(fb_g, 1024, "变量 '%s' 是模块级全局变量,函数内赋值需用 global 声明(否则创建局部变量遮蔽全局,导致全局保持 null 崩溃)", nm.id)
msg_g = fb_g
HandlesType.fatal_error(target, msg_g, "SyntaxError")
# 普通局部变量
alloca: llvmlite.Value | t.CPtr = HandlesVar.get_or_create_sym(
self.Trans.SymTab, pool, builder, nm.id, rhs_val.Ty)
if alloca is not None:
# 无注解赋值:从 RHS 表达式推断类名设置变量注解
# (联合类型 X|t.CPtr 简化为 Ptr(i8),属性访问按需过滤需要
# AnnotClassName 才能定位结构体字段)
cls_inf: str = self._infer_rhs_annot(pool, mod, asgn.value, self.Trans, rhs_val)
if cls_inf is not None:
HandlesVar.set_var_annot_class_name(
self.Trans.SymTab, nm.id, cls_inf)
# 按 alloca 类型对值进行转换(如 double → float)
store_val: llvmlite.Value | t.CPtr = rhs_val
if alloca.Ty is not None and alloca.Ty.Pointee is not None:
store_val = HandlesExpr.coerce_to_type(
builder, rhs_val, alloca.Ty.Pointee, node)
llvmlite.build_store(builder, store_val, alloca)
# lambda 表达式赋给变量:注册为闭包变量名,
# 调用分派(is_closure_name)才走闭包间接调用路径;
# 否则 i8** alloca 被 _is_func_ptr_alloca 误判为
# 函数指针,无参 call 直接跳闭包数据崩溃
if asgn.value is not None \
and asgn.value.kind() == ast.ASTKind.Lambda:
ExprCallCall.register_closure_name(nm.id)
existing: llvmlite.Value | t.CPtr = HandlesVar.lookup_current(
self.Trans.SymTab, nm.id)
if existing is None:
new_vars += 1
else:
# fail-fast: 变量存储创建失败,立即终止
HandlesType.fatal_error(
target,
f"变量 '{nm.id}' 存储创建失败",
"TypeError")
return new_vars
# ============================================================
# _infer_rhs_annot - 从 RHS 表达式推断变量注解类名
#
# 无注解赋值(如 v = Vec2(...) / v3 = v1 + v2)时,变量 AnnotClassName
# 缺失会导致后续属性访问(.x)无法"按需过滤":联合类型 X|t.CPtr 在 LLVM
# 中简化为 Ptr(i8),不携带类名,无法定位结构体字段(字段未找到 → fast-fail)。
# 此函数按 RHS 结构推断类名:
# Call → 类实例化(func 为已注册结构体名才采用,避免普通函数误标);
# func 为 Attribute 时是方法调用(a.cross()),obj 类名 +
# 方法存在 + rhs_val 为指针类型(联合对象)三条件判定
# Name → 源变量的 AnnotClassName
# BinOp/UnaryOp → lhs 类名 + 该类存在对应 dunder 方法(运算符重载返回同类对象)
# Attribute → 字段注解类名(委托 Generator 单例 _resolve_attr_field_class)
# 仅当目标为已注册结构体时采用,与"按需过滤,找不到 fast-fail"原则一致。
# ============================================================
def _infer_rhs_annot(self, pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
node: ast.AST | t.CPtr,
trans: HT.Translator | t.CPtr,
rhs_val: llvmlite.Value | t.CPtr = None) -> str:
"""从 RHS 表达式推断类名,无法推断返回 None"""
if node is None or trans is None:
return None
k: int = node.kind()
# Call: 类实例化 / 方法调用
if k == ast.ASTKind.Call:
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(node)
if cl is None or cl.func is None:
return None
if cl.func.kind() == ast.ASTKind.Name:
# 类实例化:func 为已注册结构体名才采用
cand: str = ((ast.Name | t.CPtr)(cl.func)).id
if cand is None:
return None
se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(cand)
if se is not None:
return cand
return None
if cl.func.kind() == ast.ASTKind.Attribute:
# 方法调用 a.cross(b):从 vpi 返回注解缓存精确解析返回类名
# (方法可返回非同类对象,如 Transform.world_position → 'Vec3',
# 启发式取 obj 类名会 GEP 错字段)。vpi 未命中时返回 None,
# 由后续属性访问 fast-fail 暴露 vpi 缺失根因(不静默回退)。
ca: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(cl.func)
if ca is None or ca.attr is None or ca.value is None:
return None
obj_cls: str = self._infer_rhs_annot(pool, mod, ca.value, trans)
if obj_cls is None:
# 模块级函数调用(requests.get):ca.value 是已导入模块名
# 而非对象变量(模块名 lookup_var_entry 返回 None → 上面
# 对象类名推断失败)。从该模块 vpi 的返回注解缓存解析返回
# 类名(键 {sha1}.{func},cls_name=None 即模块级函数,与
# CallGenMixin 跨模块返回类型解析一致)。
# WebTest resp = requests.get(...) 根因:无注解赋值变量
# AnnotClassName 推断失败(annot=None)→ 属性访问按需过滤
# (依赖 AnnotClassName)失效 → "属性访问失败: .status_code"。
if ca.value.kind() == ast.ASTKind.Name:
mod_nm_rhs: ast.Name | t.CPtr = (ast.Name | t.CPtr)(ca.value)
if mod_nm_rhs.id is not None:
mod_sha1_rhs: str = ExprCallBase._lookup_module_sha1(
mod_nm_rhs.id)
if mod_sha1_rhs is not None:
import lib.StubGen.VpiReader as VpiReader
temp_dir_rhs: str = None
import lib.core.Gen.Generator as Generator
g_rhs: Generator.Generator | t.CPtr = (
Generator.Generator | t.CPtr)(
t.CVoid(HandlesExpr._g_gen, t.CPtr))
if g_rhs is not None and g_rhs.TempDir is not None:
temp_dir_rhs = g_rhs.TempDir
if temp_dir_rhs is not None:
VpiReader._ensure_vpi_ret_annot_loaded(
mod_sha1_rhs, temp_dir_rhs)
annot_rhs: str = VpiReader._lookup_vpi_ret_annot(
mod_sha1_rhs, None, ca.attr)
if annot_rhs is not None:
ret_cls_rhs: str = self._extract_annot_class_name(
pool, annot_rhs)
if ret_cls_rhs is not None:
return ret_cls_rhs
return None
if self._cls_has_dunder(pool, mod, obj_cls, ca.attr) == 0:
return None
# 方法定义所在模块 SHA1(优先 struct entry,回退当前模块 sha1)
cls_sha1: str = HandlesStruct.get_struct_sha1(obj_cls)
if cls_sha1 is None and trans.ModuleSha1 is not None:
cls_sha1 = trans.ModuleSha1
ret_cls: str = None
if cls_sha1 is not None:
import lib.StubGen.VpiReader as VpiReader
temp_dir: str = None
import lib.core.Gen.Generator as Generator
g2: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(
t.CVoid(HandlesExpr._g_gen, t.CPtr))
if g2 is not None and g2.TempDir is not None:
temp_dir = g2.TempDir
if temp_dir is not None:
VpiReader._ensure_vpi_ret_annot_loaded(cls_sha1, temp_dir)
annot_ret: str = VpiReader._lookup_vpi_ret_annot(
cls_sha1, obj_cls, ca.attr)
if annot_ret is not None:
ret_cls = self._extract_annot_class_name(pool, annot_ret)
return ret_cls
return None
# Name: 源变量注解
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
if nm is None or nm.id is None:
return None
ve: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
trans.SymTab, nm.id)
if ve is None:
return None
return ve.AnnotClassName
# BinOp/UnaryOp: 运算符重载返回同类对象
if k == ast.ASTKind.BinOp:
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
if bop is None or bop.left is None:
return None
dunder: str = self._op_to_dunder(bop.op)
if dunder is None:
return None
lhs_cls: str = self._infer_rhs_annot(pool, mod, bop.left, trans)
if lhs_cls is None or self._cls_has_dunder(pool, mod, lhs_cls, dunder) == 0:
return None
return lhs_cls
if k == ast.ASTKind.UnaryOp:
uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node)
if uop is None or uop.operand is None:
return None
dunder: str = self._op_to_dunder(uop.op)
if dunder is None:
return None
opr_cls: str = self._infer_rhs_annot(pool, mod, uop.operand, trans)
if opr_cls is None or self._cls_has_dunder(pool, mod, opr_cls, dunder) == 0:
return None
return opr_cls
# Attribute: 字段注解类名(属性链递归,如 p = r.origin)
if k == ast.ASTKind.Attribute:
import lib.core.Gen.Generator as Generator
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(
t.CVoid(HandlesExpr._g_gen, t.CPtr))
# ============================================================
# translate_assign - Assign 语句翻译(委托到 gen.translate_assign)
# ============================================================
def translate_assign(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译赋值语句,返回新增变量数(委托到 gen.translate_assign)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._resolve_attr_field_class(pool, trans, node)
return None
return None
# ============================================================
# _extract_annot_class_name - 从返回注解文本提取结构体类名
#
# vpi 返回注解文本(如 "'Vec3' | CPtr")按 '|' 分段,每段去除
# 空格/引号后查结构体注册表:命中即类名(内置类型 str/int/
# CFloat64T/t.CPtr 等均不注册 struct,天然过滤)。"A | B" 联合
# 多候选时取首个命中段。
# ============================================================
def _extract_annot_class_name(self, pool: memhub.MemBuddy | t.CPtr,
annot: str) -> str:
"""从返回注解文本提取已注册结构体类名,无命中返回 None"""
if pool is None or annot is None:
return None
alen: t.CSizeT = string.strlen(annot)
if alen == 0:
return None
seg: str = pool.alloc(256)
if seg is None:
return None
start: t.CSizeT = 0
i: t.CSizeT
for i in range(alen):
if annot[i] == '|':
seglen: t.CSizeT = i - start
# 段 [start, i):去除首尾空格与引号后查注册表
s: t.CSizeT = start
e: t.CSizeT = i
while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'):
s += 1
while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'):
e -= 1
seglen = e - s
if seglen > 0 and seglen < 256:
string.strncpy(seg, annot + s, seglen)
seg[seglen] = '\0'
se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(seg)
if se is not None:
return seg
start = i + 1
# 最后一段(无 '|' 后缀)
s: t.CSizeT = start
e: t.CSizeT = alen
while s < e and (annot[s] == ' ' or annot[s] == '\'' or annot[s] == '"'):
s += 1
while e > s and (annot[e - 1] == ' ' or annot[e - 1] == '\'' or annot[e - 1] == '"'):
e -= 1
seglen: t.CSizeT = e - s
if seglen > 0 and seglen < 256:
string.strncpy(seg, annot + s, seglen)
seg[seglen] = '\0'
se: HandlesStruct.StructEntry | t.CPtr = HandlesStruct.find_struct(seg)
if se is not None:
return seg
return None
# ============================================================
# _op_to_dunder - 运算符 → dunder 方法名(本地副本,避免跨 Mixin 调用)
# ============================================================
def _op_to_dunder(self, op: int) -> str:
"""BinOp/UnaryOp 运算符 → dunder 方法名,无映射返回 None"""
if op == ast.OpKind.Add: return "__add__"
if op == ast.OpKind.Sub: return "__sub__"
if op == ast.OpKind.Mult: return "__mul__"
if op == ast.OpKind.Div: return "__truediv__"
if op == ast.OpKind.FloorDiv: return "__floordiv__"
if op == ast.OpKind.Mod: return "__mod__"
if op == ast.OpKind.Pow: return "__pow__"
if op == ast.OpKind.BitAnd: return "__and__"
if op == ast.OpKind.BitOr: return "__or__"
if op == ast.OpKind.BitXor: return "__xor__"
if op == ast.OpKind.LShift: return "__lshift__"
if op == ast.OpKind.RShift: return "__rshift__"
if op == ast.OpKind.USub: return "__neg__"
if op == ast.OpKind.UAdd: return "__pos__"
if op == ast.OpKind.Invert: return "__invert__"
return None
# ============================================================
# _cls_has_dunder - 检查类(含继承链)是否存在 dunder 方法
#
# 与 ExprGenMixin.try_operator_overload 的查找一致:当前模块内定义
# 或跨模块类有 SHA1(stub 中声明)即视为存在。仅在确实存在时
# 才采用运算符重载推断的类名,避免把原生运算误标为类类型。
# ============================================================
def _cls_has_dunder(self, pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
class_name: str, dunder: str) -> int:
"""类及其 MRO 祖先链中是否存在 dunder 方法,存在返回 1"""
if class_name is None or dunder is None or mod is None:
return g.translate_assign(trans, node)
return 0
lookup_name: str = pool.alloc(128)
if lookup_name is None:
return 0
viperlib.snprintf(lookup_name, 128, "%s.%s", class_name, dunder)
if ExprCallBase.find_func_in_module(mod, lookup_name) is not None:
return 1
# 继承链祖先查找
mro_ptr: t.CSizeT | t.CPtr = HandlesStruct.get_mro_chain(pool, class_name)
mi: int = 1
while mro_ptr is not None and mro_ptr[mi] != 0:
anc: str = (str | t.CPtr)(t.CVoid(mro_ptr[mi], t.CPtr))
if anc is not None:
anc_lookup: str = pool.alloc(128)
if anc_lookup is not None:
viperlib.snprintf(anc_lookup, 128, "%s.%s", anc, dunder)
if ExprCallBase.find_func_in_module(mod, anc_lookup) is not None:
return 1
mi += 1
# 跨模块:类有 SHA1(stub 中声明该方法)视为存在
if HandlesStruct.get_struct_sha1(class_name) is not None:
return 1
return 0
# ============================================================
# NewAssignHandle - 工厂函数:分配并初始化 AssignHandle
# ============================================================
def NewAssignHandle(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> AssignHandle | t.CPtr:
h: AssignHandle | t.CPtr = pool.alloc(AssignHandle.__sizeof__())
if h is None:
return None
string.memset(h, 0, AssignHandle.__sizeof__())
h.Trans = trans
return h
+16 -270
View File
@@ -1,21 +1,21 @@
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import stdio
import string
import viperlib
import lib.core.VLogger as VLogger
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Gen.Generator as Generator
# ============================================================
# HandlesAugAssign - 增强赋值语句处理(迁移完成,保留跨 Mixin 委托壳)
#
# P6 机械化迁移:AugAssignHandle 类 → AssignGenMixin.translate_augassign。
# 分派中枢(StmtGenMixin)经本壳跨链调用(Viper @t.NoVTable 静态绑定下
# 跨 Mixin self. 调用 mangle 失败,须经模块级委托壳桥回 gen 单例)。
# 迁移收尾(编译器缺陷修复)后统一删除。
# ============================================================
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
# ============================================================
@@ -23,266 +23,12 @@ _g_gen: Generator.Generator | t.CPtr = None
# ============================================================
# HandlesAugAssign - 增强赋值语句处理(Mixin 继承模式)
#
# 处理 += -= *= /= %= &= |= ^= <<= >>=
# 流程: load target → apply binop → store result
#
# 支持 local/global/nonlocal 三种变量作用域
# translate_augassign - 增强赋值翻译(委托到 gen.translate_augassign)
# ============================================================
@t.NoVTable
class AugAssignHandle(HandlesBase.Mixin):
"""增强赋值处理器 (+=, -=, *=, etc.):继承 Mixin 获得 Trans 回指针"""
def __init__(self, trans: HT.Translator | t.CPtr):
self.Trans = trans
# ============================================================
# Handle - 处理 AugAssign 语句,返回新增变量数(始终为 0)
# ============================================================
def Handle(self, node: ast.AST | t.CPtr) -> int:
"""翻译增强赋值语句 (x += 1, y -= 2, etc.)"""
if node is None:
return 0
aug: ast.AugAssign | t.CPtr = (ast.AugAssign | t.CPtr)(node)
if aug is None:
return 0
target: ast.AST | t.CPtr = aug.target
if target is None:
return 0
tk: int = target.kind()
# Attribute 目标: self.field += 1
# 流程: get_attribute_ptr → load → binop → store
if tk == ast.ASTKind.Attribute:
pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder
mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module
# 1. 获取字段指针
field_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_attribute_ptr(
builder, pool, mod, target, self.Trans)
if field_ptr is None:
# fail-fast: 属性指针解析失败
HandlesType.fatal_error(target, "attribute ptr is None", "TypeError")
# 2. 确定字段类型并加载当前值
target_ty: llvmlite.LLVMType | t.CPtr = None
if field_ptr.Ty is not None and field_ptr.Ty.Pointee is not None:
target_ty = field_ptr.Ty.Pointee
if target_ty is None:
# fail-fast: 字段类型信息缺失,禁止兜底 i32
HandlesType.fatal_error(target, "字段类型信息缺失", "TypeError")
cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, target_ty, field_ptr)
if cur_val is None:
# fail-fast: 属性当前值加载失败
HandlesType.fatal_error(target, "无法加载 attribute 当前值", "TypeError")
# 3. 翻译 RHS 值
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, aug.value, None, 0, self.Trans)
if rhs_val is None:
# fail-fast: RHS 翻译失败
HandlesType.fatal_error(target, "rhs 翻译失败", "TypeError")
# 4. 应用二元运算
result: llvmlite.Value | t.CPtr = _apply_aug_op(
pool, builder, aug.op, cur_val, rhs_val, node, self.Trans, target)
if result is None:
# fail-fast: attribute 二元运算失败
HandlesType.fatal_error(target, f"attribute 二元运算失败 op={aug.op}", "TypeError")
# 5. 类型对齐并存储
result = HandlesExpr.coerce_to_type(builder, result, target_ty, node)
if result is None:
# fail-fast: 类型对齐失败
HandlesType.fatal_error(target, "类型对齐失败", "TypeError")
llvmlite.build_store(builder, result, field_ptr)
return 0
# Subscript 目标: self.state[i] += x / arr[i] += x
# 流程: get_subscript_ptr → load → binop → store
if tk == ast.ASTKind.Subscript:
pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder
mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module
# 1. 获取元素指针
elem_ptr: llvmlite.Value | t.CPtr = HandlesExpr.get_subscript_ptr(
builder, pool, mod, target, self.Trans)
if elem_ptr is None:
# fail-fast: 下标指针解析失败
HandlesType.fatal_error(target, "subscript ptr is None", "TypeError")
# 2. 确定元素类型并加载当前值
target_ty: llvmlite.LLVMType | t.CPtr = None
if elem_ptr.Ty is not None and elem_ptr.Ty.Pointee is not None:
target_ty = elem_ptr.Ty.Pointee
if target_ty is None:
# fail-fast: 元素类型信息缺失,禁止兜底 i32
HandlesType.fatal_error(target, "元素类型信息缺失", "TypeError")
cur_val: llvmlite.Value | t.CPtr = llvmlite.build_load(
builder, target_ty, elem_ptr)
if cur_val is None:
# fail-fast: 元素当前值加载失败
HandlesType.fatal_error(target, "无法加载 subscript 元素当前值", "TypeError")
# 3. 翻译 RHS 值
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, aug.value, None, 0, self.Trans)
if rhs_val is None:
# fail-fast: RHS 翻译失败
HandlesType.fatal_error(target, "rhs 翻译失败", "TypeError")
# 4. 应用二元运算
result: llvmlite.Value | t.CPtr = _apply_aug_op(
pool, builder, aug.op, cur_val, rhs_val, node, self.Trans, target)
if result is None:
# fail-fast: subscript 二元运算失败
HandlesType.fatal_error(target, f"subscript 二元运算失败 op={aug.op}", "TypeError")
# 5. 类型对齐并存储
result = HandlesExpr.coerce_to_type(builder, result, target_ty, node)
if result is None:
# fail-fast: 类型对齐失败
HandlesType.fatal_error(target, "类型对齐失败", "TypeError")
llvmlite.build_store(builder, result, elem_ptr)
return 0
if tk != ast.ASTKind.Name:
# fail-fast: 不支持的 AugAssign 目标类型
HandlesType.fatal_error(
target, "AugAssign 目标类型不支持,仅支持 Name/Attribute/Subscript", "TypeError")
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(target)
if nm is None or nm.id is None:
return 0
pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder
mod: llvmlite.LLVMModule | t.CPtr = self.Trans.Module
# 1. 确定变量作用域类型: 0=local, 1=global, 2=nonlocal
scope_type: int = 0
if HT.is_global_name(self.Trans, nm.id) != 0:
scope_type = 1
elif HT.is_nonlocal_name(self.Trans, nm.id) != 0:
scope_type = 2
# 2. 加载当前值
cur_val: llvmlite.Value | t.CPtr = None
target_alloca: llvmlite.Value | t.CPtr = None
target_ty: llvmlite.LLVMType | t.CPtr = None
if scope_type == 1:
# global 变量
target_alloca = HandlesVar.lookup_module_var(
self.Trans.SymTab, nm.id)
if target_alloca is not None:
if target_alloca.Ty is None:
# fail-fast: 变量类型信息缺失,禁止兜底 i32
HandlesType.fatal_error(target, "变量类型信息缺失", "TypeError")
target_ty = target_alloca.Ty.Pointee
cur_val = llvmlite.build_load(builder, target_ty, target_alloca)
elif scope_type == 2:
# nonlocal 变量(通过闭包 env)
cur_val = HandlesNonlocal.load_nonlocal_var(self.Trans, nm.id)
if cur_val is not None:
target_ty = cur_val.Ty
else:
# 普通局部变量
target_alloca = HandlesVar.lookup_var(self.Trans.SymTab, nm.id)
if target_alloca is not None:
if target_alloca.Ty is None:
# fail-fast: 变量类型信息缺失,禁止兜底 i32
HandlesType.fatal_error(target, "变量类型信息缺失", "TypeError")
target_ty = target_alloca.Ty.Pointee
cur_val = llvmlite.build_load(builder, target_ty, target_alloca)
if cur_val is None:
# fail-fast: 目标变量当前值加载失败
HandlesType.fatal_error(
target,
f"无法加载目标变量 '{nm.id}' 的当前值",
"TypeError")
# 3. 翻译 RHS 值
rhs_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, mod, aug.value, None, 0, self.Trans)
if rhs_val is None:
# fail-fast: RHS 翻译失败
HandlesType.fatal_error(target, "rhs 翻译失败", "TypeError")
# 4. 类型对齐 + 应用二元运算
# 注意: AugAssign 不走运算符重载(语义上需要 __iadd__ 而非 __add__)
result: llvmlite.Value | t.CPtr = _apply_aug_op(
pool, builder, aug.op, cur_val, rhs_val, node, self.Trans, target)
if result is None:
# fail-fast: 二元运算失败
HandlesType.fatal_error(
target,
f"对变量 '{nm.id}' 应用二元运算失败 op={aug.op}",
"TypeError")
# 5. 存储结果
result = HandlesExpr.coerce_to_type(builder, result, target_ty, node)
if result is None:
# fail-fast: 类型对齐失败
HandlesType.fatal_error(target, "类型对齐失败", "TypeError")
if scope_type == 1:
# global 变量
if target_alloca is not None:
llvmlite.build_store(builder, result, target_alloca)
elif scope_type == 2:
# nonlocal 变量
nl_ptr: llvmlite.Value | t.CPtr = HandlesNonlocal.get_nonlocal_var_ptr(
self.Trans, nm.id)
if nl_ptr is not None:
llvmlite.build_store(builder, result, nl_ptr)
else:
# 普通局部变量
if target_alloca is not None:
llvmlite.build_store(builder, result, target_alloca)
return 0
# ============================================================
# _apply_aug_op - 应用增强赋值的二元运算
#
# 支持浮点运算、指针算术: ptr += int / ptr -= int
# 整数运算自动类型提升
# ============================================================
def _apply_aug_op(pool: memhub.MemBuddy | t.CPtr,
builder: llvmlite.IRBuilder | t.CPtr,
op: int,
lhs: llvmlite.Value | t.CPtr,
rhs: llvmlite.Value | t.CPtr,
node: ast.AST | t.CPtr = None,
trans: HT.Translator | t.CPtr = None,
lhs_node: ast.AST | t.CPtr = None) -> llvmlite.Value | t.CPtr:
"""应用增强赋值的二元运算(浮点 + 指针算术 + 整数运算,委托到 gen._apply_aug_op)"""
def translate_augassign(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译增强赋值语句,返回新增变量数(委托到 gen.translate_augassign)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._apply_aug_op(pool, builder, op, lhs, rhs, node, trans, lhs_node)
return None
# ============================================================
# NewAugAssignHandle - 工厂函数
# ============================================================
def NewAugAssignHandle(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> AugAssignHandle | t.CPtr:
h: AugAssignHandle | t.CPtr = pool.alloc(AugAssignHandle.__sizeof__())
if h is None:
return None
string.memset(h, 0, AugAssignHandle.__sizeof__())
h.Trans = trans
return h
return g.translate_augassign(trans, node)
return 0
+19 -398
View File
@@ -1,58 +1,33 @@
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdio
import viperlib
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.ForHandleBase as ForHandleBase
import lib.core.Handles.ForHandleIter as ForHandleIter
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesBody as HandlesBody
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.Handles.ExprCallBase as ExprCallBase
import lib.core.Gen.Generator as Generator
# ============================================================
# HandlesFor - for 循环语句处理(P6 对象化后的委托层)
# HandlesFor - for 循环语句处理(迁移完成,保留跨 Mixin 委托壳)
#
# NewForHandle 工厂已迁移为 lib.core.Gen.StmtGenMixin 的方法
# (ForHandle 类保留:trans.ForH 的类型,由 HandlesTranslator.
# _init_state 经 NewForHandle 委托创建)。
#
# 支持 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:
# P6 机械化迁移:ForHandle/ForHandleBase/ForHandleIter 全部方法 →
# StmtGenCifMixin.translate_for 及辅助方法(_handle_ptr_iter/
# _handle_array_iter/_handle_list_literal_iter/_handle_list_iter/
# _handle_dict_iter/_handle_oop_iter/_handle_enumerate_iter/
# _handle_zip_iter/_extract_tuple_names/_seq_kind/_build_seq_loop)。
# SEQ_KIND_* 常量保留:StmtGenCifMixin._seq_kind/_build_seq_loop 经
# HandlesFor.SEQ_KIND_* 访问。
# 分派中枢(StmtGenMixin)经本壳跨链调用(Viper @t.NoVTable 静态绑定下
# 跨 Mixin self. 调用 mangle 失败,须经模块级委托壳桥回 gen 单例)。
# 迁移收尾(编译器缺陷修复)后统一删除。
# ============================================================
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式)
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
#
# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。
# 委托函数用本地 _g_gen(cast 成 Generator 类型)调
# StmtGenMixin 方法,避免函数体 import 包模块与类/模块名歧义。
# StmtGenCifMixin 方法,避免函数体 import 包模块与类/模块名歧义。
# ============================================================
_g_gen: Generator.Generator | t.CPtr = None
@@ -68,367 +43,13 @@ SEQ_KIND_STR: t.CDefine = 2
SEQ_KIND_LIST: t.CDefine = 3
@t.NoVTable
class ForHandle(ForHandleBase.ForHandleBase, ForHandleIter.ForHandleIter):
"""for 循环语句处理器:继承 Mixin 获得 Trans 回指针"""
# ============================================================
# Handle - 处理 for 语句,返回新增变量数
# ============================================================
def Handle(self, node: ast.AST | t.CPtr) -> int:
"""翻译 for i in range(...) 循环语句"""
if node is None:
return 0
trans: HT.Translator | t.CPtr = self.Trans
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
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 = HandlesExpr.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)
HandlesType.fatal_error(iter_node, err_msg)
HandlesType.fatal_error(iter_node, "仅支持 range()/enumerate()/zip() 或指针迭代")
# 非范围迭代:走指针/数组/列表字面量/容器/多变量迭代路径
if is_range_iter == 0:
# 列表字面量:按元素顺序迭代(for x in [1, 2, 3])
if iter_node.kind() == ast.ASTKind.List:
return self._handle_list_literal_iter(for_node, var_name, iter_node)
# enumerate(x):for i, v in enumerate(x)(多变量迭代)
if iter_node.kind() == ast.ASTKind.Call:
call_mi: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node)
fn_mi: str = HandlesExpr.get_func_name(call_mi.func)
if fn_mi is not None and string.strcmp(fn_mi, "enumerate") == 0:
if tk != ast.ASTKind.Tuple:
HandlesType.fatal_error(iter_node, "enumerate 迭代需要两个循环变量 (for i, v in enumerate(x))")
tup_ie: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(target)
t1_buf_ie: bytes = pool.alloc(128)
t2_buf_ie: bytes = pool.alloc(128)
if t1_buf_ie is None or t2_buf_ie is None:
return 0
t1_buf_ie[0] = '\0'
t2_buf_ie[0] = '\0'
if self._extract_tuple_names(tup_ie, t1_buf_ie, t2_buf_ie) == 0:
HandlesType.fatal_error(iter_node, "enumerate 迭代变量必须是简单名称")
return self._handle_enumerate_iter(for_node, t1_buf_ie, t2_buf_ie, call_mi)
if fn_mi is not None and string.strcmp(fn_mi, "zip") == 0:
if tk != ast.ASTKind.Tuple:
HandlesType.fatal_error(iter_node, "zip 迭代需要两个循环变量 (for a, b in zip(...))")
tup_iz: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(target)
t1_buf_iz: bytes = pool.alloc(128)
t2_buf_iz: bytes = pool.alloc(128)
if t1_buf_iz is None or t2_buf_iz is None:
return 0
t1_buf_iz[0] = '\0'
t2_buf_iz[0] = '\0'
if self._extract_tuple_names(tup_iz, t1_buf_iz, t2_buf_iz) == 0:
HandlesType.fatal_error(iter_node, "zip 迭代变量必须是简单名称")
return self._handle_zip_iter(for_node, t1_buf_iz, t2_buf_iz, call_mi)
# list[T] 容器变量:按 __count__ 动态长度迭代
if iter_node.kind() == ast.ASTKind.Name and trans is not None:
nm_lst: ast.Name | t.CPtr = (ast.Name | t.CPtr)(iter_node)
if nm_lst.id is not None:
ve_lst: HandlesVar.VarEntry | t.CPtr = HandlesVar.lookup_var_entry(
trans.SymTab, nm_lst.id)
if ve_lst is not None and ve_lst.AnnotClassName is not None:
# dict 容器变量:按 __count__/__keys__ 布局迭代(__iter__ 协议内联)
if string.strstr(ve_lst.AnnotClassName, "dict") is not None:
lst_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, iter_node,
trans._funcs, trans._func_count, trans)
if lst_val is not None and lst_val.Ty is not None \
and HandlesExpr.is_ptr_type(lst_val.Ty) != 0:
return self._handle_dict_iter(for_node, var_name, lst_val)
if string.strstr(ve_lst.AnnotClassName, "list") is not None:
lst_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
builder, pool, trans.Module, iter_node,
trans._funcs, trans._func_count, trans)
if lst_val is not None and lst_val.Ty is not None \
and HandlesExpr.is_ptr_type(lst_val.Ty) != 0:
return self._handle_list_iter(for_node, var_name, lst_val)
# OOP iter 协议:迭代源是类对象且类有 __iter__/__next__ 方法 →
# 走 __iter__/__next__ 调用迭代(对齐 TPC HandlesFor.py L142-166
# _HandleForIterLlvm)。dict/list 是内置泛型容器已在上方内联处理。
ov_val: llvmlite.Value | t.CPtr = HandlesExpr.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 HandlesExpr.is_ptr_type(ov_val.Ty) != 0:
ov_st: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type_from_value(
ov_val)
if ov_st is not None:
ov_cn: str = HandlesStruct.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 = ExprCallBase.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 = ExprCallBase.find_func_in_module(
trans.Module, on_lookup)
if on_fn is not None:
return self._handle_oop_iter(
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:
HandlesType.fatal_error(
iter_node,
"for 迭代不支持该常量(仅支持字符串、数组、列表字面量、range())")
elif ik == ast.ASTKind.Dict or ik == ast.ASTKind.Set or ik == ast.ASTKind.Tuple \
or ik == ast.ASTKind.SetComp or ik == ast.ASTKind.DictComp:
HandlesType.fatal_error(
iter_node,
"for 迭代不支持字典/集合/元组字面量,请使用 range()、t.CArray 数组或列表字面量")
return self._handle_ptr_iter(for_node, var_name)
call: ast.Call | t.CPtr = (ast.Call | t.CPtr)(iter_node)
# 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 无参数,立即终止
HandlesType.fatal_error(call, "range 需要至少一个参数", "SyntaxError")
elif arg_count == 1:
stop_val = HandlesExpr.translate_value(
builder, pool, trans.Module, args.get(0),
trans._funcs, trans._func_count, trans)
if stop_val is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(args.get(0), "range 参数翻译失败", "TypeError")
elif arg_count >= 2:
start_val = HandlesExpr.translate_value(
builder, pool, trans.Module, args.get(0),
trans._funcs, trans._func_count, trans)
if start_val is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(args.get(0), "range 参数翻译失败", "TypeError")
stop_val = HandlesExpr.translate_value(
builder, pool, trans.Module, args.get(1),
trans._funcs, trans._func_count, trans)
if stop_val is None:
# fail-fast: range 参数翻译失败
HandlesType.fatal_error(args.get(1), "range 参数翻译失败", "TypeError")
if arg_count >= 3:
step_val = HandlesExpr.translate_value(
builder, pool, trans.Module, args.get(2),
trans._funcs, trans._func_count, trans)
if step_val is None:
# fail-fast: range 参数翻译失败
HandlesType.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 = HandlesVar.lookup_var(
trans.SymTab, var_name)
new_vars: int = 0
if var_alloca is None:
var_alloca = HandlesVar._alloca_at_entry(builder, i32_ty)
if HandlesVar.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 = HandlesExpr.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 = HandlesExpr.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 = HandlesExpr.get_llvm_type_bits(stop_val.Ty)
cur_bits: int = HandlesExpr.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:
HandlesBody.translate_stmt(trans, stmt)
# 恢复旧循环上下文
trans._break_bb = old_break
trans._continue_bb = old_continue
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, incr_bb)
# 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 = HandlesExpr.get_llvm_type_bits(step_val.Ty)
cur2_bits: int = HandlesExpr.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
# ============================================================
# NewForHandle - 工厂函数(委托到 gen.NewForHandle)
# translate_for - for 循环语句翻译(委托到 gen.translate_for)
# ============================================================
def NewForHandle(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> ForHandle | t.CPtr:
"""创建 ForHandle 实例(委托到 gen.NewForHandle)"""
def translate_for(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译 for 循环语句(委托到 gen.translate_for)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.NewForHandle(pool, trans)
return None
return g.translate_for(trans, node)
return 0
+20 -323
View File
@@ -1,345 +1,42 @@
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdio
import viperlib
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesBody as HandlesBody
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Handles.HandlesImports as HandlesImports
import lib.Projectrans.Config as Config
import lib.core.Gen.Generator as Generator
# ============================================================
# HandlesIf - if/elif/else 语句处理(P6 对象化后的委托层)
# HandlesIf - if/elif/else 语句处理(迁移完成,保留跨 Mixin 委托壳)
#
# 编译期 CIf 求值的模块级函数(_is_cif_attr/_is_cif_call/
# _get_platform_macro_value/_cif_name_value/_cif_attr_value/
# _cif_eval_node/_evaluate_cif_test)已迁移为 lib.core.Gen.
# StmtGenMixin 的方法(_g_cif_eval_ok → gen 实例字段 CifEvalOk),
# 本模块保留同名模块级函数作为"一行委托";模块级 _g_cif_eval_ok
# 保留为镜像,委托后同步 gen.CifEvalOk(IfHandle.Handle 直接读它)。
#
# IfHandle 类(trans.IfH 的类型)保留:由 HandlesTranslator.
# _init_state 通过 NewIfHandle 工厂创建,Handle 方法内部经模块级
# 委托函数访问 gen。
# P6 机械化迁移:IfHandle 类 → StmtGenCifMixin.translate_if。
# CIf 编译期求值(_is_cif_attr/_is_cif_call/_get_platform_macro_value/
# _cif_name_value/_cif_attr_value/_cif_eval_node/_evaluate_cif_test 及
# 模块级 _g_cif_eval_ok)已迁移为 StmtGenCifMixin 的方法/字段
# (CifEvalOk)。
# 分派中枢(StmtGenMixin)经本壳跨链调用(Viper @t.NoVTable 静态绑定下
# 跨 Mixin self. 调用 mangle 失败,须经模块级委托壳桥回 gen 单例)。
# 迁移收尾(编译器缺陷修复)后统一删除。
# ============================================================
# 编译期宏条件: if c.CIf(...) / c.CIfdef(...) / c.CIfndef(...)
#
# 对齐 TPC HandlesIf.py:编译期求值命中分支并剪枝(不发射运行时 IR)。
# c.CIf(expr) → 常量表达式求值(CDefine/平台宏/算术/比较/逻辑)
# c.CIfdef(NAME) → NAME 已定义?(本地 CDefine / 跨模块 CDefine / 平台宏)
# c.CIfndef(NAME) → NAME 未定义? ← 未定义名特判:返回"未定义"而非报错
#
# 求值失败(如运行时变量 val == 1)→ 回退运行时翻译
# (c.CIf 由 HandlesExprCall.translate_call 特判翻译成运行时真值,
# c.CIfdef/c.CIfndef 运行时恒真,对齐 TPC HandlesExprCall.py L2434-2446)。
_g_cif_eval_ok: int = 0
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式)
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
#
# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。
# 委托函数用本地 _g_gen(cast 成 Generator 类型)调
# StmtGenCifMixin 方法,避免函数体 import 包模块与类/模块名歧义。
# ============================================================
_g_gen: Generator.Generator | t.CPtr = None
def _is_cif_attr(attr: str) -> int:
"""检查方法名是否为 CIf 系(CIf/CIfdef/CIfndef)(委托到 gen._is_cif_attr)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._is_cif_attr(attr)
return 0
def _is_cif_call(node: ast.AST | t.CPtr) -> int:
"""检查 test 是否为 c.CIf(...)/c.CIfdef(...)/c.CIfndef(...)(或裸 CIf 系)调用(委托到 gen._is_cif_call)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._is_cif_call(node)
return 0
def _get_platform_macro_value(name: str) -> int:
"""平台内置宏值(从目标三元组推导,对齐 TPC HandlesIf._get_platform_macros)。
命中置 _g_cif_eval_ok=1;未命中置 0 返回 0(委托到 gen._get_platform_macro_value)。
"""
global _g_cif_eval_ok
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
v: int = g._get_platform_macro_value(name)
_g_cif_eval_ok = g.CifEvalOk
return v
return 0
def _cif_name_value(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr,
name: str) -> int:
"""查宏名值: 本地 CDefine → 跨模块 CDefine → 平台宏。
命中置 _g_cif_eval_ok=1(值 0 也算命中,如 DISABLED=0);未命中置 0(委托到 gen._cif_name_value)。
"""
global _g_cif_eval_ok
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
v: int = g._cif_name_value(pool, trans, name)
_g_cif_eval_ok = g.CifEvalOk
return v
return 0
def _cif_attr_value(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr,
at: ast.Attribute | t.CPtr) -> int:
"""Attribute 宏值: platmacro.IS_WINDOWS → 本地 CDefine(attr) → 跨模块 CDefine。
命中置 _g_cif_eval_ok=1;未命中置 0(委托到 gen._cif_attr_value)。
"""
global _g_cif_eval_ok
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
v: int = g._cif_attr_value(pool, trans, at)
_g_cif_eval_ok = g.CifEvalOk
return v
return 0
def _cif_eval_node(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr,
# ============================================================
# translate_if - if/elif/else 语句翻译(委托到 gen.translate_if)
# ============================================================
def translate_if(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 - + ~)。
成功置 _g_cif_eval_ok=1;失败(含运行时变量)置 0 返回 0(委托到 gen._cif_eval_node)。
"""
global _g_cif_eval_ok
"""翻译 if/elif/else 语句(委托到 gen.translate_if)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
v: int = g._cif_eval_node(pool, trans, node)
_g_cif_eval_ok = g.CifEvalOk
return v
return g.translate_if(trans, node)
return 0
def _evaluate_cif_test(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr,
test: ast.AST | t.CPtr) -> int:
"""求值 CIf 调用(test 必须是 c.CIf 系调用)。
成功: 置 _g_cif_eval_ok=1,返回条件值(0/1)
失败(运行时变量/未知结构): 置 _g_cif_eval_ok=0,返回 0(委托到 gen._evaluate_cif_test)。
"""
global _g_cif_eval_ok
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
v: int = g._evaluate_cif_test(pool, trans, test)
_g_cif_eval_ok = g.CifEvalOk
return v
return 0
# ============================================================
# HandlesIf - if/elif/else 语句处理(Mixin 继承模式)
#
# 翻译 if 语句为 LLVM IR 控制流:
# br i1 %cond, label %then, label %else
# then:
# ... body ...
# br label %end
# else:
# ... orelse ...
# br label %end
# end:
# ============================================================
@t.NoVTable
class IfHandle(HandlesBase.Mixin):
"""if/elif/else 语句处理器:继承 Mixin 获得 Trans 回指针"""
def __init__(self, trans: HT.Translator | t.CPtr):
self.Trans = trans
# ============================================================
# Handle - 处理 if 语句,返回新增变量数
# ============================================================
def Handle(self, node: ast.AST | t.CPtr) -> int:
"""翻译 if/elif/else 语句"""
if node is None:
return 0
trans: HT.Translator | t.CPtr = self.Trans
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
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 _is_cif_call(if_node.test) == 1:
cif_val: int = _evaluate_cif_test(pool, trans, if_node.test)
if _g_cif_eval_ok != 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:
HandlesBody.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.Handle(sub_cif)
elif sub_cif is not None:
HandlesBody.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:
HandlesBody.translate_stmt(trans, stmt_cif2)
return 0
# 1. 求值条件表达式
cond_val: llvmlite.Value | t.CPtr = HandlesExpr.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 条件表达式翻译失败
HandlesType.fatal_error(if_node.test, "if 条件表达式翻译失败", "TypeError")
cond_bits: int = HandlesExpr.get_llvm_type_bits(cond_val.Ty)
if cond_bits == 1:
cond_i1: llvmlite.Value | t.CPtr = cond_val
elif HandlesExpr.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:
HandlesBody.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:
HandlesBody.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
# ============================================================
# NewIfHandle - 工厂函数(委托到 gen.NewIfHandle)
# ============================================================
def NewIfHandle(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> IfHandle | t.CPtr:
"""创建 IfHandle 实例(委托到 gen.NewIfHandle)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.NewIfHandle(pool, trans)
return None
+33 -130
View File
@@ -28,8 +28,10 @@ import lib.core.Gen.Generator as Generator
# 保留同名模块级函数作为"一行委托":延迟 import Gen 取全局单例
# (BuildPipeline/main 创建后 set_global_gen 注册),再调用 gen 的
# 对应方法。签名与旧函数完全一致,调用方零改动。
# ImportsHandle 类与 NewImportsHandle 工厂保留在本模块(对象工厂,
# 不依赖 gen 状态,与 HandlesExpr.NewExprHandle 模式一致)。
# ImportsHandle 类与 NewImportsHandle 工厂已删除(P6 机械化迁移:
# HandleImport/HandleImportFromModule/HandleImportFromNames → 本模块
# 新增的 translate_import/translate_import_from_module/
# translate_import_from_names 模块级委托壳,路由到 gen 方法)。
# ============================================================
MAX_REEXPORT: t.CDefine = 512
@@ -287,137 +289,38 @@ def _check_import_sha1(node: ast.AST | t.CPtr, mod_name: str) -> int:
# ============================================================
# ImportsHandle - 导入语句处理器(Mixin 继承模式)
#
# 方法版本:直接更新 trans._imported_modules / trans._from_imports
# (内部调用的模块级工具函数经上方委托函数路由到 gen 方法)
# translate_import - 处理 import 语句(委托到 gen.translate_import)
# ============================================================
@t.NoVTable
class ImportsHandle(HandlesBase.Mixin):
"""导入语句处理器:继承 Mixin 获得 Trans 回指针"""
def __init__(self, trans: HT.Translator | t.CPtr):
self.Trans = trans
# ============================================================
# HandleImport - 处理 import 语句,更新 trans._imported_modules
# ============================================================
def HandleImport(self, node: ast.AST | t.CPtr) -> int:
"""处理 import 语句,返回 0"""
imp: ast.Import | t.CPtr = (ast.Import | t.CPtr)(node)
if imp is None:
return 0
names: list[ast.AST | t.CPtr] | t.CPtr = imp.names
if names is None:
return 0
nn: t.CSizeT = len(names)
for ni in range(nn):
alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni))
if alias is not None and alias.name is not None:
# 导入时立即校验模块 SHA1 是否注册(fast-fail,仅全量翻译时检查)
# declare_only=1/2 是 struct 预注册/import 扫描阶段:此时 SHA1 表
# 尚未包含后续才追加的模块(如 App 源文件),检查会造成误报
if self.Trans._declare_only == 0:
_check_import_sha1(node, alias.name)
pool_val: memhub.MemBuddy | t.CPtr = self.Trans.Pool
im_val: str = self.Trans._imported_modules
self.Trans._imported_modules = add_imported_module(
pool_val, im_val, alias.name)
# 别名也加入导入模块列表(用于模块限定构造器检查 Module.Class())
if alias.asname is not None:
self.Trans._imported_modules = add_imported_module(
pool_val, self.Trans._imported_modules, alias.asname)
# 别名也加入 from_imports(asname:fullname),
# 使 HT.func() 跨模块调用能通过 from_imports 查找别名→完整模块名→SHA1
# 否则 _lookup_module_sha1("HT") 找不到(mod_arr 只存文件名 HandlesTranslator)
self.Trans._from_imports = add_from_import(
pool_val, self.Trans._from_imports, alias.asname, alias.name)
else:
# 无别名时(import a.b.c),将顶层包名 "a" 也加入 _imported_modules,
# 使 a.b.c 作为属性访问的 base 被翻译时能通过 is_module_imported("a") 检查
dot_ptr: str = string.strstr(alias.name, '.')
if dot_ptr is not None:
pkg_len: t.CSizeT = t.CSizeT(t.CUInt64T(dot_ptr) - t.CUInt64T(alias.name))
if pkg_len > 0 and pkg_len < 256:
pkg_buf: bytes = pool_val.alloc(pkg_len + 1)
if pkg_buf is not None:
string.strncpy(pkg_buf, alias.name, pkg_len)
pkg_buf[pkg_len] = '\0'
self.Trans._imported_modules = add_imported_module(
pool_val, self.Trans._imported_modules, pkg_buf)
return 0
# ============================================================
# HandleImportFromModule - 处理 from X import Y 的模块部分
#
# 对相对导入(level > 0),使用 trans.CurrentPackage 解析为
# 完整模块名(如 __types → llvmlite.__types),确保 .deps.txt
# 记录的模块名与 SHA1 映射表一致。
# ============================================================
def HandleImportFromModule(self, node: ast.AST | t.CPtr) -> int:
"""处理 from X import Y 的模块部分,更新 trans._imported_modules"""
impf: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(node)
if impf is None:
return 0
# 解析模块名:相对导入需补充包前缀
resolved: str = _resolve_relative_module(
self.Trans.Pool, self.Trans.CurrentPackage,
impf.level, impf.module)
if resolved is not None:
# 导入时立即校验模块 SHA1 是否注册(fast-fail,仅全量翻译时检查)
if self.Trans._declare_only == 0:
_check_import_sha1(node, resolved)
self.Trans._imported_modules = add_imported_module(
self.Trans.Pool, self.Trans._imported_modules, resolved)
return 0
# ============================================================
# HandleImportFromNames - 处理 from X import Y 的名称部分
#
# 同样使用解析后的完整模块名,确保 from-import 映射
# (如 LLVMType:llvmlite.__types)能正确查到 SHA1。
# ============================================================
def HandleImportFromNames(self, node: ast.AST | t.CPtr) -> int:
"""处理 from X import Y 的名称部分,更新 trans._from_imports"""
impf: ast.ImportFrom | t.CPtr = (ast.ImportFrom | t.CPtr)(node)
if impf is None:
return 0
# 解析模块名:相对导入需补充包前缀
resolved: str = _resolve_relative_module(
self.Trans.Pool, self.Trans.CurrentPackage,
impf.level, impf.module)
if resolved is not None:
names: list[ast.AST | t.CPtr] | t.CPtr = impf.names
if names is not None:
nn: t.CSizeT = len(names)
for ni in range(nn):
alias: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(names.get(ni))
if alias is not None and alias.name is not None:
local_name: str = alias.name
orig_name: str = None
if alias.asname is not None:
local_name = alias.asname
orig_name = alias.name
self.Trans._from_imports = add_from_import(
self.Trans.Pool, self.Trans._from_imports,
local_name, resolved, orig_name)
# 命名空间隔离:from-import 的名称标记为可见结构体
HandlesStruct.add_visible_struct(self.Trans.Pool, local_name)
# 注册 re-export 映射:当前模块 re-export 了 local_name,源模块为 resolved
# 使跨模块调用 module.func() 能解析到正确的源模块 SHA1
if self.Trans.ModuleSha1 is not None:
register_reexport(self.Trans.ModuleSha1, local_name, resolved)
def translate_import(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""处理 import 语句,返回 0(委托到 gen.translate_import)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.translate_import(trans, node)
return 0
# ============================================================
# NewImportsHandle - 工厂函数
# translate_import_from_module - 处理 from X import Y 的模块部分
# (委托到 gen.translate_import_from_module)
# ============================================================
def NewImportsHandle(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> ImportsHandle | t.CPtr:
h: ImportsHandle | t.CPtr = pool.alloc(ImportsHandle.__sizeof__())
if h is None:
return None
string.memset(h, 0, ImportsHandle.__sizeof__())
h.Trans = trans
return h
def translate_import_from_module(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""处理 from X import Y 的模块部分(委托到 gen.translate_import_from_module)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.translate_import_from_module(trans, node)
return 0
# ============================================================
# translate_import_from_names - 处理 from X import Y 的名称部分
# (委托到 gen.translate_import_from_names)
# ============================================================
def translate_import_from_names(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""处理 from X import Y 的名称部分(委托到 gen.translate_import_from_names)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.translate_import_from_names(trans, node)
return 0
File diff suppressed because it is too large. Load diff
+6 -215
View File
@@ -1,227 +1,18 @@
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Gen.Generator as Generator
# ============================================================
# HandlesReturn - Return 语句处理(P6 对象化后的委托层)
# HandlesReturn - Return 语句处理(迁移完成)
#
# NewReturnHandle 工厂已迁移为 lib.core.Gen.StmtGenMixin 的方法
# (ReturnHandle 类保留:trans.ReturnH 的类型,由 HandlesTranslator.
# _init_state 经 NewReturnHandle 委托创建)。
# P6 机械化迁移:ReturnHandle 类 → StmtGenCifMixin.translate_return
# (lib.core.Gen.StmtGenCifMixin)。本文件保留模块级 _g_gen 单例
# (main.vp / BuildPipeline.vp 注入),迁移收尾后统一删除。
# ============================================================
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式)
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
# ============================================================
_g_gen: Generator.Generator | t.CPtr = None
@t.NoVTable
class ReturnHandle(HandlesBase.Mixin):
"""Return 语句处理器:继承 Mixin 获得 Trans 回指针"""
def __init__(self, trans: HT.Translator | t.CPtr):
self.Trans = trans
# ============================================================
# Handle - 处理 Return 语句,返回 0
#
# 翻译返回值(若有)并生成 ret 指令
# ============================================================
def Handle(self, 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 = self.Trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = self.Trans._cur_builder
mod: llvmlite.LLVMModule | t.CPtr = self.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 = HandlesExpr.translate_value(
builder, pool, mod, rtp_elts.get(rvi),
self.Trans._funcs, self.Trans._func_count, self.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 = HandlesVar.lookup_var(
self.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 HandlesExpr.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 = HandlesExpr.translate_value(
builder, pool, mod, rt.value,
self.Trans._funcs, self.Trans._func_count, self.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 = self.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 零值兜底
HandlesType.fatal_error(rt, "函数返回类型无法确定", "TypeError")
val = llvmlite.ConstZero(pool, ret_ty)
if val is None:
# fail-fast: 无法按返回类型构造零值
HandlesType.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 = self.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 = HandlesExpr.get_llvm_type_bits(val.Ty)
ret_bits: int = HandlesExpr.get_llvm_type_bits(ret_ty_rt)
val_is_ptr: int = HandlesExpr.is_ptr_type(val.Ty)
ret_is_ptr: int = HandlesExpr.is_ptr_type(ret_ty_rt)
# ptr 类型不一致性:val 是整数但 ret 是 ptr(或反之),必须转换
if val_is_ptr != ret_is_ptr:
val = HandlesExpr.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 = HandlesExpr.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 = HandlesExpr.coerce_to_type(builder, val, ret_ty_rt, node)
llvmlite.build_ret(builder, val)
return 0
# ============================================================
# NewReturnHandle - 工厂函数(委托到 gen.NewReturnHandle)
# ============================================================
def NewReturnHandle(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> ReturnHandle | t.CPtr:
"""创建 ReturnHandle 实例(委托到 gen.NewReturnHandle)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.NewReturnHandle(pool, trans)
return None
+3 -50
View File
@@ -185,19 +185,6 @@ class Translator:
# 跨模块函数返回类型无法精确解析。Phase A 多遍循环据此下遍重试。
_deps_pending: t.CInt
# 子 Handle 指针(每个 Handle 一个槽,通过 Mixin 回指针访问本结构体)
AssignH: HandlesAssign.AssignHandle | t.CPtr
ReturnH: HandlesReturn.ReturnHandle | t.CPtr
ImportsH: HandlesImports.ImportsHandle | t.CPtr
AnnAssignH: HandlesAnnAssign.AnnAssignHandle | t.CPtr
AugAssignH: HandlesAugAssign.AugAssignHandle | t.CPtr
IfH: HandlesIf.IfHandle | t.CPtr
WhileH: HandlesWhile.WhileHandle | t.CPtr
ForH: HandlesFor.ForHandle | t.CPtr
ExprH: HandlesExpr.ExprHandle | t.CPtr
ExprCallH: HandlesExprCall.ExprCallHandle | t.CPtr
MatchH: HandlesMatch.MatchHandle | t.CPtr
# 嵌套作用域符号表
SymTab: HandlesVar.SymbolTable | t.CPtr
@@ -240,17 +227,6 @@ class Translator:
self.GenericTypeArgs = None
self._declare_only = 0
self._deps_pending = 0
self.AssignH = None
self.ReturnH = None
self.ImportsH = None
self.AnnAssignH = None
self.AugAssignH = None
self.IfH = None
self.WhileH = None
self.ForH = None
self.ExprH = None
self.ExprCallH = None
self.MatchH = None
self.SymTab = None
# ============================================================
@@ -280,29 +256,6 @@ class Translator:
self._nonlocal_types = stdlib.malloc(MAX_GLOBAL_NAMES * 8)
if self._nonlocal_types is not None:
string.memset(self._nonlocal_types, 0, MAX_GLOBAL_NAMES * 8)
# 创建子 Handle(传入 self 作为 Mixin 回指针)
if self.AssignH is None:
self.AssignH = HandlesAssign.NewAssignHandle(pool, self)
if self.ReturnH is None:
self.ReturnH = HandlesReturn.NewReturnHandle(pool, self)
if self.ImportsH is None:
self.ImportsH = HandlesImports.NewImportsHandle(pool, self)
if self.AnnAssignH is None:
self.AnnAssignH = HandlesAnnAssign.NewAnnAssignHandle(pool, self)
if self.AugAssignH is None:
self.AugAssignH = HandlesAugAssign.NewAugAssignHandle(pool, self)
if self.IfH is None:
self.IfH = HandlesIf.NewIfHandle(pool, self)
if self.WhileH is None:
self.WhileH = HandlesWhile.NewWhileHandle(pool, self)
if self.ForH is None:
self.ForH = HandlesFor.NewForHandle(pool, self)
if self.MatchH is None:
self.MatchH = HandlesMatch.NewMatchHandle(pool, self)
if self.ExprH is None:
self.ExprH = HandlesExpr.NewExprHandle(pool, self)
if self.ExprCallH is None:
self.ExprCallH = ExprCallHandle.NewExprCallHandle(pool, self)
# ============================================================
# 主翻译入口
@@ -426,11 +379,11 @@ class Translator:
kd: int = child.kind()
if kd == ast.ASTKind.Import:
cur_imp_lineno = child.lineno
self.ImportsH.HandleImport(child)
HandlesImports.translate_import(self, child)
elif kd == ast.ASTKind.ImportFrom:
cur_imp_lineno = child.lineno
self.ImportsH.HandleImportFromModule(child)
self.ImportsH.HandleImportFromNames(child)
HandlesImports.translate_import_from_module(self, child)
HandlesImports.translate_import_from_names(self, child)
# 对齐 TPC _inject_auto_imports:检测源文件对 list/dict 容器的使用
# (裸名注解 d: dict / 构造 dict(...) / 下标 list[T]),自动把容器
# 类标记为可见结构体。背景:_list.vp/_dict.vp 定义内建容器类且已由
+14 -194
View File
@@ -1,220 +1,40 @@
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdio
import viperlib
import lib.core.Handles.HandlesBase as HandlesBase
import lib.core.Handles.HandlesTranslator as HT
import lib.core.Handles.HandlesExpr as HandlesExpr
import lib.core.Handles.HandlesBody as HandlesBody
import lib.core.Handles.HandlesType as HandlesType
import lib.core.Gen.Generator as Generator
# ============================================================
# HandlesWhile - while 循环语句处理(P6 对象化后的委托层)
# HandlesWhile - while 循环语句处理(迁移完成,保留跨 Mixin 委托壳)
#
# NewWhileHandle 工厂已迁移为 lib.core.Gen.StmtGenMixin 的方法
# (WhileHandle 类保留:trans.WhileH 的类型,由 HandlesTranslator.
# _init_state 经 NewWhileHandle 委托创建)。
#
# 翻译 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:
# P6 机械化迁移:WhileHandle 类 → StmtGenCifMixin.translate_while;
# 模块级辅助 _IsConstTrue/_NodeHasBreak/_StmtHasBreak → StmtGenCifMixin
# 方法(merge 可达性判定)。
# 分派中枢(StmtGenMixin)经本壳跨链调用(Viper @t.NoVTable 静态绑定下
# 跨 Mixin self. 调用 mangle 失败,须经模块级委托壳桥回 gen 单例)。
# 迁移收尾(编译器缺陷修复)后统一删除。
# ============================================================
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesStruct 模式)
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
#
# 由 BuildPipeline/main 在 gen 创建后调用 set_global_gen 注入。
# 委托函数用本地 _g_gen(cast 成 Generator 类型)调
# StmtGenMixin 方法,避免函数体 import 包模块与类/模块名歧义。
# StmtGenCifMixin 方法,避免函数体 import 包模块与类/模块名歧义。
# ============================================================
_g_gen: Generator.Generator | t.CPtr = None
@t.NoVTable
class WhileHandle(HandlesBase.Mixin):
"""while 循环语句处理器:继承 Mixin 获得 Trans 回指针"""
def __init__(self, trans: HT.Translator | t.CPtr):
self.Trans = trans
# ============================================================
# Handle - 处理 while 语句,返回新增变量数
# ============================================================
def Handle(self, node: ast.AST | t.CPtr) -> int:
"""翻译 while 循环语句"""
if node is None:
return 0
trans: HT.Translator | t.CPtr = self.Trans
pool: memhub.MemBuddy | t.CPtr = trans.Pool
builder: llvmlite.IRBuilder | t.CPtr = trans._cur_builder
func: llvmlite.Function | t.CPtr = trans._cur_func
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 = HandlesExpr.translate_value(
builder, pool, trans.Module, while_node.test,
trans._funcs, trans._func_count, trans)
if cond_val is None:
# fail-fast: while 条件表达式翻译失败
HandlesType.fatal_error(while_node.test, "while 条件表达式翻译失败", "TypeError")
# Compare/Not 表达式已返回 i1,直接使用;指针类型与 null 比较;其他类型与 0 比较
cond_bits: int = HandlesExpr.get_llvm_type_bits(cond_val.Ty)
if cond_bits == 1:
cond_i1: llvmlite.Value | t.CPtr = cond_val
elif HandlesExpr.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:
HandlesBody.translate_stmt(trans, stmt)
# 恢复旧循环上下文
trans._break_bb = old_break
trans._continue_bb = old_continue
if llvmlite.builder_cur_block_is_terminated(builder) == 0:
llvmlite.build_br(builder, 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 1 全 return 被误判"流程掉出末尾"。
if _IsConstTrue(while_node.test) != 0 and _StmtHasBreak(body) == 0:
trans._ctrl_merge_reachable = 0
return 0
# ============================================================
# NewWhileHandle - 工厂函数(委托到 gen.NewWhileHandle)
# translate_while - while 循环语句翻译(委托到 gen.translate_while)
# ============================================================
def NewWhileHandle(pool: memhub.MemBuddy | t.CPtr,
trans: HT.Translator | t.CPtr) -> WhileHandle | t.CPtr:
"""创建 WhileHandle 实例(委托到 gen.NewWhileHandle)"""
def translate_while(trans: HT.Translator | t.CPtr,
node: ast.AST | t.CPtr) -> int:
"""翻译 while 循环语句(委托到 gen.translate_while)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.NewWhileHandle(pool, trans)
return None
# ============================================================
# 无限循环判定辅助(merge 可达性)
#
# _IsConstTrue: while 条件为常量真(CONST_INT 非 0 / CONST_BOOL 真)
# _NodeHasBreak / _StmtHasBreak: 扫描本层 break(跳过嵌套 While/For
# 子树——嵌套循环的 break 归内层,不影响外层 merge 可达性)
# ============================================================
def _IsConstTrue(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(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 _NodeHasBreak(c) != 0:
return 1
return 0
def _StmtHasBreak(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 _NodeHasBreak(s) != 0:
return 1
return g.translate_while(trans, node)
return 0
+2
View File
@@ -18,6 +18,7 @@ import lib.core.Handles.HandlesMatch as HandlesMatch
import lib.core.Handles.HandlesEnum as HandlesEnum
import lib.core.Handles.HandlesAnnAssign as HandlesAnnAssign
import lib.core.Handles.HandlesAugAssign as HandlesAugAssign
import lib.core.Handles.HandlesAssign as HandlesAssign
import lib.core.Handles.HandlesVar as HandlesVar
import lib.core.Handles.HandlesMain as HandlesMain
import lib.core.BuildPipeline as BuildPipeline
@@ -149,6 +150,7 @@ def main() -> int:
HandlesEnum._g_gen = gen
HandlesAnnAssign._g_gen = gen
HandlesAugAssign._g_gen = gen
HandlesAssign._g_gen = gen
HandlesVar._g_gen = gen
HandlesTranslator._g_gen = gen
HandlesMain._g_gen = gen