Files
ViperC/App/lib/core/Handles/HandlesAnnAssign.vp
T
TermiNexus e07ea491a5 chore(gen): 全量备份——Handles 委托壳瘦身与单例注入统一
- 删除 Handles 各模块已迁移至 Gen 的旧函数体,保留一行委托壳(25 文件 -798 行)
- main.vp / BuildPipeline.vp 全局单例注入改为 _g_gen 直接赋值
- 机械化迁移测试前的基线备份
2026-08-20 05:33:59 +08:00

728 lines
39 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import t, c
from stdint import *
import ast
import llvmlite
import memhub
import string
import stdio
import stdlib
import w32.fileio as fileio
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.HandlesType as HandlesType
import lib.core.Handles.HandlesNonlocal as HandlesNonlocal
import lib.core.Handles.HandlesClassDef as HandlesClassDef
import lib.core.Handles.HandlesExprCall as HandlesExprCall
import lib.core.Handles.HandlesStruct as HandlesStruct
import lib.core.VLogger as VLogger
import lib.core.Handles.ExprCallCall as ExprCallCall
import lib.core.Handles.ExprCallCtor as ExprCallCtor
import lib.core.Gen.Generator as Generator
# ============================================================
# 全局 gen 单例(模块级镜像,同 HandlesType/HandlesStruct 模式)
# ============================================================
_g_gen: Generator.Generator | t.CPtr = None
# ============================================================
# HandlesAnnAssign - AnnAssign 语句处理(Mixin 继承模式)
# ============================================================
# ============================================================
# is_cdefine_annotation - 检测注解是否为 t.CDefine(模块级函数)
#
# 支持两种形式:
# 1. Attribute(Name('t'), 'CDefine')
# 2. BinOp(... | Attribute(Name('t'), 'CDefine'))(联合注解)
# ============================================================
def is_cdefine_annotation(annot: ast.AST | t.CPtr) -> int:
"""检测注解是否为 t.CDefine,返回 1 表示是,0 表示否(委托到 gen.is_cdefine_annotation)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.is_cdefine_annotation(annot)
return 0
def is_ctypedef_annotation(annot: ast.AST | t.CPtr) -> int:
"""检测注解是否为 t.CTypedef,返回 1 表示是,0 表示否(委托到 gen._is_ctypedef_annotation)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._is_ctypedef_annotation(annot)
return 0
# ============================================================
# extract_cdefine_int_value - 从 AnnAssign.value 提取整数常量(模块级函数)
#
# 支持的表达式形式:
# 1. Constant(INT) — 如 0x0002, 42
# 2. BinOp(BitOr/BitAnd) — 如 FOREGROUND_RED | FOREGROUND_GREEN
# 3. Name — 引用已注册的 CDefine 常量
# 4. Call — 如 t.CUnsignedLong(-11) → 取第一个参数
# 5. UnaryOp(USub/UAdd/Invert) — 如 -11
# ============================================================
def extract_cdefine_int_value(val_node: ast.AST | t.CPtr) -> t.CInt64T:
"""从值节点提取整数常量(支持 Constant/BinOp/Name/Call/UnaryOp,委托到 gen.extract_cdefine_int_value)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g.extract_cdefine_int_value(val_node)
return 0
# ============================================================
# _register_cdefine_from_value - 注册 CDefine 常量(浮点/整数自动识别)
#
# 浮点字面量(如 vipermath 的 U_M_PI: t.CDefine = 3.14159...)走
# register_cdefine_double,否则 translate_value 查表得 0 生成
# ret i32 0(llc 报错 "value doesn't match function result type")。
# ============================================================
def _register_cdefine_from_value(pool: memhub.MemBuddy | t.CPtr,
name: str, val_node: ast.AST | t.CPtr) -> None:
"""注册 CDefine 常量(浮点字面量 → register_cdefine_double,否则整数,委托到 gen._register_cdefine_from_value)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
g._register_cdefine_from_value(pool, name, val_node)
# ============================================================
# 源文件重读恢复 CDefine 浮点值
#
# 背景:AST 节点的 float_val/str_val 字段可能被 pool 分配操作覆写
# (MemBuddy 内存冲突),导致注册的浮点 CDefine 值错误(llc ret i32 0)。
# 本函数直接读源文件找 "NAME: t.CDefine = value" 行,atof 解析 value——
# 源文件文本不受 pool 影响,是最可靠的恢复路径。
# 原模块级 _g_recover_found 全局已迁移为 gen 字段(RecoverFound)。
# ============================================================
def _recover_found() -> int:
"""检查最近一次 _recover_cdefine_float 是否成功(委托到 gen._recover_found)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._recover_found()
return 0
def _recover_cdefine_float(name: str, out: t.CDouble | t.CPtr) -> int:
"""从当前模块源文件恢复浮点 CDefine 值,写入 out[0],成功返回 1
用输出参数传递 double,避免 TPV 跨模块 double 返回值传递 bug。
(委托到 gen._recover_cdefine_float)
"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._recover_cdefine_float(name, out)
return 0
# ============================================================
# _annotation_contains_name - 递归检查注解中是否包含指定名称
#
# 支持 BinOp(BitOr) 递归,同时检查 Attribute.attr 和 Name.id。
# ============================================================
def _annotation_contains_name(annot: ast.AST | t.CPtr, name: str) -> int:
"""递归检查注解中是否包含指定名称,返回 1=包含 / 0=不包含(委托到 gen._annotation_contains_name)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._annotation_contains_name(annot, name)
return 0
# ============================================================
# _is_ptr_element_annotation - 检查注解是否为 bytes|t.CPtr 或 str|t.CPtr
#
# 返回 1=是(下标按 8 字节步长, i8** 语义), 0=否(下标按 1 字节步长, i8* 语义)
#
# 规则:
# bytes|t.CPtr / str|t.CPtr → i8**(8 字节步长)→ 返回 1
# t.CChar|t.CPtr / t.CInt8T|t.CPtr → i8*(1 字节步长)→ 返回 0
# 纯 bytes / str → i8*(1 字节步长)→ 返回 0
#
# 注: 注解中的 "|" 是"和"的意思(组合类型),非右值中的位或运算
# ============================================================
def _is_ptr_element_annotation(annot: ast.AST | t.CPtr) -> int:
"""检查注解是否为 bytes|t.CPtr 或 str|t.CPtr 形式(委托到 gen._is_ptr_element_annotation)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._is_ptr_element_annotation(annot)
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 + 列表字面量 → 静态数组
#
# 单参 t.CArray[elem_ty] 解析为 Ptr(elem_ty),但当 RHS 是列表字面量时,
# 按 TPC 语义应推断为 [len x elem_ty](对齐 TPC ParseListAnnotation):
# 避免误走动态 list 构造(_find_pool_var 兜底引用外部 @_mbuddy → 链接期
# undefined)。PreScan 与 Handle 都调用(PreScan 预创建 alloca 的类型必须
# 与 Handle 一致,否则 get_or_create_sym 复用旧 alloca 使推断失效)。
# ============================================================
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)
return resolved_ty
# ============================================================
# _init_global_array_from_list — 从列表字面量初始化全局数组
#
# 为每个元素生成 GEP + store 指令,将值存入全局数组的对应位置。
# 适用于模块级 t.CArray[elem_ty, count] = [v0, v1, ...] 的初始化。
#
# Args:
# builder: IRBuilder
# pool: 编译器内存池
# mod: LLVMModule
# array_alloca: 全局数组变量的 Value 引用(类型为 [N x elem_ty]*)
# list_node: ast.List 节点
# trans: Translator 对象
#
# Returns:
# 0 成功,1 失败
# ============================================================
def _init_global_array_from_list(builder: llvmlite.IRBuilder | t.CPtr,
pool: memhub.MemBuddy | t.CPtr,
mod: llvmlite.LLVMModule | t.CPtr,
array_alloca: llvmlite.Value | t.CPtr,
list_node: ast.AST | t.CPtr,
trans: HT.Translator | t.CPtr) -> int:
"""从列表字面量初始化全局数组,为每个元素生成 GEP + store(委托到 gen._init_global_array_from_list)"""
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
if g is not None:
return g._init_global_array_from_list(builder, pool, mod, array_alloca, list_node, trans)
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")
return 0
# ============================================================
# NewAnnAssignHandle - 工厂函数
# ============================================================
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