同 includes 的同类修正:把一级指针 i8* 隐式塞进二级注解(i8** / str*)。 TransPyV 侧 coerce(ExprGenBase._ptr_cast_reason)没有 TPC 那样的「值侧是显式 指针 cast ⇒ 按 bitcast 重解释」豁免,故一旦用新构建的 TransPyV 编到这些文件 必然 fail-fast(回归测试首爆点在 includes/llvmlite 侧,本仓同形态站点随后必然 同样触发)。 涉及的两种形态: · `slot: str | t.CPtr = (t.CPtr)(addr)` —— cast 目标是一级 t.CPtr · `nm_slot: str* = (t.CPtr)(addr)` —— 注解 str* 即 i8** 统一改为 cast 到声明类型:`(str | t.CPtr)(addr)` / `str*(addr)`(后者与 includes/sys.vp `argv_arr: str* = str*(...)` 同一写法)。 本仓 47 处 / 6 文件: App/lib/core/Gen/VarGenMixin.vp 3 App/lib/core/Gen/TranslatorGenMixin.vp 8 App/lib/core/Gen/Func/FuncGenMixin.vp 13 App/lib/core/Gen/AsyncGenMixin.vp 15 App/lib/core/Gen/DebugInfoGen.vp 6 App/lib/Stub/StubGen/Converter.vp 2 Converter.vp:107 的 `_g_pyi_cdef_names: str | t.CPtr = None` 保持原样 (None 即空指针,任何指针类型均可,不属本类问题)。 只提交本 6 个文件;本仓其余未提交改动(CallGenBase/CallGenDispatch/CallGenFd/ CallGenProp/Generator/Translator/VLogger)与本迁移无关,保持不动。
1391 lines
79 KiB
Plaintext
1391 lines
79 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
|
||
import lib.core.Gen.GenApi as GenApi
|
||
|
||
|
||
# ============================================================
|
||
# TranslatorGenMixin - 翻译驱动 Mixin
|
||
#
|
||
# 职责:模块级翻译入口(translate_children/create_wrapper_main/
|
||
# handle_module_level_var 等)与 global/nonlocal 名称管理辅助。
|
||
# 容量常量 MAX_VARS/MAX_FUNCS/MAX_GLOBAL_NAMES 不在此定义(本文件无使用点),
|
||
# 统一经 HT.<NAME> 引用 Translator.vp 的唯一真源(与 FuncGenMixin 同一引用路径)。
|
||
# @t.NoVTable:静态绑定(方法沿 MRO 直接调用 + this 调整)。
|
||
# ============================================================
|
||
|
||
|
||
# ============================================================
|
||
# TranslatorGenMixin - 翻译驱动(模块级翻译入口 + 作用域名称管理)
|
||
# ============================================================
|
||
novirtual class TranslatorGenMixin:
|
||
"""翻译驱动 Mixin"""
|
||
|
||
# ============================================================
|
||
# _register_cexport_from_funcdef - Phase 1a 预注册 CExport/State 函数
|
||
#
|
||
# 解决翻译顺序依赖问题:Phase 1b 按字母序翻译,后翻译的模块的
|
||
# CExport 函数无法被先翻译的模块正确识别为裸名调用。
|
||
# Phase 1a 预注册所有 CExport/State 函数名到全局表。
|
||
# ============================================================
|
||
Gen: Generator.Generator*
|
||
def _register_cexport_from_funcdef(self, trans: HT.Translator*, node: ast.AST*) -> int:
|
||
"""预注册 CExport/State 函数到全局表(仅注册,不生成 IR)"""
|
||
fd: ast.FunctionDef* = ast.FunctionDef*(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*, tree: ast.AST*) -> int:
|
||
"""遍历 tree.children 并翻译每个子节点
|
||
|
||
Args:
|
||
trans: 翻译器(含所有共享状态)
|
||
tree: AST 模块节点
|
||
|
||
Returns:
|
||
int: 新增的变量数
|
||
"""
|
||
ch: list[ast.AST*]* = tree.children
|
||
if ch is None: return 0
|
||
cn_count: sizet = len(ch)
|
||
added_total: int = 0
|
||
for ci in range(cn_count):
|
||
child: ast.AST* = 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)。
|
||
# 仅触发特化,不验证结果(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
|
||
|
||
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*, node: ast.AST*) -> None:
|
||
"""预解析模块级函数签名的返回/参数类型,触发泛型类特化"""
|
||
if trans is None or node is None:
|
||
return
|
||
# 入口收基类 ast.AST*(模块级调度器只持有 ast.AST* 子节点,与同一处调用的
|
||
# translate_function_def / translate_class_def / _register_cexport_from_funcdef
|
||
# 形参口径一致),在此显式窄化为 ast.FunctionDef*:基类指针传派生类形参属
|
||
# 向下转型,严格指针规则下禁止隐式转换。
|
||
fd: ast.FunctionDef* = ast.FunctionDef*(node)
|
||
if fd is None:
|
||
return
|
||
pool: memhub.MemBuddy* = 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* = ast.Arguments*(fd.args)
|
||
if ags.args is not None:
|
||
al: list[ast.AST*]* = ags.args
|
||
an: sizet = len(al)
|
||
ai: sizet
|
||
for ai in range(an):
|
||
ag: ast.Arg* = ast.Arg*(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*,
|
||
var_ty: llvmlite.LLVMType*,
|
||
list_node: ast.List*) -> 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* = ast.List*(list_node)
|
||
if ln is None:
|
||
return None
|
||
|
||
# 从 var_ty 提取数组元素类型和数量
|
||
elem_ty: llvmlite.LLVMType* = None
|
||
arr_count: int = 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*]* = ln.elts
|
||
if elts is None:
|
||
return None
|
||
elts_count: sizet = len(elts)
|
||
|
||
# 元素数超过声明长度 → fail-fast(不按声明长度截断、静默丢弃多余元素)。
|
||
if sizet(arr_count) < elts_count:
|
||
self.Gen.TypeGenErr.fatal_error(list_node, f"数组初始化元素数 {elts_count} 超过数组声明长度 {arr_count},不允许静默截断", "OverflowError")
|
||
return None
|
||
|
||
# 非整数元素类型(struct/指针等聚合):不存在 "%s %lld" 文本展开,仅当列表
|
||
# 全零(元素缺失按零填充)时返回整体 "zeroinitializer"——对任意聚合类型合法
|
||
# (否则会生成与声明类型不匹配的 [i8 0, ...] → llc type mismatch)。
|
||
# 含非零/非整数常量无法文本表达 → None → 调用方 fail-fast。
|
||
if is_int_elem == 0:
|
||
# 嵌套数组元素(如 t.CArray[t.CArray[uint8, 16], 256]):elem_ty 是 Array →
|
||
# 递归构建子数组初始化器文本,内层类型省略(由外层全局类型推断),llc 合法。
|
||
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: sizet = sizet(arr_count)
|
||
buf_size_n: sizet = 128 + cnt_total_n * 192
|
||
buf_n: str = pool.alloc(buf_size_n)
|
||
if buf_n is None:
|
||
return None
|
||
written_n: int = viperlib.snprintf(buf_n, buf_size_n, "[")
|
||
pos_n: sizet = sizet(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: sizet = 0
|
||
while i_n < cnt_total_n:
|
||
sub_n: str = None
|
||
if i_n < elts_count:
|
||
en_n: ast.AST* = 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*(en_n))
|
||
elif ek_n == ast.ASTKind.Set:
|
||
# 花括号行字面量(如点阵字库 {0x00, ...}):Set.elts
|
||
# 与 List 同构,包装为临时 List 递归生成子数组文本
|
||
se_n: rawptr[ast.Set] = rawptr[ast.Set](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 += sizet(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 += sizet(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* = elts.get(zi)
|
||
if ze is None:
|
||
continue
|
||
zk: int = ze.kind()
|
||
if zk == ast.ASTKind.Constant:
|
||
zc: ast.Constant* = ast.Constant*(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: sizet = sizet(arr_count)
|
||
buf_size: sizet = 64 + cnt_total * 32
|
||
buf: str = pool.alloc(buf_size)
|
||
if buf is None:
|
||
return None
|
||
|
||
# 写入前缀: "["(类型前缀由 _print_global 输出,初始化器只需元素列表)
|
||
written: int = viperlib.snprintf(buf, buf_size, "[")
|
||
pos: sizet = sizet(written)
|
||
|
||
# 逐个元素写入:元素数必须与数组声明长度 arr_count 一致,
|
||
# 列表元素不足时补零(如 g_arr: t.CArray[int, 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: sizet = 0
|
||
while i < cnt_total:
|
||
elem_val: int64 = 0
|
||
if i < elts_count:
|
||
elem_node: ast.AST* = elts.get(i)
|
||
# 直接从 Constant 节点提取 int_val(避免 extract_cdefine_int_value 的 int 截断)
|
||
if elem_node is not None:
|
||
ek: int = elem_node.kind()
|
||
if ek == ast.ASTKind.Constant:
|
||
ec: ast.Constant* = ast.Constant*(elem_node)
|
||
# CONST_CHAR 字符字面量(如 `_ps2_set1 = ['\x1b', '1', ...]`):
|
||
# int_val 即字符码(不识别则字符元素全编成 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,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 = int64(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 += sizet(written)
|
||
written = viperlib.snprintf(buf + pos, buf_size - pos, "%s %lld", elem_ir_ty, elem_val)
|
||
pos += sizet(written)
|
||
i += 1
|
||
|
||
# 写入后缀 "]"
|
||
viperlib.snprintf(buf + pos, buf_size - pos, "]")
|
||
return buf
|
||
|
||
# _build_string_array_initializer_text - 字符串字面量初始化数组全局
|
||
# t.CArray[char, N] = "..." → [i8 b0, i8 b1, ..., i8 0, ...](字符串字节 +
|
||
# 零填充到数组长度;空串返回 zeroinitializer)。
|
||
# 不能用字符串指针 GEP 初始化器:会导致 @g = global [N x i8] <ptr> 类型不匹配。
|
||
def _build_string_array_initializer_text(self, pool: memhub.MemBuddy*,
|
||
var_ty: llvmlite.LLVMType*,
|
||
str_val: str) -> str:
|
||
"""字符串字面量初始化数组全局,返回初始化器文本或 None"""
|
||
if var_ty is None or str_val is None:
|
||
return None
|
||
arr_count: int = 0
|
||
match var_ty:
|
||
case llvmlite.LLVMType.Array(_, cnt):
|
||
arr_count = cnt
|
||
if arr_count <= 0:
|
||
return None
|
||
slen: sizet = string.strlen(str_val)
|
||
if slen == 0:
|
||
return "zeroinitializer"
|
||
buf_size: sizet = 64 + sizet(arr_count) * 16
|
||
buf: str = pool.alloc(buf_size)
|
||
if buf is None:
|
||
return None
|
||
written: int = viperlib.snprintf(buf, buf_size, "[")
|
||
pos: sizet = sizet(written)
|
||
i: sizet = 0
|
||
while i < sizet(arr_count):
|
||
if i > 0:
|
||
written = viperlib.snprintf(buf + pos, buf_size - pos, ", ")
|
||
pos += sizet(written)
|
||
bv: int64 = 0
|
||
if i < slen:
|
||
bv = int64(str_val[i])
|
||
written = viperlib.snprintf(buf + pos, buf_size - pos, "i8 %lld", bv)
|
||
pos += sizet(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[char, None] = "ABC..." 等字符串初始化指针类型
|
||
# ============================================================
|
||
def _build_string_ptr_initializer(self, pool: memhub.MemBuddy*,
|
||
mod: llvmlite.LLVMModule*,
|
||
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* = llvmlite.create_global_string(pool, mod, str_name_buf, str_val)
|
||
if str_gv is None:
|
||
return None
|
||
|
||
# 生成 GEP 初始化器文本
|
||
str_len: sizet = 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*,
|
||
fty: llvmlite.LLVMType*,
|
||
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*,
|
||
fty: llvmlite.LLVMType*,
|
||
ty_str: str,
|
||
dval: ast.AST*) -> str:
|
||
"""字段默认值 → "ty 值" 文本;不可折叠返回 None"""
|
||
if dval is None or fty is None or ty_str is None:
|
||
return None
|
||
is_int: int = 0
|
||
dv_int: int64 = 0
|
||
if dval.kind() == ast.ASTKind.Constant:
|
||
dc: ast.Constant* = ast.Constant*(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_body_text - storage struct 字段元素文本(不含大括号)
|
||
# 生成 "elem0, elem1, ..."(含字段默认值折叠,缺失处按类型零值兜底),供两处复用:
|
||
# - _build_stg_struct_init_text:外包 "{ ... }" 作为完整初始化器;
|
||
# - vtable 对象 storage:首元素为 vtable 指针,其后追加本函数结果(start_idx=1 跳过字段 0)。
|
||
# 无任何非零默认值时返回 None,调用方据此保持原零值路径(避免无谓文本)。
|
||
def _build_stg_struct_body_text(self, pool: memhub.MemBuddy*,
|
||
se: GenTypes.StructEntry*,
|
||
start_idx: int) -> str:
|
||
"""按字段默认值生成 "e0, e1, ..." 元素文本;无非零默认值返回 None"""
|
||
if se is None or se.Fields is None:
|
||
return None
|
||
fc: int = se.FieldCount
|
||
if fc <= start_idx:
|
||
return None
|
||
buf_size: sizet = 256 + sizet(fc) * 160
|
||
buf: str = pool.alloc(buf_size)
|
||
if buf is None:
|
||
return None
|
||
pos: sizet = 0
|
||
first: int = 1
|
||
has_nonzero: int = 0
|
||
i: int = start_idx
|
||
while i < fc:
|
||
fe: GenTypes.FieldEntry* = 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
|
||
written: int = 0
|
||
if first == 0:
|
||
written = viperlib.snprintf(buf + pos, buf_size - pos, ", ")
|
||
pos += sizet(written)
|
||
written = viperlib.snprintf(buf + pos, buf_size - pos, "%s", elem)
|
||
pos += sizet(written)
|
||
first = 0
|
||
if is_zero == 0:
|
||
has_nonzero = 1
|
||
if has_nonzero == 0:
|
||
return None
|
||
return buf
|
||
|
||
# _build_stg_struct_init_text - storage struct 完整常量初始化器(含字段默认值)
|
||
# 用于模块级对象全局 `X: T = T()`:按字段默认值生成完整 struct 常量
|
||
# (LLVM 要求列全每个字段);不生成则字段默认值全丢。
|
||
# 无任何非零默认值时返回 None,由调用方保持 zeroinitializer(避免无谓文本)。
|
||
def _build_stg_struct_init_text(self, pool: memhub.MemBuddy*,
|
||
se: GenTypes.StructEntry*,
|
||
start_idx: int) -> str:
|
||
"""按字段默认值生成完整 struct 初始化器;无非零默认值返回 None"""
|
||
body: str = self._build_stg_struct_body_text(pool, se, start_idx)
|
||
if body is None:
|
||
return None
|
||
body_len: sizet = sizet(string.strlen(body))
|
||
buf: str = pool.alloc(body_len + 8)
|
||
if buf is None:
|
||
return None
|
||
viperlib.snprintf(buf, body_len + 8, "{ %s }", body)
|
||
return buf
|
||
|
||
# ============================================================
|
||
# 模块级全局变量 t.attr.* 属性提取
|
||
#
|
||
# 语法:属性写在类型注解的联合里(`T | t.attr.section(".x")`),因为
|
||
# Assign/AnnAssign 节点没有 decorator_list(解析器对 `@c.Attribute(...)`
|
||
# 后接赋值会直接报 "decorator must be followed by def/class")。
|
||
# 与函数侧口径差异:函数属性来自 decorator_list,提取为属性组文本
|
||
# `"section"="xxx"`(LLVM 字符串属性必须带引号,走 attributes #N);
|
||
# 全局变量属性没有属性组,直接写入 GlobalVariable.Section/Align/Linkage
|
||
# 字段,打印时由 includes/llvmlite/__module.vp 的 _print_global 补引号
|
||
# (`, section "xxx"` / `, align N`),故此处 Section 值不带引号。
|
||
# ============================================================
|
||
def _scan_global_tattr(self, node: ast.AST*,
|
||
want_name: str) -> ast.AST*:
|
||
"""在全局变量类型注解中查找 t.attr.<want_name> 节点。
|
||
|
||
注解形态是 BinOp(BitOr) 左深链(`A | B | C` = BinOp(BinOp(A,B),C)),
|
||
递归左右子节点。命中返回该 t.attr 节点(Call: t.attr.aligned(16) /
|
||
Attribute: t.attr.weak),未命中返回 None。属性名识别复用类侧
|
||
ClassGenBase._tattr_name(Call→func→attr / Attribute→attr)。
|
||
"""
|
||
if node is None:
|
||
return None
|
||
if node.kind() == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp* = ast.BinOp*(node)
|
||
if bop.op == ast.OpKind.BitOr:
|
||
hit_l: ast.AST* = self._scan_global_tattr(bop.left, want_name)
|
||
if hit_l is not None:
|
||
return hit_l
|
||
return self._scan_global_tattr(bop.right, want_name)
|
||
return None
|
||
if self.Gen.ClassGenBase._tattr_name(node, want_name) != 0:
|
||
return node
|
||
return None
|
||
def _extract_global_attr_section(self, node: ast.AST*,
|
||
var_name: str) -> str:
|
||
"""取 `T | t.attr.section("xxx")` 的段名(不含引号)。
|
||
|
||
缺参/空段名属非法值 → fail-fast(与 handle_module_level_var 既有
|
||
TypeGenErr.fatal_error 风格一致):空段名会生成 `section ""` 这种
|
||
无意义/非法的 IR,静默忽略只会掩盖拼写错误。
|
||
"""
|
||
hit: ast.AST* = self._scan_global_tattr(node, "section")
|
||
if hit is None:
|
||
return None
|
||
sec_val: str = self.Gen.FuncGenBase._get_attr_call_arg_str(hit)
|
||
if sec_val is None or sec_val[0] == 0:
|
||
self.Gen.TypeGenErr.fatal_error(node, f"模块级变量 '{var_name}' 的 t.attr.section(...) 段名缺失或为空", "ValueError")
|
||
return None
|
||
return sec_val
|
||
def _extract_global_attr_aligned(self, node: ast.AST*,
|
||
var_name: str) -> int:
|
||
"""取 `T | t.attr.aligned(N)` 的对齐字节数(无该属性返回 0)。
|
||
|
||
N 必须是正整数字面量:aligned(0)/aligned(-4)/aligned("x") 均属非法值
|
||
→ fail-fast(llc 亦拒绝 `align 0`,静默忽略会掩盖参数错误)。
|
||
"""
|
||
hit: ast.AST* = self._scan_global_tattr(node, "aligned")
|
||
if hit is None:
|
||
return 0
|
||
al_val: int = self.Gen.ClassGenBase._tattr_aligned_int(hit)
|
||
if al_val <= 0:
|
||
self.Gen.TypeGenErr.fatal_error(node, f"模块级变量 '{var_name}' 的 t.attr.aligned(N) 需要正整数字面量 N", "ValueError")
|
||
return 0
|
||
return al_val
|
||
def _extract_global_attr_weak(self, node: ast.AST*) -> int:
|
||
"""检测 `T | t.attr.weak` / `t.attr.weak()`(1=有,0=无)"""
|
||
if self._scan_global_tattr(node, "weak") is not None:
|
||
return 1
|
||
return 0
|
||
|
||
# ============================================================
|
||
# handle_module_level_var - 模块级变量声明 → 创建 LLVM 全局变量
|
||
#
|
||
# 当用户已定义 main(无 wrapper main builder)时,模块级
|
||
# AnnAssign/Assign 创建全局变量 @var_name 并注册到 SymTab 模块作用域
|
||
# 支持整数、列表字面量、字符串字面量初始值
|
||
# ============================================================
|
||
# ============================================================
|
||
# _RegisterStaticModuleVar - 模块级 static 变量登记
|
||
#
|
||
# `static x: int = 0`(解析层已归一为 `x: t.CStatic | int`)与手写
|
||
# `x: t.CStatic | int` 均命中 → 登记 (变量名, 定义模块 SHA1) 到 static 符号表,
|
||
# 供引用侧(ExprGenAttr / CallGenMixin / ImportsGenMixin)拦截跨模块使用。
|
||
# 变量无装饰器通道(@t.CStatic 只作用于 def),故只看注解。
|
||
# 时机:调用点位于 handle_module_level_var 的 `_declare_only` 提前返回之后,
|
||
# 预声明遍不会走到;登记接口本身也做了幂等,重复登记无副作用。
|
||
# 独立成函数:不内联(内联新增分支会干扰调用方的类型推断)。
|
||
# ============================================================
|
||
def _RegisterStaticModuleVar(self, trans: HT.Translator*,
|
||
annot_node: ast.AST*,
|
||
var_name: str) -> int:
|
||
if trans is None or annot_node is None or var_name is None:
|
||
return 0
|
||
if trans.ModuleSha1 is None:
|
||
return 0
|
||
if self.Gen.TypeGenErr.has_decorator_marker(annot_node, "CStatic", 0) == 0:
|
||
return 0
|
||
self.Gen.CallGenBase.RegisterStaticSymbol(trans.ModuleSha1, var_name)
|
||
return 0
|
||
|
||
|
||
def handle_module_level_var(self, trans: HT.Translator*,
|
||
node: ast.AST*) -> int:
|
||
"""处理模块级变量声明,创建全局变量"""
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
mod: llvmlite.LLVMModule* = trans.Module
|
||
|
||
# CDefine 注解: 编译期常量,不创建全局变量
|
||
# 注册到全局 CDefine 表供 t.CArray[elem_ty, NAME] 解析
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.AnnAssign:
|
||
aa_cd: ast.AnnAssign* = ast.AnnAssign*(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* = ast.Name*(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, aa_cd.annotation)
|
||
return 0
|
||
# CTypedef 注解(如 posix.vp mode_t: t.CTypedef = uint32):
|
||
# 不创建全局变量(否则生成 @mode_t 符号 → 链接 duplicate symbol)。
|
||
# 预注册阶段按需注册到 CTypedef 表:翻译期表已被 clear_ctypedefs 清空
|
||
# (每文件隔离),不注册则函数参数注解查表失败 → NameError。
|
||
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* = llvmlite.Int32(pool)
|
||
resolved_stg_ty: llvmlite.LLVMType* = None # 对象类全局:静态 storage 类型(BSS 实例)
|
||
resolved_stg_entry: GenTypes.StructEntry* = None # 对象类全局:对应 StructEntry(vtable 初始化用)
|
||
init_val: int64 = 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* = None
|
||
# = None 显式初始化(如 tokens.vp `_kw_head: KwEntry | t.CPtr = None`):
|
||
# 对象类全局的懒初始化指针语义——必须保持 NULL,不能创建 BSS storage
|
||
# (storage 会让 @g = &g.stg 恒非 NULL,破坏 `if _kw_head != None` 守卫,
|
||
# 懒初始化代码永不执行)。
|
||
is_none_init: int = 0
|
||
annot_node: ast.AST* = None # 类型注解节点(检测 t.CExport 标记)
|
||
|
||
if k == ast.ASTKind.AnnAssign:
|
||
aa: ast.AnnAssign* = ast.AnnAssign*(node)
|
||
if aa is None or aa.target is None:
|
||
return 0
|
||
if aa.target.kind() != ast.ASTKind.Name:
|
||
return 0
|
||
nm: ast.Name* = ast.Name*(aa.target)
|
||
var_name = nm.id
|
||
annot_node = aa.annotation
|
||
# f-string 逃逸:模块级变量的初始值是**全局**(函数外可见),而 f-string
|
||
# 结果指向当前函数的栈缓冲(且模块级初始化根本没有可用的函数栈)⇒
|
||
# fail-fast;需要字面量以外的初值请用显式拷贝(GenApi.escape_fstring_copy)。
|
||
GenApi.fail_if_fstring_escape(aa.value, "全局变量初始化")
|
||
# static 符号(禁止跨模块使用):模块级变量带 t.CStatic 标记
|
||
# (`static x: int = 0` 经解析层归一为 `x: t.CStatic | int`;亦覆盖
|
||
# 手写 `x: t.CStatic | int`)→ 登记 (变量名, 定义模块 SHA1)。
|
||
# 逻辑收敛在 _RegisterStaticModuleVar 内(不内联——本函数含多分支,
|
||
# 内联新增分支会干扰其类型推断,与 ExprGenAttr/CallGenMixin 同款处理)。
|
||
self._RegisterStaticModuleVar(trans, annot_node, var_name)
|
||
# t.Callable 模块级函数指针:登记 (变量名 → 返回类型) 签名。此路径原先
|
||
# 只创建全局变量、不登记签名,模块级 t.Callable 变量被间接调用时在
|
||
# CallGenLeafKit._translate_func_ptr_call 报"返回类型未注册(t.Callable
|
||
# 注解缺失)"(CallGenLeafKit.vp:843-850)。与函数内 AnnAssign 同一登记函数
|
||
# (AssignGenMixin.vp:1465-1474),参数形态照抄该处:
|
||
# (pool, 注解, trans._imported_modules, trans._from_imports, trans)。
|
||
# 时机:_translate_module_level 在 translate_children 之前先遍历全部模块级
|
||
# AnnAssign/Assign(Translator.vp:568-575,其后才是 :578 translate_children),
|
||
# 故登记早于本文件任何函数体翻译;签名表本体与返回类型深拷贝都在 PermPool
|
||
# (CallGenLeafKit.vp:698-699、:783-788),跨文件查找可见。
|
||
# t.CDefine/t.CTypedef 等分支已在 :675-689 提前返回,行为不变。
|
||
if annot_node is not None:
|
||
ml_callable_ret: llvmlite.LLVMType* = self.Gen.TypeGenErr.try_extract_callable_ret(pool, annot_node, trans._imported_modules,trans._from_imports, trans)
|
||
if ml_callable_ret is not None:
|
||
# 返回值:0=成功/同类型幂等命中;非 0 已在 register_func_ptr_sig
|
||
# 内部 fatal_error 终止编译,此处分支仅防御(见 AssignGenMixin 同处)。
|
||
if self.Gen.CallGenLeafKit.register_func_ptr_sig(pool, var_name, ml_callable_ret, aa) != 0:
|
||
return 0
|
||
# 解析类型
|
||
if aa.annotation is not None:
|
||
resolved: llvmlite.LLVMType* = 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 值,模块级变量此处需包装 Ptr;若建成
|
||
# 值实例,跨模块字段访问/虚表调用会按指针处理读首 8 字节当 vtable → 崩溃。
|
||
# 纯 t.CStruct(无方法无虚表无 __new__)保持值实例。
|
||
if resolved.kind() == llvmlite.LLVMType.Struct:
|
||
gv_entry: GenTypes.StructEntry* = 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 为 NULL,
|
||
# 对象字段落在物理页 0。
|
||
resolved_stg_ty = resolved
|
||
resolved_stg_entry = gv_entry
|
||
resolved = llvmlite.Ptr(pool, resolved)
|
||
elif resolved.kind() == llvmlite.LLVMType.Ptr:
|
||
# 对象类联合注解(T | t.CPtr → T*):同样创建 storage;否则入口/方法
|
||
# 虚调用 load @g 得 NULL → 读 [NULL] 拿 vtable → #PF。
|
||
# var_ty 保持 Ptr(联合注解语义:指针全局),storage 承载对象实例。
|
||
pointee_uv: llvmlite.LLVMType* = resolved.Pointee
|
||
if pointee_uv is not None and pointee_uv.kind() == llvmlite.LLVMType.Struct:
|
||
gv_entry_u: GenTypes.StructEntry* = 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
|
||
else:
|
||
# [S4 fail-fast] 模块级变量有注解但解析失败 → 不再静默用 i32
|
||
# (类型错会使全局存储尺寸/字段访问/ABI 全错);前向引用未注册类
|
||
# 应收敛为多遍注册而非回退 i32。
|
||
self.Gen.TypeGenErr.fatal_error(aa.annotation, f"模块级变量 '{var_name}' 类型注解解析失败", "NameError")
|
||
return 0
|
||
# 解析初始值(支持整数、负数字面量、列表字面量、字符串字面量)
|
||
if aa.value is not None:
|
||
val_kind: int = aa.value.kind()
|
||
if val_kind == ast.ASTKind.Constant:
|
||
cn: ast.Constant* = ast.Constant*(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,否则全局退化成 zeroinitializer、初始化值整体丢失。
|
||
# 数值不在此处取 AST 的 float_val,见下方 init_kind==4 的源文件恢复逻辑。
|
||
init_kind = 4
|
||
elif val_kind == ast.ASTKind.UnaryOp:
|
||
# 负数/按位取反字面量(如 `_vblank_ok: int = -1`):AST 是
|
||
# UnaryOp(USub, Constant),不处理则全局编成 zeroinitializer、初始化值丢失。
|
||
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*(aa.value)
|
||
init_kind = 2
|
||
elif k == ast.ASTKind.Assign:
|
||
asgn: ast.Assign* = ast.Assign*(node)
|
||
if asgn is None or asgn.targets is None:
|
||
return 0
|
||
targets: list[ast.AST*]* = asgn.targets
|
||
if len(targets) < 1:
|
||
return 0
|
||
t0: ast.AST* = targets.get(0)
|
||
if t0 is None or t0.kind() != ast.ASTKind.Name:
|
||
return 0
|
||
nm2: ast.Name* = ast.Name*(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* = ast.Constant*(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*(asgn.value)
|
||
init_kind = 2
|
||
elif val_kind2 == ast.ASTKind.Attribute:
|
||
# 模块级 re-export 别名(如 fat32_core.vp `_read32 = types._read32`):
|
||
# RHS 是函数/实体引用,无值语义可落入 LLVM 全局。不识别则 var_ty 默认 i32
|
||
# → 生成假符号 `global i32 zeroinitializer`(被引用即调用地址 0)。
|
||
# 与 __all__ 同类:别名/元数据实体不产出 LLVM 全局。
|
||
# 真正的函数别名机制(可调用 + 可 re-export)属独立特性,待后续实现。
|
||
return 0
|
||
|
||
if var_name is None:
|
||
return 0
|
||
|
||
# __all__ 是 Python 模块元数据(公开名列表),无运行时语义:StubGen 的 .vpi 不为其
|
||
# 生成 stub 声明,此处同样跳过全局创建——否则无注解 list-of-strings 全局类型推断
|
||
# 缺失(var_ty 默认 i32)→ _build_array_initializer_text 返回 None → 误报
|
||
# "初始化器构建失败"。与 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* = 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: rawptr[memhub.MemManager] → 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)
|
||
# extern 全局(`extern NAME: T` → 注解含 t.State / t.CExtern):符号定义在
|
||
# 外部(C 库 / 汇编 / 其它翻译单元),本模块只生成外部声明
|
||
# `@裸名 = external global T`——external linkage、无初始值、无 storage。
|
||
# 与 export 的差别:export 是**本模块定义**(裸名导出);extern 是**仅声明**。
|
||
# `t.State` = t.CExtern | t.CExport(parser 的 `extern NAME: T` 展开产物)。
|
||
is_global_extern: int = 0
|
||
if annot_node is not None:
|
||
is_global_extern = self.Gen.TypeGenErr.has_decorator_marker(annot_node, "CExtern", 0)
|
||
if is_global_extern == 0:
|
||
is_global_extern = self.Gen.TypeGenErr.has_decorator_marker(annot_node, "State", 0)
|
||
# 全局变量侧 t.attr.* 属性(`T | t.attr.xxx` 注解联合形态):
|
||
# section→gv.Section、aligned→gv.Align、weak→gv.Linkage(见下方应用点)。
|
||
# 仅在 AnnAssign(annot_node 非 None)时存在,与 t.CExport 同一条路。
|
||
gv_attr_section: str = None
|
||
gv_attr_align: int = 0
|
||
gv_attr_weak: int = 0
|
||
if annot_node is not None:
|
||
gv_attr_section = self._extract_global_attr_section(annot_node, var_name)
|
||
gv_attr_align = self._extract_global_attr_aligned(annot_node, var_name)
|
||
gv_attr_weak = self._extract_global_attr_weak(annot_node)
|
||
mangled_name: str = var_name
|
||
if is_global_cexport == 0 and is_global_extern == 0:
|
||
mangled_name = self.Gen.FuncGenBase._mangle_name(trans, var_name)
|
||
gv: llvmlite.GlobalVariable* = llvmlite.new_global_variable(pool, mangled_name, var_ty)
|
||
if gv is None:
|
||
return 0
|
||
llvmlite.module_add_global(mod, gv)
|
||
|
||
# 段名:直接写字段(_print_global 会补 `, section "xxx"` 的引号)。
|
||
if gv_attr_section is not None:
|
||
llvmlite.global_set_section(gv, gv_attr_section)
|
||
|
||
# B5:@c.Attribute(t.attr.aligned(N)) 类的全局实例施加对齐(如 fpu_context 16 对齐,
|
||
# FXSAVE 区域要求 16 字节对齐,否则 fxsave/fxrstor #GP)。
|
||
# 优先级:变量级显式 `T | t.attr.aligned(N)` 比类级(struct entry Align)更具体,
|
||
# 显式值胜出;无显式属性时沿用类级对齐(既有行为不变)。
|
||
al_ty: llvmlite.LLVMType* = var_ty
|
||
match var_ty:
|
||
case llvmlite.LLVMType.Ptr(pointee_al):
|
||
al_ty = pointee_al
|
||
case _:
|
||
pass
|
||
al_entry: GenTypes.StructEntry* = 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 gv_attr_align > 0:
|
||
gv.Align = gv_attr_align
|
||
elif al_entry is not None and al_entry.Align > 0:
|
||
gv.Align = al_entry.Align
|
||
|
||
# 设置初始值(有初始值时清除 external linkage,因为 LLVM 22+ 不允许 external global 带初始值)
|
||
# extern 全局例外:保持 external(仅外部声明,绝不写初始值 / storage)。
|
||
if is_global_extern != 0:
|
||
gv.Linkage = "external"
|
||
else:
|
||
gv.Linkage = None
|
||
# t.attr.weak → weak linkage(须在 Linkage 清空之后设置)。
|
||
if gv_attr_weak != 0:
|
||
llvmlite.global_set_linkage(gv, "weak")
|
||
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[char, N]):字节数组初始化器(字符串内容 + 零填充)。
|
||
# 不能用字符串指针 GEP 初始化器(@g = global [N x i8] <ptr> 类型不匹配)。
|
||
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[char, 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 注释)。
|
||
# 浮点分支缺失时模块级 t.CDouble 全局会退化成 zeroinitializer(值全变 0)。
|
||
fc_g: llvmlite.Value* = 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) and is_global_extern == 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 语义。
|
||
# extern 全局(is_global_extern)同样不建 storage:外部声明无本模块实例。
|
||
if resolved_stg_ty is not None and is_none_init == 0 and is_global_extern == 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 → 入口虚调用 call [vtable+0x10] → 跳 0x0 #PF。
|
||
# @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)
|
||
# vtable 符号前缀必须用类定义模块的 sha1(对齐 CallGenLeafKit._make_vtable_ref_i8):
|
||
# 用当前模块 _mangle_name 会使跨模块对象类全局 storage 初始化引用
|
||
# "@当前sha1.Class.vtable",而 vtable 实为定义模块的符号 → llc "use of
|
||
# undefined value"。resolved_stg_entry.ModuleSha1 即定义模块,比裸名反查精确。
|
||
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: sizet = 16384
|
||
init_full: str = pool.alloc(init_full_len)
|
||
if init_full is not None:
|
||
written_v: int = viperlib.snprintf(init_full, init_full_len, "{ ")
|
||
pos_v: sizet = sizet(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 += sizet(written_v)
|
||
# 字段 1..N 优先按字段默认值折叠(vtable 对象全局
|
||
# 如 `_mbuddy: MemBuddy` 的字段默认不再丢失);
|
||
# 全部默认值恰为零时回退逐字段零值,避免无谓文本。
|
||
# 两者均列全字段(LLVM 要求初始化器元素数匹配)。
|
||
rest_v: str = self._build_stg_struct_body_text(pool, resolved_stg_entry, 1)
|
||
if rest_v is not None:
|
||
written_v = viperlib.snprintf(init_full + pos_v, init_full_len - pos_v, ", %s", rest_v)
|
||
pos_v += sizet(written_v)
|
||
else:
|
||
fc_v: int = resolved_stg_entry.FieldCount
|
||
for fi_v in range(1, fc_v):
|
||
fe_v: GenTypes.FieldEntry* = 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 += sizet(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 / 普通类):按字段默认值生成常量初始化器;
|
||
# 一律 zeroinitializer 会丢掉全部字段默认值(模块级 X: T = T() 的构造调用
|
||
# 不发射)。无任何非零默认值时返回 None → 保持 zeroinitializer(零开销)。
|
||
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: sizet = sizet(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* = 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: sizet = sizet(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* = self.Gen.ExprGenAttr.make_global_ref(pool, stg_name_buf, resolved_stg_ty)
|
||
if stg_ref is not None:
|
||
stg_key_len: sizet = sizet(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* = 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* = llvmlite.SSAValue(pool, var_ptr_ty, ref_name)
|
||
|
||
# 注册到模块作用域
|
||
if self.Gen.VarGen.define_module_var(trans.SymTab, var_name, gv_ref) == 0:
|
||
# t.CVolatile 存储类标记(注解联合含 t.CVolatile)→ 标记全局变量
|
||
# volatile:所有 load/store 带 LLVM volatile,禁止优化器把忙等循环
|
||
# 的重复 load 提升/消除(如 `locked: t.CVolatile | t.CInt`)。
|
||
if annot_node is not None:
|
||
# const 对象全局:注解含 t.CConst 且类型非指针 ⇒ 登记 IsConst,
|
||
# 之后对该全局名的赋值/增量赋值/元素赋值 fail-fast(判据同 TPC
|
||
# 的 Gen.global_const_flags,见 Debugger/type-descriptors.md)。
|
||
if self.Gen.TypeGenErr.is_const_object_marker(annot_node, var_ty) != 0:
|
||
self.Gen.VarGen.set_var_const(trans.SymTab, var_name)
|
||
if self.Gen.TypeGenErr.has_decorator_marker(annot_node, "CVolatile", 0) != 0:
|
||
self.Gen.VarGen.set_var_volatile(trans.SymTab, var_name)
|
||
# rawptr[t.CVolatile | T](volatile 指针指向物):解引用(p[i]/
|
||
# p.field/c.Deref(p))的 load/store 带 volatile。与上一分支互斥:
|
||
# 前者是变量自身限定(BinOp 联合),后者是 rawptr 下标实参标记。
|
||
if self.Gen.TypeGenErr.has_pointee_volatile_marker(annot_node) != 0:
|
||
self.Gen.VarGen.set_var_pointee_volatile(trans.SymTab, var_name)
|
||
# 设置 AnnotClassName(联合类型如 Logger|t.CPtr 简化为 Ptr(i8) 时,
|
||
# 属性访问需要通过 AnnotClassName 回退到类名查找结构体)
|
||
if k == ast.ASTKind.AnnAssign:
|
||
aa_ml: ast.AnnAssign* = ast.AnnAssign*(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* = ast.BinOp*(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*,
|
||
tree: ast.AST*,
|
||
i32_ty: llvmlite.LLVMType*) -> int:
|
||
"""创建包装 main 函数并翻译所有顶层语句
|
||
|
||
Args:
|
||
trans: 翻译器(含所有共享状态)
|
||
tree: AST 模块节点
|
||
i32_ty: i32 LLVMType
|
||
|
||
Returns:
|
||
int: 新增的变量数
|
||
"""
|
||
pool: memhub.MemBuddy* = trans.Pool
|
||
mod: llvmlite.LLVMModule* = trans.Module
|
||
|
||
main_func: llvmlite.Function* = llvmlite.create_function(pool, mod, "main", i32_ty)
|
||
if main_func is None:
|
||
VLogger.error("CreateFunction main returned NULL", "TR")
|
||
return 0
|
||
|
||
entry_blk: rawptr[llvmlite.BasicBlock] = llvmlite.create_block(pool, main_func, "entry")
|
||
if entry_blk is None:
|
||
VLogger.error("CreateBlock returned NULL", "TR")
|
||
return 0
|
||
|
||
builder: llvmlite.IRBuilder* = 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*]* = tree.children
|
||
if ch is not None:
|
||
cn_count: sizet = len(ch)
|
||
for ci in range(cn_count):
|
||
child: ast.AST* = 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* = 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* = 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*, 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 >= HT.MAX_GLOBAL_NAMES:
|
||
pool_err: memhub.MemBuddy* = 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", HT.MAX_GLOBAL_NAMES)
|
||
VLogger.error(err_buf, "ScopeDecl")
|
||
else:
|
||
VLogger.error("global 变量数量超过上限,请减少 global 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl")
|
||
return
|
||
entry_addr: uint64 = uint64(trans._global_names) + trans._global_name_count * 8
|
||
slot_ptr: str | t.CPtr = (str | t.CPtr)(entry_addr)
|
||
slot_ptr[0] = name
|
||
trans._global_name_count += 1
|
||
|
||
def is_global_name(self, trans: HT.Translator*, 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: uint64 = uint64(trans._global_names) + i * 8
|
||
slot_ptr: str | t.CPtr = (str | 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*, name: str,
|
||
var_ty: llvmlite.LLVMType* = 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: uint64 = uint64(trans._nonlocal_types) + idx * 8
|
||
ty_slot: str | t.CPtr = (str | t.CPtr)(ty_addr)
|
||
ty_slot[0] = var_ty
|
||
return
|
||
if trans._nonlocal_name_count >= HT.MAX_GLOBAL_NAMES:
|
||
pool_err_nl: memhub.MemBuddy* = 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", HT.MAX_GLOBAL_NAMES)
|
||
VLogger.error(err_buf_nl, "ScopeDecl")
|
||
else:
|
||
VLogger.error("nonlocal 变量数量超过上限,请减少 nonlocal 声明或增大 MAX_GLOBAL_NAMES", "ScopeDecl")
|
||
return
|
||
entry_addr: uint64 = uint64(trans._nonlocal_names) + trans._nonlocal_name_count * 8
|
||
slot_ptr: str | t.CPtr = (str | t.CPtr)(entry_addr)
|
||
slot_ptr[0] = name
|
||
# 存储类型信息(用 str|t.CPtr = i8** 二级指针,与 _nonlocal_names 一致)
|
||
if trans._nonlocal_types is not None:
|
||
ty_addr2: uint64 = uint64(trans._nonlocal_types) + trans._nonlocal_name_count * 8
|
||
ty_slot2: str | t.CPtr = (str | t.CPtr)(ty_addr2)
|
||
# var_ty 为 None 时直接报错终止(fail-fast),不再默认 i32
|
||
stored_ty: llvmlite.LLVMType* = 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*,
|
||
name: str) -> llvmlite.LLVMType*:
|
||
"""获取 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: uint64 = uint64(trans._nonlocal_types) + idx * 8
|
||
ty_slot: str | t.CPtr = (str | t.CPtr)(ty_addr)
|
||
return (llvmlite.LLVMType*)(ty_slot[0])
|
||
|
||
def is_nonlocal_name(self, trans: HT.Translator*, 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: uint64 = uint64(trans._nonlocal_names) + i * 8
|
||
slot_ptr: str | t.CPtr = (str | 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*, 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: uint64 = uint64(trans._nonlocal_names) + i * 8
|
||
slot_ptr: str | t.CPtr = (str | 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*):
|
||
"""清空当前函数的 global/nonlocal 名称集合(进入新函数时调用)"""
|
||
if trans is None:
|
||
return
|
||
trans._global_name_count = 0
|
||
trans._nonlocal_name_count = 0
|
||
trans._closure_env_count = 0
|