- 新增 _default_val_const_text:字段默认值 AST -> 常量文本(仅整型/字符/负号字面量可折叠,其余零值兜底) - 新增 _build_stg_struct_init_text:按 StructEntry 字段默认值生成完整 struct 常量初始化器(LLVM 要求列全字段);无非零默认值返回 None - storage 分支新增 elif:无 vtable 对象全局走默认值初始化器(vtable 路径不变) - 效果:fat32.default_fs 的 .stg 由 zeroinitializer 变为含 sector_size=512/root_cluster=2/free_clusters=0xFFFFFFFF/backup_sector=6/winsect=-1 的完整常量;drive_lock 等零值等价场景保持 zeroinitializer
1299 lines
72 KiB
Plaintext
1299 lines
72 KiB
Plaintext
import lib.core.Gen.Generator as Generator
|
||
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import llvmlite
|
||
import memhub
|
||
import string
|
||
import stdio
|
||
import viperlib
|
||
import lib.core.VLogger as VLogger
|
||
import lib.core.Gen.Translator as HT
|
||
import lib.core.Gen.GenTypes as GenTypes
|
||
|
||
|
||
# ============================================================
|
||
# TranslatorGenMixin - 翻译驱动 Mixin(对象化 P6-E)
|
||
#
|
||
# 从 HandlesMain.vp / HandlesTranslator.vp 迁移:模块级纯函数
|
||
# (trans 首参)→ 类方法。包含:
|
||
# - 模块级翻译入口(translate_children/create_wrapper_main/
|
||
# handle_module_level_var 等,原 HandlesMain.vp)
|
||
# - global/nonlocal 名称管理辅助函数(原 HandlesTranslator.vp)
|
||
#
|
||
# 常量(MAX_VARS/MAX_FUNCS/MAX_GLOBAL_NAMES)与原模块保持一致。
|
||
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
|
||
# ============================================================
|
||
|
||
|
||
# ============================================================
|
||
# 常量(与 HandlesTranslator 保持一致)
|
||
# ============================================================
|
||
MAX_VARS: t.CDefine = 1024
|
||
MAX_FUNCS: t.CDefine = 1024
|
||
MAX_GLOBAL_NAMES: t.CDefine = 32
|
||
|
||
|
||
# ============================================================
|
||
# TranslatorGenMixin - 翻译驱动(模块级翻译入口 + 作用域名称管理)
|
||
# ============================================================
|
||
@t.NoVTable
|
||
class TranslatorGenMixin:
|
||
"""翻译驱动 Mixin(P6 方法化)"""
|
||
|
||
# ============================================================
|
||
# _register_cexport_from_funcdef - Phase 1a 预注册 CExport/State 函数
|
||
#
|
||
# 解决翻译顺序依赖问题:Phase 1b 按字母序翻译,后翻译的模块的
|
||
# CExport 函数无法被先翻译的模块正确识别为裸名调用。
|
||
# Phase 1a 预注册所有 CExport/State 函数名到全局表。
|
||
# ============================================================
|
||
Gen: Generator.Generator | t.CPtr
|
||
def _register_cexport_from_funcdef(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""预注册 CExport/State 函数到全局表(仅注册,不生成 IR)"""
|
||
fd: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node)
|
||
if fd is None or fd.name is None:
|
||
return 0
|
||
if trans is None or trans.ModuleSha1 is None:
|
||
return 0
|
||
|
||
# 检查返回类型是否有 CExport 或 State 标记
|
||
has_export: int = 0
|
||
has_state: int = 0
|
||
if fd.returns is not None:
|
||
has_export = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "CExport", 0)
|
||
has_state = self.Gen.TypeGenErr.has_decorator_marker(fd.returns, "State", 0)
|
||
|
||
if has_export != 0 or has_state != 0:
|
||
self.Gen.CallGenBase.register_cexport_func(trans.ModuleSha1, fd.name)
|
||
|
||
return 0
|
||
|
||
# ============================================================
|
||
# translate_children - 遍历 AST 子节点并分派翻译
|
||
#
|
||
# 对应 TransPyC translator._translate_children()
|
||
# 共享状态从 trans 获取,imported_modules/from_imports 更新到 trans
|
||
# ============================================================
|
||
def translate_children(self, trans: HT.Translator | t.CPtr,
|
||
tree: ast.AST | t.CPtr) -> int:
|
||
"""遍历 tree.children 并翻译每个子节点
|
||
|
||
Args:
|
||
trans: 翻译器(含所有共享状态)
|
||
tree: AST 模块节点
|
||
|
||
Returns:
|
||
t.CInt: 新增的变量数
|
||
"""
|
||
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||
if ch is None:
|
||
return 0
|
||
|
||
cn_count: t.CSizeT = len(ch)
|
||
added_total: int = 0
|
||
|
||
for ci in range(cn_count):
|
||
child: ast.AST | t.CPtr = ch.get(ci)
|
||
if child is None: continue
|
||
kd: int = child.kind()
|
||
|
||
# _declare_only == 0 时,_translate_module_level 已预处理导入语句,
|
||
# 此处跳过避免重复处理(from_imports 条目重复)
|
||
if trans._declare_only == 0 and (kd == ast.ASTKind.Import or kd == ast.ASTKind.ImportFrom):
|
||
continue
|
||
if kd == ast.ASTKind.Import:
|
||
self.Gen.ImportsGen.translate_import(trans, child)
|
||
elif kd == ast.ASTKind.ImportFrom:
|
||
self.Gen.ImportsGen.translate_import_from_module(trans, child)
|
||
self.Gen.ImportsGen.translate_import_from_names(trans, child)
|
||
elif kd == ast.ASTKind.FunctionDef:
|
||
# Phase 1a 声明模式:只注册 CExport/State 函数到全局表(解决翻译顺序依赖)
|
||
# Phase 1b 全量翻译:正常翻译函数体
|
||
if trans._declare_only == 0:
|
||
added: int = self.Gen.FuncGenDef.translate_function_def(trans, child)
|
||
added_total += added
|
||
elif trans._declare_only == 1:
|
||
self._register_cexport_from_funcdef(trans, child)
|
||
# 预解析函数签名类型,触发泛型类特化(如 numpy 的 _empty_like
|
||
# 签名 ndarray[t.CDouble] → 特化结构体注册)。
|
||
# 1a 阶段在 mark1 之前,特化结构体的 Ty/Fields 分配在 mark1 前,
|
||
# 不被 1b 的 mark/reset 回收 → 避免 Phase2 翻译 App 文件时 UAF
|
||
# (Phase1 1b 才触发特化时,结构体 Ty/Fields 在 pool 被 reset 覆写)。
|
||
# 仅触发特化,不验证结果(1b 全量翻译时仍会重新解析)。
|
||
self._prescan_funcdef_signatures(trans, child)
|
||
elif kd == ast.ASTKind.ClassDef:
|
||
# ClassDef 在模块级直接处理(不需要 builder)
|
||
# _declare_only=2(import扫描模式)时跳过,只处理 import 依赖
|
||
if trans._declare_only != 2:
|
||
self.Gen.ClassGenDef.translate_class_def(trans, child)
|
||
elif trans._declare_only == 0 and trans._cur_builder is not None:
|
||
# 有 builder → 委托 HandlesBody 分派
|
||
added = self.Gen.StmtGen.translate_stmt(trans, child)
|
||
added_total += added
|
||
elif kd == ast.ASTKind.AnnAssign and trans._declare_only != 2:
|
||
# 模块级 AnnAssign
|
||
# _declare_only=2(import扫描模式)时跳过
|
||
# _declare_only=1(struct注册模式)时只处理 CDefine(在 handle_module_level_var 内部判断)
|
||
# _declare_only=0(全量翻译)时处理所有模块级 AnnAssign
|
||
added = self.handle_module_level_var(trans, child)
|
||
added_total += added
|
||
elif trans._declare_only == 0 and kd == ast.ASTKind.Assign:
|
||
# 无 builder 的模块级 Assign → 创建全局变量(仅全量翻译模式)
|
||
added = self.handle_module_level_var(trans, child)
|
||
added_total += added
|
||
# [PF-DBG] 子语句翻译后 pending 检测(用后移除):定位 gfx.vp 类收敛失败
|
||
if trans is not None and trans._deps_pending != 0:
|
||
nm_dbg: str = None
|
||
if kd == ast.ASTKind.ClassDef:
|
||
cd_dbg: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(child)
|
||
if cd_dbg is not None:
|
||
nm_dbg = cd_dbg.name
|
||
elif kd == ast.ASTKind.FunctionDef:
|
||
fd_dbg: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(child)
|
||
if fd_dbg is not None:
|
||
nm_dbg = fd_dbg.name
|
||
stdio.printf("[PF-DBG] pending-after-child: kind=%d name=%s sha1=%s\n",
|
||
kd, nm_dbg if nm_dbg is not None else "-",
|
||
trans.ModuleSha1 if trans.ModuleSha1 is not None else "?")
|
||
stdio.fflush(None)
|
||
|
||
return added_total
|
||
|
||
# ============================================================
|
||
# _prescan_funcdef_signatures - 1a 阶段预解析模块级函数签名
|
||
#
|
||
# 触发泛型类特化(如 numpy 的 _empty_like 签名 ndarray[t.CDouble]),
|
||
# 使特化结构体在 mark1 前注册(Ty/Fields 不被 1b 的 mark/reset 回收),
|
||
# 避免 Phase2 翻译 App 文件时访问悬空结构体(UAF)。
|
||
# 仅解析类型触发特化,不验证结果(1b 全量翻译时重新解析)。
|
||
# ============================================================
|
||
def _prescan_funcdef_signatures(self, trans: HT.Translator | t.CPtr,
|
||
fd: ast.FunctionDef | t.CPtr) -> None:
|
||
"""预解析模块级函数签名的返回/参数类型,触发泛型类特化"""
|
||
if trans is None or fd is None:
|
||
return
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
if pool is None:
|
||
return
|
||
imp: str = trans._imported_modules
|
||
fi: str = trans._from_imports
|
||
if fd.returns is not None:
|
||
self.Gen.TypeGenResolve.resolve_annotation_type(pool, fd.returns, imp, fi, trans, 0)
|
||
if fd.args is not None:
|
||
ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args)
|
||
if ags.args is not None:
|
||
al: list[ast.AST | t.CPtr] | t.CPtr = ags.args
|
||
an: t.CSizeT = len(al)
|
||
ai: t.CSizeT
|
||
for ai in range(an):
|
||
ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(al.get(ai))
|
||
if ag is not None and ag.annotation is not None:
|
||
self.Gen.TypeGenResolve.resolve_annotation_type(pool, ag.annotation, imp, fi, trans, 0)
|
||
|
||
# ============================================================
|
||
# _build_array_initializer_text - 从 AST List 生成 LLVM IR 数组初始化器
|
||
#
|
||
# 生成格式: [N x elem_ty] [elem_ty val0, elem_ty val1, ...]
|
||
# 用于模块级 t.CArray 列表字面量初始化(不依赖 builder,直接生成常量初始化器)
|
||
# ============================================================
|
||
def _build_array_initializer_text(self, pool: memhub.MemBuddy | t.CPtr,
|
||
var_ty: llvmlite.LLVMType | t.CPtr,
|
||
list_node: ast.List | t.CPtr) -> str:
|
||
"""从 AST List 节点生成 LLVM IR 数组初始化器文本,None 失败"""
|
||
if var_ty is None or list_node is None:
|
||
return None
|
||
|
||
# 重新进行类型转换,确保 TPV 编译器正确识别 ast.List 类型
|
||
# (避免 init_list_node 初始值为 None 时类型推断退化为 t.CPtr)
|
||
ln: ast.List | t.CPtr = (ast.List | t.CPtr)(list_node)
|
||
if ln is None:
|
||
return None
|
||
|
||
# 从 var_ty 提取数组元素类型和数量
|
||
elem_ty: llvmlite.LLVMType | t.CPtr = None
|
||
arr_count: t.CInt = 0
|
||
match var_ty:
|
||
case llvmlite.LLVMType.Array(et, cnt):
|
||
elem_ty = et
|
||
arr_count = cnt
|
||
|
||
if elem_ty is None or arr_count <= 0:
|
||
return None
|
||
|
||
# 确定元素类型的 IR 表示
|
||
elem_ir_ty: str = "i8"
|
||
is_int_elem: int = 1
|
||
match elem_ty:
|
||
case llvmlite.LLVMType.Int(bits):
|
||
is_int_elem = 1
|
||
if bits == 8:
|
||
elem_ir_ty = "i8"
|
||
elif bits == 16:
|
||
elem_ir_ty = "i16"
|
||
elif bits == 32:
|
||
elem_ir_ty = "i32"
|
||
elif bits == 64:
|
||
elem_ir_ty = "i64"
|
||
case _:
|
||
is_int_elem = 0
|
||
|
||
# 获取列表元素(通过 ln.elts 而非 list_node.elts,确保类型正确识别)
|
||
elts: list[ast.AST | t.CPtr] | t.CPtr = ln.elts
|
||
if elts is None:
|
||
return None
|
||
elts_count: t.CSizeT = len(elts)
|
||
|
||
# 元素数超过声明长度 → fail-fast(此前在下方循环中按声明长度截断、静默丢弃
|
||
# 多余元素:apic._trampoline_bin 声明 [128 x i8] 却给出 138 个字节 → 末尾
|
||
# mov rax,[0x7F28]; jmp rax 被丢弃,AP trampoline 失效)。
|
||
if t.CSizeT(arr_count) < elts_count:
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
list_node,
|
||
f"数组初始化元素数 {elts_count} 超过数组声明长度 {arr_count},不允许静默截断",
|
||
"OverflowError")
|
||
return None
|
||
|
||
# 非整数元素类型(struct/指针等聚合):不存在 "%s %lld" 文本展开。
|
||
# 仅当列表全零(元素缺失按零填充)时返回整体 "zeroinitializer"——
|
||
# 对任意聚合类型合法(devfs.directories: t.CArray[devfs_directory, N]
|
||
# = [0] 此前生成 [i8 0, ...] 与 [N x %devfs_directory] 类型不匹配,
|
||
# llc "constant expression type mismatch" 根因)。含非零/非整数常量
|
||
# 无法文本表达 → None → 调用方 fail-fast。
|
||
if is_int_elem == 0:
|
||
# 嵌套数组元素(t.CArray[t.CArray[t.CUInt8T, 16], 256] = [{...}, ...]):
|
||
# elem_ty 是 Array → 递归构建子数组初始化器文本。内层类型省略
|
||
# (由外层全局类型推断),llc 合法。vga.vp font 8x16 点阵字库根因:
|
||
# 此前只支持 Int 元素,嵌套数组走 zeroinitializer-only 检查,花括号
|
||
# 行(ast.Set)含非零常量 → None → "初始化器构建失败" fail-fast。
|
||
is_nested_arr: int = 0
|
||
match elem_ty:
|
||
case llvmlite.LLVMType.Array(_, _):
|
||
is_nested_arr = 1
|
||
case _:
|
||
pass
|
||
if is_nested_arr != 0:
|
||
cnt_total_n: t.CSizeT = t.CSizeT(arr_count)
|
||
buf_size_n: t.CSizeT = 128 + cnt_total_n * 192
|
||
buf_n: str = pool.alloc(buf_size_n)
|
||
if buf_n is None:
|
||
return None
|
||
written_n: t.CInt = viperlib.snprintf(buf_n, buf_size_n, "[")
|
||
pos_n: t.CSizeT = t.CSizeT(written_n)
|
||
# 子数组元素类型前缀(如 "[16 x i8]"):嵌套数组初始化器内层
|
||
# 必须显式类型(llc 对省略内层类型的 [[i8 0,...],...] 报
|
||
# "expected number in address space";用户规范要求
|
||
# [[16 x i8][i8 0, ...], ...] 形式)。TypePrint 序列化 elem_ty。
|
||
elem_ty_str_n: str = pool.alloc(96)
|
||
if elem_ty_str_n is None:
|
||
return None
|
||
llvmlite.TypePrint(elem_ty_str_n, 96, elem_ty, pool)
|
||
i_n: t.CSizeT = 0
|
||
while i_n < cnt_total_n:
|
||
sub_n: str = None
|
||
if i_n < elts_count:
|
||
en_n: ast.AST | t.CPtr = elts.get(i_n)
|
||
if en_n is not None:
|
||
ek_n: int = en_n.kind()
|
||
if ek_n == ast.ASTKind.List:
|
||
sub_n = self._build_array_initializer_text(
|
||
pool, elem_ty, (ast.List | t.CPtr)(en_n))
|
||
elif ek_n == ast.ASTKind.Set:
|
||
# 花括号行字面量(如点阵字库 {0x00, ...}):Set.elts
|
||
# 与 List 同构,包装为临时 List 递归生成子数组文本
|
||
se_n: ast.Set | t.CPtr = (ast.Set | t.CPtr)(en_n)
|
||
if se_n is not None and se_n.elts is not None:
|
||
sub_n = self._build_array_initializer_text(
|
||
pool, elem_ty, ast.List(pool, se_n.elts, ast.ASTCtx.Load))
|
||
if sub_n is None:
|
||
# 元素缺失/无法展开:子数组整体零初始化
|
||
sub_n = "zeroinitializer"
|
||
if i_n > 0:
|
||
written_n = viperlib.snprintf(buf_n + pos_n, buf_size_n - pos_n, ", ")
|
||
pos_n += t.CSizeT(written_n)
|
||
written_n = viperlib.snprintf(
|
||
buf_n + pos_n, buf_size_n - pos_n, "%s%s", elem_ty_str_n, sub_n)
|
||
pos_n += t.CSizeT(written_n)
|
||
i_n += 1
|
||
viperlib.snprintf(buf_n + pos_n, buf_size_n - pos_n, "]")
|
||
return buf_n
|
||
for zi in range(elts_count):
|
||
ze: ast.AST | t.CPtr = elts.get(zi)
|
||
if ze is None:
|
||
continue
|
||
zk: int = ze.kind()
|
||
if zk == ast.ASTKind.Constant:
|
||
zc: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(ze)
|
||
if zc is None:
|
||
continue
|
||
# None(CONST_NONE)视为零:函数指针数组
|
||
# irq_handlers: t.CArray[irq_handler_t, 16] = [None] 表示
|
||
# 全空(idt.vp L387)——CONST_NONE 不是 CONST_INT,此前
|
||
# 被拒 → "初始化器构建失败" fail-fast。None 归一零填充。
|
||
if zc.const_kind == ast.CONST_NONE:
|
||
continue
|
||
if zc.const_kind != ast.CONST_INT or zc.int_val != 0:
|
||
return None
|
||
elif zk == ast.ASTKind.UnaryOp:
|
||
if self.Gen.AssignGen.extract_cdefine_int_value(ze) != 0:
|
||
return None
|
||
else:
|
||
return None
|
||
return "zeroinitializer"
|
||
|
||
# 计算缓冲区大小: 每个元素最多 "i32 -9223372036854775808, " 约 26 字符
|
||
# 按数组声明长度 arr_count 计算(元素不足时补零,可能多于 elts_count)
|
||
cnt_total: t.CSizeT = t.CSizeT(arr_count)
|
||
buf_size: t.CSizeT = 64 + cnt_total * 32
|
||
buf: str = pool.alloc(buf_size)
|
||
if buf is None:
|
||
return None
|
||
|
||
# 写入前缀: "["(类型前缀由 _print_global 输出,初始化器只需元素列表)
|
||
written: t.CInt = viperlib.snprintf(buf, buf_size, "[")
|
||
pos: t.CSizeT = t.CSizeT(written)
|
||
|
||
# 逐个元素写入:元素数必须与数组声明长度 arr_count 一致,
|
||
# 列表元素不足时补零(如 g_arr: t.CArray[t.CInt, 4] = [0] →
|
||
# [i32 0, i32 0, i32 0, i32 0]),否则 llc 报
|
||
# "constant expression type mismatch: got type '[1 x i32]' but expected '[4 x i32]'"
|
||
i: t.CSizeT = 0
|
||
while i < cnt_total:
|
||
elem_val: t.CInt64T = 0
|
||
if i < elts_count:
|
||
elem_node: ast.AST | t.CPtr = elts.get(i)
|
||
# 直接从 Constant 节点提取 int_val(避免 extract_cdefine_int_value 的 t.CInt 截断)
|
||
if elem_node is not None:
|
||
ek: int = elem_node.kind()
|
||
if ek == ast.ASTKind.Constant:
|
||
ec: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(elem_node)
|
||
# CONST_CHAR 字符字面量(如 `_ps2_set1 = ['\x1b', '1', ...]`):
|
||
# int_val 即字符码,此前只认 CONST_INT → 字符元素被跳过全编成
|
||
# 0(128 字节 PS/2 扫描码表全 0 → 键盘输入失效根因)。
|
||
if ec is not None and (ec.const_kind == ast.CONST_INT or ec.const_kind == ast.CONST_CHAR):
|
||
elem_val = ec.int_val
|
||
# CONST_STR 单字符(双引号如 "'" / '"'):parser 把双引号
|
||
# 一律判为 CONST_STR(见 ast/parser.vp 字符串常量判定),
|
||
# 此前只认 CONST_INT/CONST_CHAR → 双引号单字符元素被编成 0
|
||
# (keyboard.vp scancode_set1[40]='\'' 、scancode_set1_shift[40]
|
||
# ='"' 丢失根因;A2 的修复只覆盖了单引号字符)。
|
||
# strlen == 1 时取首字符码;多字符字符串无法表达为整型元素
|
||
# → 保持 0(由下方按声明长度补零)。
|
||
elif ec is not None and ec.const_kind == ast.CONST_STR:
|
||
if ec.str_val is not None and string.strlen(ec.str_val) == 1:
|
||
elem_val = t.CInt64T(ec.str_val[0])
|
||
elif ek == ast.ASTKind.UnaryOp:
|
||
# 负数: UnaryOp(USub, Constant)
|
||
elem_val = self.Gen.AssignGen.extract_cdefine_int_value(elem_node)
|
||
if i > 0:
|
||
written = viperlib.snprintf(buf + pos, buf_size - pos, ", ")
|
||
pos += t.CSizeT(written)
|
||
written = viperlib.snprintf(buf + pos, buf_size - pos, "%s %lld", elem_ir_ty, elem_val)
|
||
pos += t.CSizeT(written)
|
||
i += 1
|
||
|
||
# 写入后缀 "]"
|
||
viperlib.snprintf(buf + pos, buf_size - pos, "]")
|
||
return buf
|
||
|
||
# ============================================================
|
||
# _build_string_array_initializer_text - 字符串字面量初始化数组全局
|
||
#
|
||
# t.CArray[t.CChar, N] = "..." → [i8 b0, i8 b1, ..., i8 0, ...]
|
||
# (字符串字节 + 零填充到数组长度;空串返回 zeroinitializer)。
|
||
# 此前统一走字符串指针 GEP 初始化器 → @g = global [N x i8] <ptr>
|
||
# 类型不匹配(llc constant expression type mismatch,
|
||
# pyzlib_error_msg = global [512 x i8] <GEP ptr> 根因)。
|
||
# ============================================================
|
||
def _build_string_array_initializer_text(self, pool: memhub.MemBuddy | t.CPtr,
|
||
var_ty: llvmlite.LLVMType | t.CPtr,
|
||
str_val: str) -> str:
|
||
"""字符串字面量初始化数组全局,返回初始化器文本或 None"""
|
||
if var_ty is None or str_val is None:
|
||
return None
|
||
arr_count: t.CInt = 0
|
||
match var_ty:
|
||
case llvmlite.LLVMType.Array(_, cnt):
|
||
arr_count = cnt
|
||
if arr_count <= 0:
|
||
return None
|
||
slen: t.CSizeT = string.strlen(str_val)
|
||
if slen == 0:
|
||
return "zeroinitializer"
|
||
buf_size: t.CSizeT = 64 + t.CSizeT(arr_count) * 16
|
||
buf: str = pool.alloc(buf_size)
|
||
if buf is None:
|
||
return None
|
||
written: t.CInt = viperlib.snprintf(buf, buf_size, "[")
|
||
pos: t.CSizeT = t.CSizeT(written)
|
||
i: t.CSizeT = 0
|
||
while i < t.CSizeT(arr_count):
|
||
if i > 0:
|
||
written = viperlib.snprintf(buf + pos, buf_size - pos, ", ")
|
||
pos += t.CSizeT(written)
|
||
bv: t.CInt64T = 0
|
||
if i < slen:
|
||
bv = t.CInt64T(str_val[i])
|
||
written = viperlib.snprintf(buf + pos, buf_size - pos, "i8 %lld", bv)
|
||
pos += t.CSizeT(written)
|
||
i += 1
|
||
viperlib.snprintf(buf + pos, buf_size - pos, "]")
|
||
return buf
|
||
|
||
# ============================================================
|
||
# _build_string_ptr_initializer - 为字符串字面量初始化指针类型全局变量
|
||
#
|
||
# 创建内部字符串常量全局 @.str.{var_name} = private constant [len+1 x i8] c"...\00"
|
||
# 返回 GEP 初始化器文本: getelementptr inbounds ([len+1 x i8], [len+1 x i8]* @.str.{var_name}, i32 0, i32 0)
|
||
# 用于 b64_tab: t.CArray[t.CChar, None] = "ABC..." 等字符串初始化指针类型
|
||
# ============================================================
|
||
def _build_string_ptr_initializer(self, pool: memhub.MemBuddy | t.CPtr,
|
||
mod: llvmlite.LLVMModule | t.CPtr,
|
||
var_name: str,
|
||
str_val: str) -> str:
|
||
"""为字符串字面量创建内部常量全局并返回 GEP 初始化器文本,None 失败"""
|
||
if str_val is None or var_name is None:
|
||
return None
|
||
|
||
# 构造内部字符串常量名称: .str.{var_name}
|
||
str_name_buf: str = pool.alloc(64)
|
||
if str_name_buf is None:
|
||
return None
|
||
viperlib.snprintf(str_name_buf, 64, ".str.%s", var_name)
|
||
|
||
# 调用 llvmlite.create_global_string 创建字符串常量全局
|
||
str_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.create_global_string(
|
||
pool, mod, str_name_buf, str_val)
|
||
if str_gv is None:
|
||
return None
|
||
|
||
# 生成 GEP 初始化器文本
|
||
str_len: t.CSizeT = string.strlen(str_val)
|
||
init_buf: str = pool.alloc(128)
|
||
if init_buf is None:
|
||
return None
|
||
viperlib.snprintf(init_buf, 128,
|
||
"getelementptr inbounds ([%d x i8], [%d x i8]* @%s, i32 0, i32 0)",
|
||
str_len + 1, str_len + 1, str_name_buf)
|
||
return init_buf
|
||
|
||
def _stg_field_zero_text(self, pool: memhub.MemBuddy | t.CPtr,
|
||
fty: llvmlite.LLVMType | t.CPtr,
|
||
ty_str: str) -> str:
|
||
"""按 LLVM 类型生成 storage struct 字段的零值初始化器文本
|
||
|
||
LLVM struct 初始化器必须列全所有字段(部分初始化 llc 报
|
||
"initializer with struct type has wrong # elements")。
|
||
Ptr→null、Int→0、Float→0.0、Array/Struct→zeroinitializer。
|
||
"""
|
||
if fty is None or ty_str is None:
|
||
return None
|
||
buf: str = pool.alloc(160)
|
||
if buf is None:
|
||
return None
|
||
match fty:
|
||
case llvmlite.LLVMType.Ptr(_):
|
||
viperlib.snprintf(buf, 160, "%s null", ty_str)
|
||
case llvmlite.LLVMType.Int(_):
|
||
viperlib.snprintf(buf, 160, "%s 0", ty_str)
|
||
case llvmlite.LLVMType.Float(_):
|
||
viperlib.snprintf(buf, 160, "%s 0.0", ty_str)
|
||
case _:
|
||
# Array / Struct 等 aggregate → zeroinitializer
|
||
viperlib.snprintf(buf, 160, "%s zeroinitializer", ty_str)
|
||
return buf
|
||
|
||
# ============================================================
|
||
# _default_val_const_text - 字段默认值 → LLVM 常量元素文本
|
||
#
|
||
# 仅处理可常量折叠的整型默认值(CONST_INT/CONST_CHAR 及负号字面量);
|
||
# 其余(浮点/字符串/None/名字/表达式)返回 None,由调用方按零值兜底。
|
||
# ============================================================
|
||
def _default_val_const_text(self, pool: memhub.MemBuddy | t.CPtr,
|
||
fty: llvmlite.LLVMType | t.CPtr,
|
||
ty_str: str,
|
||
dval: ast.AST | t.CPtr) -> str:
|
||
"""字段默认值 → "ty 值" 文本;不可折叠返回 None"""
|
||
if dval is None or fty is None or ty_str is None:
|
||
return None
|
||
is_int: int = 0
|
||
dv_int: t.CInt64T = 0
|
||
if dval.kind() == ast.ASTKind.Constant:
|
||
dc: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(dval)
|
||
if dc is not None:
|
||
if dc.const_kind == ast.CONST_INT or dc.const_kind == ast.CONST_CHAR:
|
||
dv_int = dc.int_val
|
||
is_int = 1
|
||
elif dval.kind() == ast.ASTKind.UnaryOp:
|
||
# 负数/按位取反字面量(如 -1 / 0xFFFFFFFFFFFFFFFF)
|
||
dv_int = self.Gen.AssignGen.extract_cdefine_int_value(dval)
|
||
is_int = 1
|
||
if is_int == 0:
|
||
return None
|
||
# 仅整型字段可写整数常量(浮点/指针/聚合交给零值兜底)
|
||
match fty:
|
||
case llvmlite.LLVMType.Int(_):
|
||
pass
|
||
case _:
|
||
return None
|
||
buf: str = pool.alloc(48)
|
||
if buf is None:
|
||
return None
|
||
viperlib.snprintf(buf, 48, "%s %lld", ty_str, dv_int)
|
||
return buf
|
||
|
||
# ============================================================
|
||
# _build_stg_struct_init_text - storage struct 完整常量初始化器(含字段默认值)
|
||
#
|
||
# 用于模块级对象全局 `X: T = T()`:此前 storage 一律 zeroinitializer,
|
||
# `__before_init__`/字段默认(如 fat32.volinfo 的 sector_size=512、
|
||
# root_cluster=2、free_clusters=0xFFFFFFFF、backup_sector=6)全部丢失。
|
||
# 现按字段默认值生成完整 struct 常量(LLVM 要求列全每个字段)。
|
||
# 无任何非零默认值时返回 None,由调用方保持 zeroinitializer(避免无谓文本)。
|
||
# start_idx:vtable 对象跳过字段 0(首元素由调用方单独写 vtable 指针)。
|
||
# ============================================================
|
||
def _build_stg_struct_init_text(self, pool: memhub.MemBuddy | t.CPtr,
|
||
se: GenTypes.StructEntry | t.CPtr,
|
||
start_idx: int) -> str:
|
||
"""按字段默认值生成完整 struct 初始化器;无非零默认值返回 None"""
|
||
if se is None or se.Fields is None:
|
||
return None
|
||
fc: int = se.FieldCount
|
||
if fc <= start_idx:
|
||
return None
|
||
buf_size: t.CSizeT = 256 + t.CSizeT(fc) * 160
|
||
buf: str = pool.alloc(buf_size)
|
||
if buf is None:
|
||
return None
|
||
written: t.CInt = viperlib.snprintf(buf, buf_size, "{ ")
|
||
pos: t.CSizeT = t.CSizeT(written)
|
||
first: int = 1
|
||
has_nonzero: int = 0
|
||
i: int = start_idx
|
||
while i < fc:
|
||
fe: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry(se, i)
|
||
i += 1
|
||
if fe is None or fe.Ty is None:
|
||
continue
|
||
ty_str: str = pool.alloc(128)
|
||
if ty_str is None:
|
||
continue
|
||
llvmlite.TypePrint(ty_str, 128, fe.Ty, pool)
|
||
elem: str = self._default_val_const_text(pool, fe.Ty, ty_str, fe.DefaultVal)
|
||
is_zero: int = 0
|
||
if elem is None:
|
||
elem = self._stg_field_zero_text(pool, fe.Ty, ty_str)
|
||
is_zero = 1
|
||
if elem is None:
|
||
continue
|
||
if first == 0:
|
||
written = viperlib.snprintf(buf + pos, buf_size - pos, ", ")
|
||
pos += t.CSizeT(written)
|
||
written = viperlib.snprintf(buf + pos, buf_size - pos, "%s", elem)
|
||
pos += t.CSizeT(written)
|
||
first = 0
|
||
if is_zero == 0:
|
||
has_nonzero = 1
|
||
if has_nonzero == 0:
|
||
return None
|
||
viperlib.snprintf(buf + pos, buf_size - pos, " }")
|
||
return buf
|
||
|
||
# ============================================================
|
||
# handle_module_level_var - 模块级变量声明 → 创建 LLVM 全局变量
|
||
#
|
||
# 当用户已定义 main(无 wrapper main builder)时,模块级
|
||
# AnnAssign/Assign 创建全局变量 @var_name 并注册到 SymTab 模块作用域
|
||
# 支持整数、列表字面量、字符串字面量初始值
|
||
# ============================================================
|
||
def handle_module_level_var(self, trans: HT.Translator | t.CPtr,
|
||
node: ast.AST | t.CPtr) -> int:
|
||
"""处理模块级变量声明,创建全局变量"""
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||
|
||
# CDefine 注解: 编译期常量,不创建全局变量
|
||
# 注册到全局 CDefine 表供 t.CArray[elem_ty, NAME] 解析
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.AnnAssign:
|
||
aa_cd: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||
if aa_cd is not None and aa_cd.target is not None:
|
||
if aa_cd.target.kind() == ast.ASTKind.Name:
|
||
nm_cd: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa_cd.target)
|
||
if nm_cd.id is not None:
|
||
if self.Gen.AssignGen.is_cdefine_annotation(aa_cd.annotation) != 0:
|
||
# 浮点/整数自动识别注册(浮点 CDefine 如 vipermath U_M_PI)
|
||
self.Gen.AssignGen._register_cdefine_from_value(
|
||
pool, nm_cd.id, aa_cd.value)
|
||
return 0
|
||
# CTypedef 注解(如 posix.vp mode_t: t.CTypedef = t.CUInt32T):
|
||
# 不创建全局变量——否则生成 @mode_t 符号 → 链接 duplicate
|
||
# symbol warning。预注册阶段(forward_declare_functions
|
||
# 之前)按需注册到 CTypedef 表:翻译期表已被 clear_ctypedefs
|
||
# 清空(每文件隔离),若不在此时注册,S_ISREG(mode: mode_t)
|
||
# 等函数参数注解在 FuncGenDef 正式翻译时查表失败 →
|
||
# NameError: mode_t(AstTest/posix.vp 根因;模块级 AnnAssign
|
||
# 经本函数分派,不经过 AnnAssignHandle.Handle 的注册分支)。
|
||
if self.Gen.TypeGenCType._is_ctypedef_annotation(aa_cd.annotation) != 0:
|
||
ctd_str: str = self.Gen.TypeGenResolve._get_type_name_from_annotation(
|
||
pool, aa_cd.value)
|
||
if ctd_str is not None:
|
||
self.Gen.TypeGenCType.register_ctypedef(pool, nm_cd.id, ctd_str)
|
||
return 0
|
||
|
||
# _declare_only=1(struct注册模式)时只处理 CDefine,不创建全局变量
|
||
# CDefine 已在上面处理并返回,到这里说明不是 CDefine,直接跳过
|
||
if trans._declare_only == 1:
|
||
return 0
|
||
|
||
var_name: str = None
|
||
var_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Int32(pool)
|
||
resolved_stg_ty: llvmlite.LLVMType | t.CPtr = None # 对象类全局:静态 storage 类型(BSS 实例)
|
||
resolved_stg_entry: GenTypes.StructEntry | t.CPtr = None # 对象类全局:对应 StructEntry(vtable 初始化用)
|
||
init_val: t.CInt64T = 0
|
||
init_fval: t.CDouble = 0.0 # init_kind==4(浮点字面量)时的数值
|
||
init_kind: int = 0 # 0=none, 1=int, 2=list, 3=str, 4=float
|
||
init_str_val: str = None
|
||
init_list_node: ast.List | t.CPtr = None
|
||
# = None 显式初始化(如 tokens.vp `_kw_head: KwEntry | t.CPtr = None`):
|
||
# 对象类全局的懒初始化指针语义——必须保持 NULL,不能创建 BSS storage
|
||
# (storage 会让 @g = &g.stg 恒非 NULL,破坏 `if _kw_head != None` 懒初始化
|
||
# 守卫 → _init_keywords 永不执行 → _kw_lookup 遍历零存储 strcmp(NULL) 崩溃,
|
||
# 二代自举 1.log ASan 根因;_op_head/_kw_pool 同款模式一并修复)。
|
||
is_none_init: int = 0
|
||
annot_node: ast.AST | t.CPtr = None # 类型注解节点(检测 t.CExport 标记)
|
||
|
||
if k == ast.ASTKind.AnnAssign:
|
||
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||
if aa is None or aa.target is None:
|
||
return 0
|
||
if aa.target.kind() != ast.ASTKind.Name:
|
||
return 0
|
||
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa.target)
|
||
var_name = nm.id
|
||
annot_node = aa.annotation
|
||
# 解析类型
|
||
if aa.annotation is not None:
|
||
resolved: llvmlite.LLVMType | t.CPtr = self.Gen.TypeGenResolve.resolve_annotation_type(
|
||
pool, aa.annotation, trans._imported_modules, trans._from_imports, trans, 0)
|
||
if resolved is not None:
|
||
# 对象类模块级变量(@t.Object/@t.CVTable:对象即指针)→ Ptr(struct)。
|
||
# 裸类名注解 resolve 返回 struct 值(参数层 FuncGenDef 会包装 Ptr,
|
||
# 模块级变量此处缺包装)→ 若建成值实例,跨模块字段访问/虚表调用
|
||
# 按指针处理读首 8 字节当 vtable → 垃圾地址 #PF(devfs.vp
|
||
# serial0_file.open = serial0_open 根因)。纯 t.CStruct(无方法
|
||
# 无虚表无 __new__,如 pci_device)保持值实例。
|
||
if resolved.kind() == llvmlite.LLVMType.Struct:
|
||
gv_entry: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_type(resolved)
|
||
if gv_entry is not None \
|
||
and (gv_entry.HasNew != 0 or gv_entry.HasVTable != 0 or gv_entry.IsOOP != 0):
|
||
# 对象类全局(裸类名注解 → 对象即指针):记录原 Struct 值类型,
|
||
# 用于创建静态 storage 全局承载对象实例(BSS)。
|
||
# 否则 @g = global T* zeroinitializer → NULL → 对象字段落在
|
||
# 物理页 0(IVT+BDA 混叠),devfs/fat32/sched 全部对象失效根因。
|
||
resolved_stg_ty = resolved
|
||
resolved_stg_entry = gv_entry
|
||
resolved = llvmlite.Ptr(pool, resolved)
|
||
elif resolved.kind() == llvmlite.LLVMType.Ptr:
|
||
# 对象类联合注解(T | t.CPtr → T*,如 Gargantua `_v3_pool:
|
||
# memhub.MemPool | t.CPtr`、`CAM: V3 | t.CPtr`):同样创建 storage。
|
||
# 否则 @g = global T* null → 入口/方法虚调用 load @g 得 NULL →
|
||
# 读 [NULL] 拿 vtable → #PF cr2=0x0(Gargantua/Terminal 启动即崩根因)。
|
||
# var_ty 保持 Ptr(联合注解语义:指针全局),storage 承载对象实例。
|
||
pointee_uv: llvmlite.LLVMType | t.CPtr = resolved.Pointee
|
||
if pointee_uv is not None and pointee_uv.kind() == llvmlite.LLVMType.Struct:
|
||
gv_entry_u: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_type(pointee_uv)
|
||
if gv_entry_u is not None \
|
||
and (gv_entry_u.HasNew != 0 or gv_entry_u.HasVTable != 0 or gv_entry_u.IsOOP != 0):
|
||
resolved_stg_ty = pointee_uv
|
||
resolved_stg_entry = gv_entry_u
|
||
var_ty = resolved
|
||
# 解析初始值(支持整数、负数字面量、列表字面量、字符串字面量)
|
||
if aa.value is not None:
|
||
val_kind: int = aa.value.kind()
|
||
if val_kind == ast.ASTKind.Constant:
|
||
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(aa.value)
|
||
if cn.const_kind == ast.CONST_NONE:
|
||
is_none_init = 1
|
||
elif cn.const_kind == ast.CONST_INT:
|
||
init_val = cn.int_val
|
||
init_kind = 1
|
||
elif cn.const_kind == ast.CONST_STR:
|
||
init_str_val = cn.str_val
|
||
init_kind = 3
|
||
elif cn.const_kind == ast.CONST_FLOAT:
|
||
# 浮点字面量(如 torch `LCG_M: t.CDouble = 2147483647.0`):
|
||
# 此前无此分支 → init_kind 保持 0 → 全局退化成
|
||
# zeroinitializer,初始化值整体丢失(负数 -1 补在 UnaryOp
|
||
# 分支是同一类漏项)。数值不在此处取 AST 的 float_val,
|
||
# 见下方 init_kind==4 的源文件恢复逻辑。
|
||
init_kind = 4
|
||
elif val_kind == ast.ASTKind.UnaryOp:
|
||
# 负数/按位取反字面量(如 `_vblank_ok: t.CInt = -1`):
|
||
# AST 是 UnaryOp(USub, Constant),此前未处理 → init_kind 保持 0
|
||
# → 全局编译成 zeroinitializer(desktop 7 个 -1 初始化全部丢失
|
||
# → _drag_idx=0 无条件拖拽窗口 0 / _focused_win=0 事件错路由根因)。
|
||
init_val = self.Gen.AssignGen.extract_cdefine_int_value(aa.value)
|
||
init_kind = 1
|
||
elif val_kind == ast.ASTKind.List:
|
||
init_list_node = (ast.List | t.CPtr)(aa.value)
|
||
init_kind = 2
|
||
elif k == ast.ASTKind.Assign:
|
||
asgn: ast.Assign | t.CPtr = (ast.Assign | t.CPtr)(node)
|
||
if asgn is None or asgn.targets is None:
|
||
return 0
|
||
targets: list[ast.AST | t.CPtr] | t.CPtr = asgn.targets
|
||
if len(targets) < 1:
|
||
return 0
|
||
t0: ast.AST | t.CPtr = targets.get(0)
|
||
if t0 is None or t0.kind() != ast.ASTKind.Name:
|
||
return 0
|
||
nm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(t0)
|
||
var_name = nm2.id
|
||
if asgn.value is not None:
|
||
val_kind2: int = asgn.value.kind()
|
||
if val_kind2 == ast.ASTKind.Constant:
|
||
cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(asgn.value)
|
||
if cn2.const_kind == ast.CONST_NONE:
|
||
is_none_init = 1
|
||
elif cn2.const_kind == ast.CONST_INT:
|
||
init_val = cn2.int_val
|
||
init_kind = 1
|
||
elif cn2.const_kind == ast.CONST_STR:
|
||
init_str_val = cn2.str_val
|
||
init_kind = 3
|
||
elif cn2.const_kind == ast.CONST_FLOAT:
|
||
# 无注解的模块级浮点赋值:字面量本身即类型依据,提升为 double
|
||
# (默认 var_ty 是 i32,不提升会把浮点位模式写进 i32 全局)
|
||
init_kind = 4
|
||
var_ty = llvmlite.Double(pool)
|
||
elif val_kind2 == ast.ASTKind.UnaryOp:
|
||
# 负数字面量(同 AnnAssign 分支,见上):UnaryOp(USub, Constant)
|
||
init_val = self.Gen.AssignGen.extract_cdefine_int_value(asgn.value)
|
||
init_kind = 1
|
||
elif val_kind2 == ast.ASTKind.List:
|
||
init_list_node = (ast.List | t.CPtr)(asgn.value)
|
||
init_kind = 2
|
||
elif val_kind2 == ast.ASTKind.Attribute:
|
||
# 模块级 re-export 别名(如 fat32_core.vp `_read32 = types._read32`、
|
||
# fat32_dir.vp/fat32_file.vp 的同型 shim):RHS 是函数/实体引用,
|
||
# 无值语义可落入 LLVM 全局。此前未识别 → var_ty 默认 i32 →
|
||
# 生成假符号 `global i32 zeroinitializer`(被引用即调用地址 0)。
|
||
# 与 __all__ 同类:别名/元数据实体不产出 LLVM 全局(详见 L693)。
|
||
# 真正的函数别名机制(可调用 + 可 re-export)属独立特性,待后续实现。
|
||
return 0
|
||
|
||
if var_name is None:
|
||
return 0
|
||
|
||
# __all__ 是 Python 模块元数据(公开名列表),无运行时语义:
|
||
# StubGen 的 .vpi 不为其生成 stub 声明(无注解模块级赋值不产出 vpi
|
||
# 条目),此处同样跳过全局创建——否则无注解 list-of-strings 全局
|
||
# 类型推断缺失(var_ty 默认 i32)→ _build_array_initializer_text
|
||
# 返回 None → fail-fast "初始化器构建失败" 误报
|
||
# (Projectrans/__init__.vp 追加83 根因)。与 CDefine/CTypedef
|
||
# 同类:编译期/元数据实体不落入 LLVM 全局。
|
||
if string.strcmp(var_name, "__all__") == 0:
|
||
return 0
|
||
|
||
# 浮点字面量初始化(init_kind==4):数值一律从当前源文件按变量名重读,
|
||
# 不用 AST 节点的 float_val —— 该字段可能被后续 pool 操作覆写,且跨模块
|
||
# double 返回值传递本身有缺陷(详见 AssignGenMixin._recover_float_literal)。
|
||
# 同时校验注解类型:注解不是浮点却给浮点字面量属类型错误,直接终止,
|
||
# 不静默零初始化。
|
||
if init_kind == 4:
|
||
is_fty_g: int = 0
|
||
match var_ty:
|
||
case llvmlite.LLVMType.Float(_):
|
||
is_fty_g = 1
|
||
case _:
|
||
pass
|
||
if is_fty_g == 0:
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
node, f"模块级变量 '{var_name}' 用浮点字面量初始化,但注解不是浮点类型",
|
||
"TypeError")
|
||
return 0
|
||
if self.Gen.AssignGen._recover_float_literal(
|
||
var_name, t.CPtr(c.Addr(init_fval)), 0) != 1:
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
node, f"模块级浮点变量 '{var_name}' 初始化值源文件恢复失败",
|
||
"InternalCompilerError")
|
||
return 0
|
||
|
||
# 检查是否已注册
|
||
existing: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_module_var(
|
||
trans.SymTab, var_name)
|
||
if existing is not None:
|
||
return 0
|
||
|
||
# 创建全局变量 @var_name
|
||
# 先确保 var_ty 中的跨模块结构体类型在模块中有 opaque 声明
|
||
# 否则 @var_name = global %"sha1.ClassName"* zeroinitializer 会报
|
||
# "use of undefined type named 'sha1.ClassName'" 错误
|
||
# (如 _mbuddy: memhub.MemManager | t.CPtr → Ptr(Struct("aeb3...MemManager")))
|
||
llvmlite.module_ensure_opaque_for_type(mod, pool, var_ty)
|
||
# 模块级全局命名带 SHA1 前缀(对齐函数名 mangling):多个模块声明同名
|
||
# 全局(如 _mbuddy)时各自独立命名,消除 ld.lld duplicate symbol。
|
||
# SymTab 注册 key 保持裸名(查找逻辑零改动),LLVM 符号名用 mangled 名。
|
||
# t.CExport 标记的全局用裸名(内联汇编引用 / 外部符号对接,如
|
||
# VKernel gdt/gp/_switch_old_rsp/_coro_* 被 c.Asm 引用,带 SHA1 前缀
|
||
# 无法在 LLVM MC 中解析)。
|
||
is_global_cexport: int = 0
|
||
if annot_node is not None:
|
||
is_global_cexport = self.Gen.TypeGenErr.has_decorator_marker(
|
||
annot_node, "CExport", 0)
|
||
mangled_name: str = var_name
|
||
if is_global_cexport == 0:
|
||
mangled_name = self.Gen.FuncGenBase._mangle_name(trans, var_name)
|
||
gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(pool, mangled_name, var_ty)
|
||
if gv is None:
|
||
return 0
|
||
llvmlite.module_add_global(mod, gv)
|
||
|
||
# B5:@c.Attribute(t.attr.aligned(N)) 类的全局实例施加对齐(如 fpu_context 16 对齐,
|
||
# FXSAVE 区域要求 16 字节对齐,否则 fxsave/fxrstor #GP)。
|
||
al_ty: llvmlite.LLVMType | t.CPtr = var_ty
|
||
match var_ty:
|
||
case llvmlite.LLVMType.Ptr(pointee_al):
|
||
al_ty = pointee_al
|
||
case _:
|
||
pass
|
||
al_entry: GenTypes.StructEntry | t.CPtr = None
|
||
if al_ty is not None and al_ty.kind() == llvmlite.LLVMType.Struct:
|
||
al_entry = self.Gen.StructGen.find_struct_by_type(al_ty)
|
||
if al_entry is not None and al_entry.Align > 0:
|
||
gv.Align = al_entry.Align
|
||
|
||
# 设置初始值(有初始值时清除 external linkage,因为 LLVM 22+ 不允许 external global 带初始值)
|
||
gv.Linkage = None
|
||
if init_kind == 1:
|
||
# 整数初始值
|
||
init_buf: str = pool.alloc(48)
|
||
if init_buf is not None:
|
||
viperlib.snprintf(init_buf, 48, "%lld", init_val)
|
||
gv.Initializer = init_buf
|
||
elif init_kind == 2:
|
||
# 列表字面量 → 数组初始化器 [N x elem_ty] [elem_ty val0, ...]
|
||
arr_init: str = self._build_array_initializer_text(pool, var_ty, init_list_node)
|
||
if arr_init is not None:
|
||
gv.Initializer = arr_init
|
||
else:
|
||
# 初始化器构建失败:直接报错终止(fail-fast),不再回退 zeroinitializer
|
||
self.Gen.TypeGenErr.fatal_error(node, f"模块级变量 '{var_name}' 初始化器构建失败", "TypeError")
|
||
elif init_kind == 3:
|
||
# 字符串字面量初始化
|
||
# 数组类型(t.CArray[t.CChar, N]):字节数组初始化器(字符串内容 + 零填充)
|
||
# ——此前统一走字符串指针 GEP 初始化器 → @g = global [N x i8] <ptr> 类型
|
||
# 不匹配(llc constant expression type mismatch,pyzlib_error_msg 根因)
|
||
is_arr_g: int = 0
|
||
match var_ty:
|
||
case llvmlite.LLVMType.Array(_, _):
|
||
is_arr_g = 1
|
||
case _:
|
||
pass
|
||
if is_arr_g != 0:
|
||
arr_str_init: str = self._build_string_array_initializer_text(
|
||
pool, var_ty, init_str_val)
|
||
if arr_str_init is not None:
|
||
gv.Initializer = arr_str_init
|
||
else:
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
node, f"模块级数组变量 '{var_name}' 字符串初始化器构建失败", "TypeError")
|
||
else:
|
||
# 指针类型(如 b64_tab: t.CArray[t.CChar, None] = "ABC..."):
|
||
# 创建字符串常量全局 + GEP 引用
|
||
str_init: str = self._build_string_ptr_initializer(pool, mod, var_name, init_str_val)
|
||
if str_init is not None:
|
||
gv.Initializer = str_init
|
||
else:
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
node, f"模块级变量 '{var_name}' 初始化器构建失败", "TypeError")
|
||
elif init_kind == 4:
|
||
# 浮点初始值:LLVM IR 的浮点常量必须写成位模式文本(0x%016llx / 0x%08x)。
|
||
# 十进制文本经 llc 解析对部分值有 ±1 ulp 误差(见 llvmlite.ConstFloat 注释)。
|
||
# 此前 init_kind 没有浮点分支 → 模块级 t.CDouble 全局一律退化成
|
||
# zeroinitializer(torch 的 LCG_A/LCG_M/_rng_state 全变 0 →
|
||
# _next_rand() 得到 0.0/0.0 = NaN → Kaiming 初始化写入全 NaN 权重 →
|
||
# 推理 softmax 分母 NaN → 十个概率全为 0 的根因链)。
|
||
fc_g: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, var_ty, init_fval)
|
||
if fc_g is not None and fc_g.Name is not None:
|
||
gv.Initializer = fc_g.Name
|
||
else:
|
||
self.Gen.TypeGenErr.fatal_error(
|
||
node, f"模块级变量 '{var_name}' 浮点初始化器构建失败", "TypeError")
|
||
else:
|
||
# 使用 zeroinitializer 而非 "0":指针类型必须用 null/zeroinitializer,
|
||
# 整数/聚合类型也兼容 zeroinitializer,避免 "integer constant must have integer type"
|
||
# 对象类全局(有 storage)的 Initializer 由下方 storage 逻辑设为 &@storage,
|
||
# 此处不覆盖;但 = None 懒初始化全局(is_none_init)既无 storage 也无其他
|
||
# Initializer → 必须显式 zeroinitializer(LLVM 对指针类型输出为 null),
|
||
# 否则 gv 无初始化器 → 全局声明残缺。
|
||
if resolved_stg_ty is None or is_none_init != 0:
|
||
gv.Initializer = "zeroinitializer"
|
||
|
||
# 对象类全局:创建静态 storage 全局(BSS)承载对象实例,@g 编译期引用它。
|
||
# 函数内 `g = T()` 构造时把对象复制到 storage(见 AssignGenMixin 全局分支),
|
||
# 不再依赖栈 alloca(悬垂);c.Addr(g) load @g 得到 &storage,均非 NULL。
|
||
# 豁免:显式 `= None` 初始化(is_none_init)的懒初始化指针全局
|
||
# (如 _kw_head/_op_head)不建 storage,保持 NULL 语义。
|
||
if resolved_stg_ty is not None and is_none_init == 0:
|
||
# 值类型 storage 需要完整 struct 定义(跨模块类默认 opaque →
|
||
# @g.stg = global %T zeroinitializer 报 "use of undefined type")
|
||
self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, resolved_stg_ty)
|
||
# @t.CVTable 对象类:storage 首字段(vtable 指针,偏移 0)初始化为 vtable 地址。
|
||
# 否则 zeroinitializer → vtable=0 → 模块级全局对象(如用户程序 vpsdk 对象)
|
||
# 入口虚调用 call [vtable+0x10] → 跳 0x0 #PF(HelloWorld 启动即崩根因)。
|
||
# @t.Object(无 CVTable)/普通对象:保持 zeroinitializer(无 vtable 需求)。
|
||
stg_init_text: str = "zeroinitializer"
|
||
if resolved_stg_entry is not None and resolved_stg_entry.Name is not None \
|
||
and resolved_stg_entry.HasVTable != 0:
|
||
vt_name_buf: str = pool.alloc(128)
|
||
if vt_name_buf is not None:
|
||
viperlib.snprintf(vt_name_buf, 128, "%s.vtable", resolved_stg_entry.Name)
|
||
# [FIX 2026-08-31] vtable 符号前缀必须用类定义模块的 sha1
|
||
# (对齐 CallGenLeafKit._make_vtable_ref_i8)。此前用当前模块
|
||
# _mangle_name → 跨模块对象类全局(如 Translator 模块的
|
||
# _mbuddy: memhub.MemBuddy)storage 初始化引用
|
||
# "@当前sha1.MemBuddy.vtable",而 vtable 实为定义模块
|
||
# 的 "@7e4672b992208969.MemBuddy.vtable" → llc 报
|
||
# "use of undefined value"(eba110fc7acac3e6.ll:7999 根因)。
|
||
# resolved_stg_entry.ModuleSha1 即定义模块,比 get_struct_sha1
|
||
# 裸名反查更精确(避免跨模块同名类歧义)。
|
||
vt_sha1: str = None
|
||
if resolved_stg_entry.ModuleSha1 is not None:
|
||
vt_sha1 = resolved_stg_entry.ModuleSha1
|
||
if vt_sha1 is None:
|
||
vt_sha1 = trans.ModuleSha1
|
||
vt_mangled: str = self.Gen.FuncGenBase._mangle_name_with_sha1(
|
||
vt_sha1, vt_name_buf)
|
||
if vt_mangled is not None:
|
||
# 完整 struct 初始化器(LLVM 拒绝部分初始化):
|
||
# 字段 0 = __vtable__(i8* @vtable),其余用户字段按类型零值。
|
||
init_full_len: t.CSizeT = 16384
|
||
init_full: str = pool.alloc(init_full_len)
|
||
if init_full is not None:
|
||
written_v: t.CInt = viperlib.snprintf(init_full, init_full_len, "{ ")
|
||
pos_v: t.CSizeT = t.CSizeT(written_v)
|
||
if self.Gen.ClassGenVTable._vtable_name_needs_quote(vt_mangled) != 0:
|
||
written_v = viperlib.snprintf(init_full + pos_v, init_full_len - pos_v, "i8* @\"%s\"", vt_mangled)
|
||
else:
|
||
written_v = viperlib.snprintf(init_full + pos_v, init_full_len - pos_v, "i8* @%s", vt_mangled)
|
||
pos_v += t.CSizeT(written_v)
|
||
fc_v: int = resolved_stg_entry.FieldCount
|
||
for fi_v in range(1, fc_v):
|
||
fe_v: GenTypes.FieldEntry | t.CPtr = self.Gen.StructGen._get_field_entry(
|
||
resolved_stg_entry, fi_v)
|
||
if fe_v is None or fe_v.Ty is None:
|
||
continue
|
||
ty_buf_v: str = pool.alloc(128)
|
||
if ty_buf_v is None:
|
||
continue
|
||
llvmlite.TypePrint(ty_buf_v, 128, fe_v.Ty, pool)
|
||
zero_v: str = self._stg_field_zero_text(pool, fe_v.Ty, ty_buf_v)
|
||
if zero_v is None:
|
||
continue
|
||
written_v = viperlib.snprintf(init_full + pos_v, init_full_len - pos_v, ", %s", zero_v)
|
||
pos_v += t.CSizeT(written_v)
|
||
viperlib.snprintf(init_full + pos_v, init_full_len - pos_v, " }")
|
||
stg_init_text = init_full
|
||
elif resolved_stg_entry is not None:
|
||
# 无 vtable 的对象全局(@t.Object / 普通类):按字段默认值生成常量
|
||
# 初始化器(如 fat32.volinfo:sector_size=512、root_cluster=2、
|
||
# free_clusters=0xFFFFFFFF、backup_sector=6、winsect/fat_winsect=-1…)。
|
||
# 此前一律 zeroinitializer → 字段默认全部丢失(模块级 X: T = T() 的
|
||
# 构造调用不发射,见第十三节)。无任何非零默认值时返回 None →
|
||
# 保持 zeroinitializer(drive_lock 等零值等价场景零开销)。
|
||
stg_default_text: str = self._build_stg_struct_init_text(
|
||
pool, resolved_stg_entry, 0)
|
||
if stg_default_text is not None:
|
||
stg_init_text = stg_default_text
|
||
stg_name_len: t.CSizeT = t.CSizeT(string.strlen(mangled_name)) + 8
|
||
stg_name_buf: str = pool.alloc(stg_name_len)
|
||
if stg_name_buf is not None:
|
||
viperlib.snprintf(stg_name_buf, stg_name_len, "%s.stg", mangled_name)
|
||
stg_gv: llvmlite.GlobalVariable | t.CPtr = llvmlite.new_global_variable(
|
||
pool, stg_name_buf, resolved_stg_ty)
|
||
if stg_gv is not None:
|
||
llvmlite.module_add_global(mod, stg_gv)
|
||
stg_gv.Linkage = None
|
||
stg_gv.Initializer = stg_init_text
|
||
# B5:storage(BSS 对象实例)同样施加 aligned 对齐
|
||
if resolved_stg_entry is not None and resolved_stg_entry.Align > 0:
|
||
stg_gv.Align = resolved_stg_entry.Align
|
||
# @g 初始值 = &@storage(对象引用指向 BSS 实例,非 NULL)
|
||
stg_init_len: t.CSizeT = t.CSizeT(string.strlen(mangled_name)) + 8
|
||
stg_init_buf: str = pool.alloc(stg_init_len)
|
||
if stg_init_buf is not None:
|
||
if self.Gen.ClassGenVTable._vtable_name_needs_quote(stg_name_buf) != 0:
|
||
viperlib.snprintf(stg_init_buf, stg_init_len, "@\"%s\"", stg_name_buf)
|
||
else:
|
||
viperlib.snprintf(stg_init_buf, stg_init_len, "@%s", stg_name_buf)
|
||
gv.Initializer = stg_init_buf
|
||
# 注册 storage 引用(key: var_name.__stg),供 AssignGenMixin
|
||
# 全局赋值分支检测对象类全局并复制对象到 storage。
|
||
stg_ref: llvmlite.Value | t.CPtr = self.Gen.ExprGenAttr.make_global_ref(
|
||
pool, stg_name_buf, resolved_stg_ty)
|
||
if stg_ref is not None:
|
||
stg_key_len: t.CSizeT = t.CSizeT(string.strlen(var_name)) + 8
|
||
stg_key: str = pool.alloc(stg_key_len)
|
||
if stg_key is not None:
|
||
viperlib.snprintf(stg_key, stg_key_len, "%s.__stg", var_name)
|
||
self.Gen.VarGen.define_module_var(trans.SymTab, stg_key, stg_ref)
|
||
|
||
# 创建 Value 引用(@mangled_name, 类型为 var_ty*)
|
||
var_ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr(pool, var_ty)
|
||
ref_name: str = pool.alloc(96)
|
||
if ref_name is not None:
|
||
# mangled 名带 SHA1 前缀(数字开头),引用必须加引号(对齐 make_global_ref)
|
||
if self.Gen.ClassGenVTable._vtable_name_needs_quote(mangled_name) != 0:
|
||
viperlib.snprintf(ref_name, 96, "@\"%s\"", mangled_name)
|
||
else:
|
||
viperlib.snprintf(ref_name, 96, "@%s", mangled_name)
|
||
gv_ref: llvmlite.Value | t.CPtr = llvmlite.SSAValue(pool, var_ptr_ty, ref_name)
|
||
|
||
# 注册到模块作用域
|
||
if self.Gen.VarGen.define_module_var(trans.SymTab, var_name, gv_ref) == 0:
|
||
# 设置 AnnotClassName(联合类型如 Logger|t.CPtr 简化为 Ptr(i8) 时,
|
||
# 属性访问需要通过 AnnotClassName 回退到类名查找结构体)
|
||
if k == ast.ASTKind.AnnAssign:
|
||
aa_ml: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(node)
|
||
if aa_ml is not None and aa_ml.annotation is not None:
|
||
cls_nm_ml: str = self.Gen.TypeGenResolve.extract_class_name_from_annotation(
|
||
aa_ml.annotation, trans._imported_modules, pool, trans._from_imports)
|
||
if cls_nm_ml is not None:
|
||
self.Gen.VarGen.set_var_annot_class_name(
|
||
trans.SymTab, var_name, cls_nm_ml)
|
||
# 模块级 str|t.CPtr / bytes|t.CPtr 全局:标记 IsPtrElement
|
||
# (i8** 语义,var[i] 按 8 字节指针步长),对齐 TPC 的
|
||
# global_var_ptr_element(_argv 等字符串指针数组)。否则
|
||
# var[i] 退化为 1 字节字符步长 GEP + load i8 截断指针。
|
||
if aa_ml.annotation.kind() == ast.ASTKind.BinOp:
|
||
bop_ml: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(aa_ml.annotation)
|
||
if bop_ml.op == ast.OpKind.BitOr:
|
||
if self.Gen.AssignGen._annotation_contains_name(
|
||
aa_ml.annotation, "str") != 0 \
|
||
or self.Gen.AssignGen._annotation_contains_name(
|
||
aa_ml.annotation, "bytes") != 0:
|
||
self.Gen.VarGen.set_var_ptr_element(
|
||
trans.SymTab, var_name)
|
||
return 1
|
||
return 0
|
||
|
||
# ============================================================
|
||
# create_wrapper_main - 创建包装 main 函数
|
||
#
|
||
# 当用户未定义 main 函数时调用。
|
||
# 创建 main() -> i32 函数 → 设置 trans._cur_func/_cur_builder →
|
||
# 预扫描 alloca → 翻译子节点 → ret 0
|
||
# ============================================================
|
||
def create_wrapper_main(self, trans: HT.Translator | t.CPtr,
|
||
tree: ast.AST | t.CPtr,
|
||
i32_ty: llvmlite.LLVMType | t.CPtr) -> int:
|
||
"""创建包装 main 函数并翻译所有顶层语句
|
||
|
||
Args:
|
||
trans: 翻译器(含所有共享状态)
|
||
tree: AST 模块节点
|
||
i32_ty: i32 LLVMType
|
||
|
||
Returns:
|
||
t.CInt: 新增的变量数
|
||
"""
|
||
pool: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
mod: llvmlite.LLVMModule | t.CPtr = trans.Module
|
||
|
||
main_func: llvmlite.Function | t.CPtr = llvmlite.create_function(
|
||
pool, mod, "main", i32_ty)
|
||
if main_func is None:
|
||
VLogger.error("CreateFunction main returned NULL", "TR")
|
||
return 0
|
||
|
||
entry_blk: llvmlite.BasicBlock | t.CPtr = llvmlite.create_block(
|
||
pool, main_func, "entry")
|
||
if entry_blk is None:
|
||
VLogger.error("CreateBlock returned NULL", "TR")
|
||
return 0
|
||
|
||
builder: llvmlite.IRBuilder | t.CPtr = llvmlite.new_builder(pool, main_func)
|
||
if builder is None:
|
||
VLogger.error("NewBuilder returned NULL", "TR")
|
||
return 0
|
||
llvmlite.position_at_end(builder, entry_blk)
|
||
|
||
# 设置当前翻译上下文(供 Handle 通过 self.Trans._cur_builder 访问)
|
||
trans._cur_func = main_func
|
||
trans._cur_builder = builder
|
||
|
||
# 预处理模块级变量:为 AnnAssign/Assign 创建 LLVM 全局变量
|
||
# 必须在 pre_scan_allocas 之前执行,否则 PreScan 会创建局部 alloca,
|
||
# 导致其他函数通过 SSA 编号引用 wrapper main 的局部变量(无效 IR)
|
||
ch: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||
if ch is not None:
|
||
cn_count: t.CSizeT = len(ch)
|
||
for ci in range(cn_count):
|
||
child: ast.AST | t.CPtr = ch.get(ci)
|
||
if child is not None:
|
||
kd: int = child.kind()
|
||
if kd == ast.ASTKind.AnnAssign or kd == ast.ASTKind.Assign:
|
||
self.handle_module_level_var(trans, child)
|
||
|
||
# 预扫描顶层语句:为函数内 AnnAssign 提前创建 alloca
|
||
# (模块级变量已在上面注册到模块作用域,PreScan 的 lookup_current 会跳过它们)
|
||
if ch is not None:
|
||
for ci in range(cn_count):
|
||
child: ast.AST | t.CPtr = ch.get(ci)
|
||
if child is not None:
|
||
self.Gen.StmtGenDecl.pre_scan_allocas(trans, child)
|
||
|
||
# 翻译子节点
|
||
added_total: int = self.translate_children(trans, tree)
|
||
|
||
# 返回 0
|
||
zero_val: llvmlite.Value | t.CPtr = llvmlite.const_int32(pool, 0)
|
||
llvmlite.build_ret(builder, zero_val)
|
||
|
||
return added_total
|
||
|
||
# ============================================================
|
||
# global/nonlocal 名称管理(迁移自 HandlesTranslator.vp 模块级函数)
|
||
# ============================================================
|
||
def add_global_name(self, trans: HT.Translator | t.CPtr, name: str):
|
||
"""添加一个 global 变量名"""
|
||
if trans is None or name is None:
|
||
return
|
||
if trans._global_names is None:
|
||
return
|
||
# 检查是否已存在
|
||
if self.is_global_name(trans, name) != 0:
|
||
return
|
||
if trans._global_name_count >= MAX_GLOBAL_NAMES:
|
||
pool_err: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
err_buf: str = None
|
||
if pool_err is not None:
|
||
err_buf = pool_err.alloc(256)
|
||
if err_buf is not None:
|
||
viperlib.snprintf(err_buf, 256, "global 变量数量超过上限 MAX_GLOBAL_NAMES=%d,请减少 global 声明或增大 MAX_GLOBAL_NAMES", MAX_GLOBAL_NAMES)
|
||
VLogger.error(err_buf, "ScopeDecl")
|
||
else:
|
||
VLogger.error("global 变量数量超过上限,请减少 global 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl")
|
||
return
|
||
entry_addr: t.CUInt64T = t.CUInt64T(trans._global_names) + trans._global_name_count * 8
|
||
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
|
||
slot_ptr[0] = name
|
||
trans._global_name_count += 1
|
||
|
||
def is_global_name(self, trans: HT.Translator | t.CPtr, name: str) -> int:
|
||
"""检查 name 是否在当前函数的 global 集合中"""
|
||
if trans is None or name is None or trans._global_names is None:
|
||
return 0
|
||
for i in range(trans._global_name_count):
|
||
entry_addr: t.CUInt64T = t.CUInt64T(trans._global_names) + i * 8
|
||
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
|
||
entry: str = slot_ptr[0]
|
||
if entry is not None:
|
||
if string.strcmp(entry, name) == 0:
|
||
return 1
|
||
return 0
|
||
|
||
def add_nonlocal_name(self, trans: HT.Translator | t.CPtr, name: str,
|
||
var_ty: llvmlite.LLVMType | t.CPtr = None):
|
||
"""添加一个 nonlocal 变量名
|
||
|
||
Args:
|
||
name: nonlocal 变量名
|
||
var_ty: 变量的 LLVM 类型(用于 env 指针数组方案的类型恢复,
|
||
None 时回退为 i32)
|
||
"""
|
||
if trans is None or name is None:
|
||
return
|
||
if trans._nonlocal_names is None:
|
||
return
|
||
if self.is_nonlocal_name(trans, name) != 0:
|
||
# 已存在:更新类型信息(可能在预扫描时类型未知,正式翻译时更新)
|
||
# _nonlocal_types 每槽 8 字节,存 LLVMType* 指针。
|
||
# 用 str|t.CPtr (i8**) 二级指针存取(与 _nonlocal_names 模式一致),
|
||
# [0] 解引用只拷贝 8 字节指针,避免值拷贝 24+ 字节 LLVMType 结构体溢出。
|
||
if var_ty is not None and trans._nonlocal_types is not None:
|
||
idx: int = self.get_nonlocal_index(trans, name)
|
||
if idx >= 0:
|
||
ty_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + idx * 8
|
||
ty_slot: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr)
|
||
ty_slot[0] = var_ty
|
||
return
|
||
if trans._nonlocal_name_count >= MAX_GLOBAL_NAMES:
|
||
pool_err_nl: memhub.MemBuddy | t.CPtr = trans.Pool
|
||
err_buf_nl: str = None
|
||
if pool_err_nl is not None:
|
||
err_buf_nl = pool_err_nl.alloc(256)
|
||
if err_buf_nl is not None:
|
||
viperlib.snprintf(err_buf_nl, 256, "nonlocal 变量数量超过上限 MAX_GLOBAL_NAMES=%d,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", MAX_GLOBAL_NAMES)
|
||
VLogger.error(err_buf_nl, "ScopeDecl")
|
||
else:
|
||
VLogger.error("nonlocal 变量数量超过上限,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl")
|
||
return
|
||
entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + trans._nonlocal_name_count * 8
|
||
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
|
||
slot_ptr[0] = name
|
||
# 存储类型信息(用 str|t.CPtr = i8** 二级指针,与 _nonlocal_names 一致)
|
||
if trans._nonlocal_types is not None:
|
||
ty_addr2: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + trans._nonlocal_name_count * 8
|
||
ty_slot2: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr2)
|
||
# var_ty 为 None 时直接报错终止(fail-fast),不再默认 i32
|
||
stored_ty: llvmlite.LLVMType | t.CPtr = var_ty
|
||
if stored_ty is None:
|
||
self.Gen.TypeGenErr.fatal_error(None, f"nonlocal 变量 '{name}' 类型缺失,无法注册", "TypeError")
|
||
return
|
||
ty_slot2[0] = stored_ty
|
||
trans._nonlocal_name_count += 1
|
||
trans._closure_env_count += 1
|
||
|
||
def get_nonlocal_type(self, trans: HT.Translator | t.CPtr,
|
||
name: str) -> llvmlite.LLVMType | t.CPtr:
|
||
"""获取 nonlocal 变量的 LLVM 类型
|
||
|
||
Returns: 找到的类型指针,找不到返回 None
|
||
"""
|
||
if trans is None or name is None or trans._nonlocal_types is None:
|
||
return None
|
||
idx: int = self.get_nonlocal_index(trans, name)
|
||
if idx < 0:
|
||
return None
|
||
ty_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_types) + idx * 8
|
||
ty_slot: str | t.CPtr = (t.CVoid | t.CPtr)(ty_addr)
|
||
return (llvmlite.LLVMType | t.CPtr)(ty_slot[0])
|
||
|
||
def is_nonlocal_name(self, trans: HT.Translator | t.CPtr, name: str) -> int:
|
||
"""检查 name 是否在当前函数的 nonlocal 集合中"""
|
||
if trans is None or name is None or trans._nonlocal_names is None:
|
||
return 0
|
||
for i in range(trans._nonlocal_name_count):
|
||
entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + i * 8
|
||
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
|
||
entry: str = slot_ptr[0]
|
||
if entry is not None:
|
||
if string.strcmp(entry, name) == 0:
|
||
return 1
|
||
return 0
|
||
|
||
def get_nonlocal_index(self, trans: HT.Translator | t.CPtr, name: str) -> int:
|
||
"""获取 nonlocal 变量在 env 中的索引(0-based),找不到返回 -1"""
|
||
if trans is None or name is None or trans._nonlocal_names is None:
|
||
return -1
|
||
for i in range(trans._nonlocal_name_count):
|
||
entry_addr: t.CUInt64T = t.CUInt64T(trans._nonlocal_names) + i * 8
|
||
slot_ptr: str | t.CPtr = (t.CVoid | t.CPtr)(entry_addr)
|
||
entry: str = slot_ptr[0]
|
||
if entry is not None:
|
||
if string.strcmp(entry, name) == 0:
|
||
return i
|
||
return -1
|
||
|
||
def clear_scope_names(self, trans: HT.Translator | t.CPtr):
|
||
"""清空当前函数的 global/nonlocal 名称集合(进入新函数时调用)"""
|
||
if trans is None:
|
||
return
|
||
trans._global_name_count = 0
|
||
trans._nonlocal_name_count = 0
|
||
trans._closure_env_count = 0
|