- 删除 Handles 各模块已迁移至 Gen 的旧函数体,保留一行委托壳(25 文件 -798 行) - main.vp / BuildPipeline.vp 全局单例注入改为 _g_gen 直接赋值 - 机械化迁移测试前的基线备份
728 lines
39 KiB
Plaintext
728 lines
39 KiB
Plaintext
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
|