同 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)与本迁移无关,保持不动。
1170 lines
62 KiB
Plaintext
1170 lines
62 KiB
Plaintext
import lib.core.Gen.GenApi as GenApi
|
||
import lib.core.VLogger as VLogger
|
||
import t, c
|
||
from stdint import *
|
||
import ast
|
||
import string
|
||
import memhub
|
||
import viperlib
|
||
import stdlib
|
||
import sys
|
||
|
||
# ============================================================
|
||
# StubGen.Converter - vpi 存根文件生成器
|
||
# ============================================================
|
||
|
||
|
||
# ============================================================
|
||
# _eval_binop_int / _eval_binop_valid - 递归计算 BinOp 常量值
|
||
#
|
||
# 用于 .vpi 存根文件生成时计算 BinOp 表达式(如 A | B, A + B)的整数值。
|
||
# 支持 BitOr/BitAnd/Add/Sub 以及嵌套的 Name(引用已注册的 CDefine 常量)。
|
||
# ============================================================
|
||
def _eval_binop_valid(node: ast.AST*) -> int:
|
||
"""检查 BinOp 节点是否可计算(所有叶子节点都是常量或已注册的 CDefine)"""
|
||
if node is None: return 0
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.Constant:
|
||
cn: ast.Constant* = ast.Constant*(node)
|
||
if cn.const_kind == ast.CONST_INT:
|
||
return 1
|
||
return 0
|
||
if k == ast.ASTKind.UnaryOp:
|
||
uop: ast.UnaryOp* = ast.UnaryOp*(node)
|
||
if uop.operand is not None:
|
||
return _eval_binop_valid(uop.operand)
|
||
return 0
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp* = ast.BinOp*(node)
|
||
if bop.left is not None and bop.right is not None:
|
||
if _eval_binop_valid(bop.left) != 0:
|
||
if _eval_binop_valid(bop.right) != 0:
|
||
return 1
|
||
return 0
|
||
if k == ast.ASTKind.Name:
|
||
# Name 引用:检查是否是已注册的 CDefine 常量
|
||
nm: ast.Name* = ast.Name*(node)
|
||
if nm.id is not None:
|
||
# 从本地 CDefine 表查找
|
||
val: int = _lookup_cdefine_for_pyi(nm.id)
|
||
if _pyi_cdefine_found() != 0:
|
||
return 1
|
||
return 0
|
||
return 0
|
||
|
||
|
||
def _eval_binop_int(node: ast.AST*) -> int64:
|
||
"""递归计算 BinOp 节点的整数值(64 位,避免大整数 CDefine 截断)"""
|
||
if node is None:
|
||
return 0
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.Constant:
|
||
cn: ast.Constant* = ast.Constant*(node)
|
||
if cn.const_kind == ast.CONST_INT:
|
||
return cn.int_val
|
||
return 0
|
||
if k == ast.ASTKind.UnaryOp:
|
||
uop: ast.UnaryOp* = ast.UnaryOp*(node)
|
||
if uop.op == ast.OpKind.USub and uop.operand is not None:
|
||
return -_eval_binop_int(uop.operand)
|
||
if uop.op == ast.OpKind.UAdd and uop.operand is not None:
|
||
return _eval_binop_int(uop.operand)
|
||
if uop.op == ast.OpKind.Invert and uop.operand is not None:
|
||
return ~_eval_binop_int(uop.operand)
|
||
return 0
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp* = ast.BinOp*(node)
|
||
if bop.left is None or bop.right is None:
|
||
return 0
|
||
lv: int64 = _eval_binop_int(bop.left)
|
||
rv: int64 = _eval_binop_int(bop.right)
|
||
if bop.op == ast.OpKind.BitOr: return lv | rv
|
||
if bop.op == ast.OpKind.BitAnd: return lv & rv
|
||
if bop.op == ast.OpKind.BitXor: return lv ^ rv
|
||
if bop.op == ast.OpKind.Add: return lv + rv
|
||
if bop.op == ast.OpKind.Sub: return lv - rv
|
||
if bop.op == ast.OpKind.Mult: return lv * rv
|
||
if bop.op == ast.OpKind.Div: return lv // rv
|
||
if bop.op == ast.OpKind.FloorDiv: return lv // rv
|
||
if bop.op == ast.OpKind.Mod: return lv % rv
|
||
if bop.op == ast.OpKind.LShift: return lv << rv
|
||
if bop.op == ast.OpKind.RShift: return lv >> rv
|
||
return 0
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name* = ast.Name*(node)
|
||
if nm.id is not None:
|
||
return _lookup_cdefine_for_pyi(nm.id)
|
||
return 0
|
||
return 0
|
||
|
||
|
||
# CDefine 查找的前向声明(实际实现在 HandlesType)
|
||
# 避免循环依赖,使用弱引用
|
||
_g_pyi_cdefine_found: int = 0
|
||
|
||
# 本文件 CDefine 值缓存(vpi 生成专用):vpi 生成早于翻译阶段注册(全局表为空),_GeneratePyiFromAst 开头按声明顺序注册,Name 引用先查本缓存。
|
||
# 两个缓存必须是 C 数组(int64* / i8**)而非 list[T]——list[int].get 会误解析为 list[str].get(返回元素地址)、list[str] 联合接收者的 .get 会误分派为 HashTable.get(索引 inttoptr 成 key 指针 → 零页崩溃);索引一律用 t.CPtr(base + i*8) + e[0]。
|
||
_g_pyi_cdef_names: str | t.CPtr = None
|
||
_g_pyi_cdef_vals: int64 | t.CPtr = None
|
||
_g_pyi_cdef_count: int = 0
|
||
|
||
|
||
def _lookup_cdefine_for_pyi(name: str) -> int64:
|
||
"""从本文件缓存 / 本地 CDefine 表查找常量值(用于 .vpi 生成时的 BinOp 计算)"""
|
||
global _g_pyi_cdefine_found
|
||
# 优先查本文件 CDefine 缓存(vpi 生成早于翻译阶段注册,全局表为空)
|
||
if _g_pyi_cdef_names is not None and _g_pyi_cdef_vals is not None:
|
||
# 循环上限用 _g_pyi_cdef_count,且绝不能用 len()/.get:i8** 指针数组上 len() 回退 strlen(基址当字符串算长度 → 垃圾小值 → 靠后注册项查不到),.get 会被误分派为 HashTable.get(索引 inttoptr 成 key 指针 → 零页崩溃);用 t.CPtr(base + i*8) + e[0] 依次取名。
|
||
pn: sizet = sizet(_g_pyi_cdef_count)
|
||
for pi in range(pn):
|
||
entry_pc: str | t.CPtr = (str | t.CPtr)(uint64(_g_pyi_cdef_names) + pi * 8)
|
||
pnm: str = entry_pc[0]
|
||
if pnm is not None and string.strcmp(pnm, name) == 0:
|
||
_g_pyi_cdefine_found = 1
|
||
return _g_pyi_cdef_vals[pi]
|
||
val: int64 = GenApi.lookup_cdefine_constant(name)
|
||
if GenApi.is_cdefine_found() != 0:
|
||
_g_pyi_cdefine_found = 1
|
||
return val
|
||
_g_pyi_cdefine_found = 0
|
||
return 0
|
||
|
||
|
||
def _eval_cdefine_value_cache(node: ast.AST*) -> int64:
|
||
"""求值 CDefine 值(Constant/UnaryOp/BinOp/Call/Name),供 vpi 预处理注册缓存"""
|
||
if node is None:
|
||
return 0
|
||
k: int = node.kind()
|
||
if k == ast.ASTKind.Constant:
|
||
cn_c: ast.Constant* = ast.Constant*(node)
|
||
if cn_c.const_kind == ast.CONST_INT:
|
||
return cn_c.int_val
|
||
if cn_c.const_kind == ast.CONST_BOOL:
|
||
return cn_c.int_val
|
||
# STR/FLOAT/NONE 不参与整数 BinOp 引用(注册 0 无害)
|
||
return 0
|
||
if k == ast.ASTKind.UnaryOp:
|
||
return _eval_binop_int(node)
|
||
if k == ast.ASTKind.BinOp:
|
||
return _eval_binop_int(node)
|
||
if k == ast.ASTKind.Call:
|
||
cl_c: ast.Call* = ast.Call*(node)
|
||
if cl_c.args is not None and len(cl_c.args) > 0:
|
||
return _eval_cdefine_value_cache(cl_c.args.get(0))
|
||
return 0
|
||
if k == ast.ASTKind.Name:
|
||
nm_c: ast.Name* = ast.Name*(node)
|
||
if nm_c.id is not None:
|
||
return _lookup_cdefine_for_pyi(nm_c.id)
|
||
return 0
|
||
return 0
|
||
|
||
|
||
def _pyi_cdefine_found() -> int:
|
||
"""返回上次 _lookup_cdefine_for_pyi 的查找结果状态"""
|
||
return _g_pyi_cdefine_found
|
||
|
||
|
||
# ============================================================
|
||
# _PyiEmit - 追加字符串到缓冲区
|
||
#
|
||
# 将 text 追加到 buf 的 pos 位置,返回新的 pos。
|
||
# 自动处理缓冲区溢出(截断)。
|
||
# ============================================================
|
||
def _PyiEmit(buf: bytes, buf_size: sizet, pos: sizet,
|
||
text: str) -> sizet:
|
||
"""追加 text 到 buf 的 pos 位置,返回新的 pos"""
|
||
if buf is None or text is None or pos >= buf_size:
|
||
return pos
|
||
tlen: sizet = string.strlen(text)
|
||
if tlen == 0:
|
||
return pos
|
||
remain: sizet = buf_size - pos
|
||
if tlen >= remain:
|
||
tlen = remain - 1
|
||
if tlen > 0:
|
||
string.memcpy(buf + pos, text, tlen)
|
||
return pos + tlen
|
||
|
||
|
||
# ============================================================
|
||
# _PyiIndent - 追加缩进空格
|
||
#
|
||
# 追加 level*4 个空格到 buf 的 pos 位置。
|
||
# ============================================================
|
||
def _PyiIndent(buf: bytes, buf_size: sizet, pos: sizet,
|
||
level: int) -> sizet:
|
||
"""追加 level*4 个空格到 buf,返回新的 pos"""
|
||
i: int = 0
|
||
while i < level:
|
||
pos = _PyiEmit(buf, buf_size, pos, " ")
|
||
i += 1
|
||
return pos
|
||
|
||
|
||
# ============================================================
|
||
# _PyiBinOpOpText - 输出二元运算符两侧的分隔文本
|
||
#
|
||
# 与 TPC StubGen/_GetTypeString 的 BinOp 运算符表逐字节一致(" | " / " + " /
|
||
# " - " / " * " / " / " / " % " / " & " / " >> ")。支持集必须两侧相同,否则
|
||
# 同一份源码写出的 .vpi 注解文本不同——旧实现恒写 " | ",使
|
||
# zhuff.vp `t.CArray[zhuff_decode_node, 2 * ZHUFF_MAX_CODES]` 写成
|
||
# `2 | ZHUFF_MAX_CODES`(读回端按位或算成 15,正确值 30 → 数组长度错)。
|
||
# 表外运算符 fail-fast:静默写错运算符会生成错误的类型/长度文本,
|
||
# 让下游按错误结果解析(与 TPC 落到未知节点 fail-fast 同语义)。
|
||
# ============================================================
|
||
def _PyiBinOpOpText(buf: bytes, buf_size: sizet, pos: sizet,
|
||
op: int, node: ast.AST*) -> sizet:
|
||
"""按运算符种类输出 " OP " 文本,表外运算符 fail-fast"""
|
||
if op == ast.OpKind.BitOr: return _PyiEmit(buf, buf_size, pos, " | ")
|
||
if op == ast.OpKind.Add: return _PyiEmit(buf, buf_size, pos, " + ")
|
||
if op == ast.OpKind.Sub: return _PyiEmit(buf, buf_size, pos, " - ")
|
||
if op == ast.OpKind.Mult: return _PyiEmit(buf, buf_size, pos, " * ")
|
||
if op == ast.OpKind.Div: return _PyiEmit(buf, buf_size, pos, " / ")
|
||
if op == ast.OpKind.Mod: return _PyiEmit(buf, buf_size, pos, " % ")
|
||
if op == ast.OpKind.BitAnd: return _PyiEmit(buf, buf_size, pos, " & ")
|
||
if op == ast.OpKind.RShift: return _PyiEmit(buf, buf_size, pos, " >> ")
|
||
GenApi.fatal_error(node, "vpi 类型注解节点类型未知", "TypeError")
|
||
return pos # 不可达(fatal_error 已退出)
|
||
|
||
|
||
# ============================================================
|
||
# _PyiTypeStr - 递归生成类型注解字符串
|
||
#
|
||
# 将 AST 类型注解节点转换为字符串表示,写入 buf 的 pos 位置。
|
||
# 支持集与 TPC StubGen/_GetTypeString 等价:
|
||
# Name, Attribute, Subscript, Tuple, BinOp, UnaryOp, Compare, BoolOp,
|
||
# Constant, List, Call
|
||
# 差异项:TPV 额外支持裸 Tuple(TPC 仅在 Subscript.slice 位置接受 Tuple);
|
||
# TPC 额外有 Index 分支(vast 遗留类,解析器不产出该节点)。
|
||
# ============================================================
|
||
def _PyiTypeStr(buf: bytes, buf_size: sizet, pos: sizet,
|
||
annot: ast.AST*,
|
||
depth: int = 0) -> sizet:
|
||
"""递归生成类型注解字符串,返回新的 pos"""
|
||
# 递归深度守卫:AST 损坏成自引用环(Attribute.value/Subscript.slice/
|
||
# BinOp.left 等回指祖先)时无限递归直至栈耗尽(Phase1 vpi 生成最先
|
||
# 执行,早于翻译阶段)。fail-fast 终止,不静默回退。
|
||
if depth > 64:
|
||
VLogger.error("vpi 类型注解递归过深(AST 环或嵌套超过 64 层)", "StubGen")
|
||
sys.exit(1)
|
||
if annot is None:
|
||
return _PyiEmit(buf, buf_size, pos, "int")
|
||
|
||
k: int = annot.kind()
|
||
|
||
# Name: 简单类型名 (如 int, str, MyClass)
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name* = ast.Name*(annot)
|
||
if nm.id is not None:
|
||
return _PyiEmit(buf, buf_size, pos, nm.id)
|
||
return _PyiEmit(buf, buf_size, pos, "int")
|
||
|
||
# Attribute: 属性引用 (如 int, memhub.MemBuddy)
|
||
if k == ast.ASTKind.Attribute:
|
||
at: ast.Attribute* = ast.Attribute*(annot)
|
||
pos = _PyiTypeStr(buf, buf_size, pos, at.value, depth + 1)
|
||
pos = _PyiEmit(buf, buf_size, pos, ".")
|
||
if at.attr is not None:
|
||
pos = _PyiEmit(buf, buf_size, pos, at.attr)
|
||
return pos
|
||
|
||
# Subscript: 下标类型 (如 list[int], t.CArray[elem, count])
|
||
if k == ast.ASTKind.Subscript:
|
||
sub: ast.Subscript* = ast.Subscript*(annot)
|
||
pos = _PyiTypeStr(buf, buf_size, pos, sub.value, depth + 1)
|
||
pos = _PyiEmit(buf, buf_size, pos, "[")
|
||
pos = _PyiTypeStr(buf, buf_size, pos, sub.slice, depth + 1)
|
||
pos = _PyiEmit(buf, buf_size, pos, "]")
|
||
return pos
|
||
|
||
# BinOp: 二元运算 (联合类型 int | str;CArray 计数表达式 MAX_ORDER + 1、
|
||
# 2 * ZHUFF_MAX_CODES;条件宏实参 MASK_BYTE & 0x0F)。
|
||
# 运算符文本按 _PyiBinOpOpText 输出,与 TPC 的运算符表逐字节一致。
|
||
if k == ast.ASTKind.BinOp:
|
||
bop: ast.BinOp* = ast.BinOp*(annot)
|
||
pos = _PyiTypeStr(buf, buf_size, pos, bop.left, depth + 1)
|
||
pos = _PyiBinOpOpText(buf, buf_size, pos, bop.op, annot)
|
||
pos = _PyiTypeStr(buf, buf_size, pos, bop.right, depth + 1)
|
||
return pos
|
||
|
||
# UnaryOp: 一元运算 (计数表达式 -1 / ~0;条件宏实参 not ct.isptr(x))。
|
||
# 输出与 TPC 的 UnaryOp 分支逐字节一致:Not → "not "、Invert → "~"、
|
||
# USub → "-";其余一元运算符两侧都不支持 → fail-fast(不静默写错符号)。
|
||
if k == ast.ASTKind.UnaryOp:
|
||
uop_t: ast.UnaryOp* = ast.UnaryOp*(annot)
|
||
if uop_t.op == ast.OpKind.Not:
|
||
pos = _PyiEmit(buf, buf_size, pos, "not ")
|
||
elif uop_t.op == ast.OpKind.Invert:
|
||
pos = _PyiEmit(buf, buf_size, pos, "~")
|
||
elif uop_t.op == ast.OpKind.USub:
|
||
pos = _PyiEmit(buf, buf_size, pos, "-")
|
||
else:
|
||
GenApi.fatal_error(annot, "vpi 类型注解节点类型未知", "TypeError")
|
||
return pos # 不可达(fatal_error 已退出)
|
||
return _PyiTypeStr(buf, buf_size, pos, uop_t.operand, depth + 1)
|
||
|
||
# Compare: 比较表达式 (条件宏实参 MAX_SIZE > 512 / val == 1)。
|
||
# 运算符文本与 TPC 的 Compare 分支逐字节一致:== != < <= > >=;
|
||
# 表外运算符(is/in 等)两侧一致输出 " ? "。
|
||
if k == ast.ASTKind.Compare:
|
||
cmp_t: rawptr[ast.Compare] = rawptr[ast.Compare](annot)
|
||
pos = _PyiTypeStr(buf, buf_size, pos, cmp_t.left, depth + 1)
|
||
ops_ct: list[int] | t.CPtr = (list[int] | t.CPtr)(cmp_t.ops)
|
||
cmps_ct: list[ast.AST*]* = cmp_t.comparators
|
||
if ops_ct is not None:
|
||
on_ct: sizet = len(ops_ct)
|
||
oi_ct: sizet = 0
|
||
while oi_ct < on_ct:
|
||
oid_ct: int = ops_ct.get(oi_ct)
|
||
if oid_ct == ast.OpKind.Eq: pos = _PyiEmit(buf, buf_size, pos, " == ")
|
||
elif oid_ct == ast.OpKind.Ne: pos = _PyiEmit(buf, buf_size, pos, " != ")
|
||
elif oid_ct == ast.OpKind.Lt: pos = _PyiEmit(buf, buf_size, pos, " < ")
|
||
elif oid_ct == ast.OpKind.Le: pos = _PyiEmit(buf, buf_size, pos, " <= ")
|
||
elif oid_ct == ast.OpKind.Gt: pos = _PyiEmit(buf, buf_size, pos, " > ")
|
||
elif oid_ct == ast.OpKind.Ge: pos = _PyiEmit(buf, buf_size, pos, " >= ")
|
||
else: pos = _PyiEmit(buf, buf_size, pos, " ? ")
|
||
# TPC 按 ops 的下标取 comparators[i];此处加长度守卫,
|
||
# 畸形 AST(ops/comparators 不等长)不越界。
|
||
if cmps_ct is not None and oi_ct < len(cmps_ct):
|
||
pos = _PyiTypeStr(buf, buf_size, pos, cmps_ct.get(oi_ct), depth + 1)
|
||
oi_ct += 1
|
||
return pos
|
||
|
||
# BoolOp: 布尔运算 (条件宏实参 ENABLED and MAX_SIZE > 0 / A or B)。
|
||
# 与 TPC 的 BoolOp 分支一致:and → " and "、or → " or "。
|
||
if k == ast.ASTKind.BoolOp:
|
||
bool_t: rawptr[ast.BoolOp] = rawptr[ast.BoolOp](annot)
|
||
vals_bt: list[ast.AST*]* = bool_t.values
|
||
if vals_bt is not None:
|
||
vn_bt: sizet = len(vals_bt)
|
||
vi_bt: sizet = 0
|
||
while vi_bt < vn_bt:
|
||
if vi_bt > 0:
|
||
if bool_t.op == ast.OpKind.Or:
|
||
pos = _PyiEmit(buf, buf_size, pos, " or ")
|
||
else:
|
||
pos = _PyiEmit(buf, buf_size, pos, " and ")
|
||
pos = _PyiTypeStr(buf, buf_size, pos, vals_bt.get(vi_bt), depth + 1)
|
||
vi_bt += 1
|
||
return pos
|
||
|
||
# Constant: 字符串前向引用 (如 'MyClass')、None 或数字常量(CArray count)
|
||
if k == ast.ASTKind.Constant:
|
||
cn: ast.Constant* = ast.Constant*(annot)
|
||
if cn.const_kind == ast.CONST_STR:
|
||
pos = _PyiEmit(buf, buf_size, pos, "'")
|
||
if cn.str_val is not None:
|
||
pos = _PyiEmit(buf, buf_size, pos, cn.str_val)
|
||
pos = _PyiEmit(buf, buf_size, pos, "'")
|
||
return pos
|
||
if cn.const_kind == ast.CONST_NONE:
|
||
return _PyiEmit(buf, buf_size, pos, "None")
|
||
# 数字常量(t.CArray[uint32, 64] 的 count 等):输出数值本身,
|
||
# 而不是回退 int——否则 vpi 生成 "t.CArray[..., int]" 在加载
|
||
# stub 时触发 TypeError(count 必须是整数常量、None、CDefine 常量名
|
||
# 或常量表达式)。
|
||
if cn.const_kind == ast.CONST_INT or cn.const_kind == ast.CONST_CHAR:
|
||
num_buf_ct: str = stdlib.malloc(24)
|
||
if num_buf_ct is not None:
|
||
viperlib.snprintf(num_buf_ct, 24, "%d", cn.int_val)
|
||
pos = _PyiEmit(buf, buf_size, pos, num_buf_ct)
|
||
stdlib.free(num_buf_ct)
|
||
return pos
|
||
return _PyiEmit(buf, buf_size, pos, "int")
|
||
|
||
# List: 函数指针参数表 (如 t.Callable[[t.CPtr, ULONG], BOOL] 的内层
|
||
# [t.CPtr, ULONG];t.Callable[[], int] 的空表)。TPV 的 AST 把 Callable
|
||
# 的参数表成型为 List(TypeGenResolve 的类型名提取同样按 List 递归),
|
||
# 故必须输出 "[a, b]" 形式——缺失该分支时该节点落入未知类型 fail-fast。
|
||
if k == ast.ASTKind.List:
|
||
lst: ast.List* = ast.List*(annot)
|
||
pos = _PyiEmit(buf, buf_size, pos, "[")
|
||
if lst.elts is not None:
|
||
lst_elts: list[ast.AST*]* = lst.elts
|
||
ln: sizet = len(lst_elts)
|
||
li: sizet = 0
|
||
while li < ln:
|
||
if li > 0:
|
||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||
le: ast.AST* = lst_elts.get(li)
|
||
pos = _PyiTypeStr(buf, buf_size, pos, le, depth + 1)
|
||
li += 1
|
||
pos = _PyiEmit(buf, buf_size, pos, "]")
|
||
return pos
|
||
|
||
# Tuple: 多参数下标 (如 Dict[str, int])
|
||
if k == ast.ASTKind.Tuple:
|
||
tup: ast.Tuple* = ast.Tuple*(annot)
|
||
if tup.elts is not None:
|
||
tup_elts: list[ast.AST*]* = tup.elts
|
||
tn: sizet = len(tup_elts)
|
||
ti: sizet = 0
|
||
while ti < tn:
|
||
if ti > 0:
|
||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||
el: ast.AST* = tup_elts.get(ti)
|
||
pos = _PyiTypeStr(buf, buf_size, pos, el, depth + 1)
|
||
ti += 1
|
||
return pos
|
||
|
||
# Call: 函数调用表达式 (用于装饰器如 @t.NoVTable())
|
||
if k == ast.ASTKind.Call:
|
||
cl: ast.Call* = ast.Call*(annot)
|
||
pos = _PyiTypeStr(buf, buf_size, pos, cl.func, depth + 1)
|
||
pos = _PyiEmit(buf, buf_size, pos, "(")
|
||
if cl.args is not None:
|
||
cl_args: list[ast.AST*]* = cl.args
|
||
can: sizet = len(cl_args)
|
||
cai: sizet = 0
|
||
while cai < can:
|
||
if cai > 0:
|
||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||
ca: ast.AST* = cl_args.get(cai)
|
||
pos = _PyiTypeStr(buf, buf_size, pos, ca, depth + 1)
|
||
cai += 1
|
||
pos = _PyiEmit(buf, buf_size, pos, ")")
|
||
return pos
|
||
|
||
# 未知节点类型 fail-fast:走到此处说明 AST 损坏或出现未支持的注解形态,报错退出(静默写 "int" 会生成错误签名,让下游按错误类型解析)
|
||
GenApi.fatal_error(annot, "vpi 类型注解节点类型未知", "TypeError")
|
||
return _PyiEmit(buf, buf_size, pos, "int") # 不可达(fatal_error 已退出)
|
||
|
||
|
||
# ============================================================
|
||
# _PyiDefaultStr - 生成默认值表达式文本
|
||
#
|
||
# 用于 vpi 签名 '= <default>' 输出(如 depth: int = 0)。
|
||
# vpi stub 必须保留默认值:VpiReader 解析后注册默认参数表,
|
||
# 跨模块缺参调用(如 resolve_annotation_type 的 depth=0)才能
|
||
# 用默认值填充,否则被调函数读到栈垃圾(假报递归过深/崩溃)。
|
||
# 支持: Constant(int/str/bool/None), Name(CDefine 常量), UnaryOp。
|
||
# ============================================================
|
||
def _PyiDefaultStr(buf: bytes, buf_size: sizet, pos: sizet,
|
||
node: ast.AST*,
|
||
depth: int = 0) -> sizet:
|
||
"""生成默认值表达式文本到 buf,返回新的 pos"""
|
||
# 递归深度守卫:AST 损坏成自引用环时 fail-fast 终止(同 _PyiTypeStr)
|
||
if depth > 64:
|
||
VLogger.error("vpi 默认值表达式递归过深(AST 环或嵌套超过 64 层)", "StubGen")
|
||
sys.exit(1)
|
||
if node is None:
|
||
return pos
|
||
|
||
k: int = node.kind()
|
||
# Constant: 数字/字符串/bool/None 直接输出字面量
|
||
if k == ast.ASTKind.Constant:
|
||
cn: ast.Constant* = ast.Constant*(node)
|
||
if cn.const_kind == ast.CONST_INT or cn.const_kind == ast.CONST_CHAR:
|
||
num_buf_dv: str = stdlib.malloc(24)
|
||
if num_buf_dv is not None:
|
||
viperlib.snprintf(num_buf_dv, 24, "%d", cn.int_val)
|
||
pos = _PyiEmit(buf, buf_size, pos, num_buf_dv)
|
||
stdlib.free(num_buf_dv)
|
||
return pos
|
||
if cn.const_kind == ast.CONST_STR:
|
||
pos = _PyiEmit(buf, buf_size, pos, "\"")
|
||
if cn.str_val is not None:
|
||
pos = _PyiEmit(buf, buf_size, pos, cn.str_val)
|
||
return _PyiEmit(buf, buf_size, pos, "\"")
|
||
if cn.const_kind == ast.CONST_BOOL:
|
||
if cn.int_val != 0:
|
||
return _PyiEmit(buf, buf_size, pos, "True")
|
||
return _PyiEmit(buf, buf_size, pos, "False")
|
||
if cn.const_kind == ast.CONST_NONE:
|
||
return _PyiEmit(buf, buf_size, pos, "None")
|
||
return pos
|
||
|
||
# Name: CDefine 常量名(如 share: ULONG = SHARE_READ)
|
||
if k == ast.ASTKind.Name:
|
||
nm: ast.Name* = ast.Name*(node)
|
||
if nm.id is not None:
|
||
return _PyiEmit(buf, buf_size, pos, nm.id)
|
||
return pos
|
||
|
||
# UnaryOp: 一元运算(如 -1, ~0)
|
||
if k == ast.ASTKind.UnaryOp:
|
||
uop: ast.UnaryOp* = ast.UnaryOp*(node)
|
||
if uop.op == ast.OpKind.USub:
|
||
pos = _PyiEmit(buf, buf_size, pos, "-")
|
||
elif uop.op == ast.OpKind.UAdd:
|
||
pos = _PyiEmit(buf, buf_size, pos, "+")
|
||
elif uop.op == ast.OpKind.Invert:
|
||
pos = _PyiEmit(buf, buf_size, pos, "~")
|
||
else:
|
||
return pos
|
||
if uop.operand is not None:
|
||
return _PyiDefaultStr(buf, buf_size, pos, uop.operand, depth + 1)
|
||
return pos
|
||
|
||
# 其它(BinOp 等复杂表达式):不输出,保持无默认值(fail-fast 由调用侧兜底)
|
||
return pos
|
||
|
||
|
||
# ============================================================
|
||
# _PyiRejectCReturnDecorator - 装饰器列表里出现 @c.CReturn 即编译期报错
|
||
#
|
||
# @c.CReturn 已移除:多返回值统一用返回注解 `-> tuple[ty1, ty2, ...]`
|
||
# (既有 tuple → struct 通路保留)。vpi 里仍带该装饰器意味着存根过旧,
|
||
# fail-fast 提示重新生成,不静默忽略。返回 0 = 装饰器列表里没有 CReturn。
|
||
# ============================================================
|
||
def _PyiRejectCReturnDecorator(node: ast.AST*,
|
||
decorators: list[ast.AST*]*) -> int:
|
||
"""装饰器列表里出现 @c.CReturn 即 fatal_error(返回 0 = 无该装饰器)"""
|
||
if decorators is None:
|
||
return 0
|
||
dn: sizet = len(decorators)
|
||
di: sizet = 0
|
||
while di < dn:
|
||
dnode: ast.AST* = decorators.get(di)
|
||
di += 1
|
||
if dnode is None:
|
||
continue
|
||
# 兼容 @c.CReturn(...)(Call(func=Attribute))与裸 @c.CReturn(Attribute)两形态
|
||
dattr: ast.Attribute* = None
|
||
if dnode.kind() == ast.ASTKind.Call:
|
||
dcall: ast.Call* = ast.Call*(dnode)
|
||
if dcall.func is not None and dcall.func.kind() == ast.ASTKind.Attribute:
|
||
dattr = ast.Attribute*(dcall.func)
|
||
elif dnode.kind() == ast.ASTKind.Attribute:
|
||
dattr = ast.Attribute*(dnode)
|
||
if dattr is None or dattr.attr is None:
|
||
continue
|
||
if string.strcmp(dattr.attr, "CReturn") == 0:
|
||
GenApi.fatal_error(node, "vpi 中仍带 `@c.CReturn`(已移除):请用返回注解 `-> tuple[ty1, ty2, ...]` 重新生成该 .vpi(可加 --clean)", "TypeError")
|
||
return 1
|
||
return 0
|
||
|
||
|
||
# ============================================================
|
||
# _PyiFunction - 生成函数签名
|
||
#
|
||
# 格式: def name(param: Type, ...) -> ReturnType: pass
|
||
# ============================================================
|
||
def _PyiFunction(buf: bytes, buf_size: sizet, pos: sizet,
|
||
fn: ast.FunctionDef*,
|
||
indent_level: int, class_name: str) -> sizet:
|
||
"""生成函数签名到 buf,返回新的 pos"""
|
||
# 装饰器
|
||
if fn.decorator_list is not None:
|
||
fn_decorator_list: list[ast.AST*]* = fn.decorator_list
|
||
dn: sizet = len(fn_decorator_list)
|
||
di: sizet = 0
|
||
while di < dn:
|
||
dec: ast.AST* = fn_decorator_list.get(di)
|
||
if dec is not None:
|
||
pos = _PyiIndent(buf, buf_size, pos, indent_level)
|
||
pos = _PyiEmit(buf, buf_size, pos, "@")
|
||
pos = _PyiTypeStr(buf, buf_size, pos, dec)
|
||
pos = _PyiEmit(buf, buf_size, pos, "\n")
|
||
di += 1
|
||
|
||
pos = _PyiIndent(buf, buf_size, pos, indent_level)
|
||
pos = _PyiEmit(buf, buf_size, pos, "def ")
|
||
if fn.name is not None:
|
||
pos = _PyiEmit(buf, buf_size, pos, fn.name)
|
||
pos = _PyiEmit(buf, buf_size, pos, "(")
|
||
|
||
# 参数列表
|
||
args_node: ast.AST* = fn.args
|
||
if args_node is not None:
|
||
args: ast.Arguments* = ast.Arguments*(args_node)
|
||
first: int = 1
|
||
|
||
# 位置参数
|
||
if args.args is not None:
|
||
args_args: list[ast.AST*]* = args.args
|
||
an: sizet = len(args_args)
|
||
# 默认值右对齐到 args 尾部:defaults[i] 对应 args[an - dn + i]。
|
||
# 必须输出 '= <default>',否则 VpiReader 解析出的默认参数表无条目,跨模块缺参调用(如 depth=0)读到栈垃圾。
|
||
# arg_defaults 必须内联声明:联合接收者的 .get 会被误分派,预声明 + 重赋值会解析成 list[int].get 返回 i32 截断指针而崩溃。
|
||
arg_defaults: list[ast.AST*]* = args.defaults
|
||
dn: sizet = 0
|
||
if arg_defaults is not None:
|
||
dn = len(arg_defaults)
|
||
ai: sizet = 0
|
||
while ai < an:
|
||
if first == 0:
|
||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||
first = 0
|
||
ag: ast.Arg* = ast.Arg*(args_args.get(ai))
|
||
if ag.arg is not None:
|
||
pos = _PyiEmit(buf, buf_size, pos, ag.arg)
|
||
if ag.annotation is not None:
|
||
pos = _PyiEmit(buf, buf_size, pos, ": ")
|
||
pos = _PyiTypeStr(buf, buf_size, pos, ag.annotation)
|
||
if arg_defaults is not None and an - dn <= ai:
|
||
di: sizet = ai - (an - dn)
|
||
dnode: ast.AST* = arg_defaults.get(di)
|
||
if dnode is not None:
|
||
pos = _PyiEmit(buf, buf_size, pos, " = ")
|
||
pos = _PyiDefaultStr(buf, buf_size, pos, dnode)
|
||
ai += 1
|
||
|
||
# *args
|
||
if args.vararg is not None:
|
||
if first == 0:
|
||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||
first = 0
|
||
pos = _PyiEmit(buf, buf_size, pos, "*")
|
||
va: ast.Arg* = ast.Arg*(args.vararg)
|
||
if va.arg is not None:
|
||
pos = _PyiEmit(buf, buf_size, pos, va.arg)
|
||
|
||
# **kwargs
|
||
if args.kwarg is not None:
|
||
if first == 0:
|
||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||
first = 0
|
||
pos = _PyiEmit(buf, buf_size, pos, "**")
|
||
kw: ast.Arg* = ast.Arg*(args.kwarg)
|
||
if kw.arg is not None:
|
||
pos = _PyiEmit(buf, buf_size, pos, kw.arg)
|
||
|
||
pos = _PyiEmit(buf, buf_size, pos, ")")
|
||
|
||
# 返回类型
|
||
if fn.returns is not None:
|
||
pos = _PyiEmit(buf, buf_size, pos, " -> ")
|
||
pos = _PyiTypeStr(buf, buf_size, pos, fn.returns)
|
||
else:
|
||
# 无 `->` 注解时若带 @c.CReturn(...):该装饰器已移除,fail-fast 提示重生成 vpi
|
||
_PyiRejectCReturnDecorator(fn, fn.decorator_list)
|
||
|
||
pos = _PyiEmit(buf, buf_size, pos, ": pass\n")
|
||
return pos
|
||
|
||
|
||
# ============================================================
|
||
# _PyiClass - 生成类定义
|
||
#
|
||
# 格式:
|
||
# class Name(Base):
|
||
# field: Type
|
||
# def method(self: Name, ...) -> RetType: pass
|
||
# ============================================================
|
||
def _PyiClass(buf: bytes, buf_size: sizet, pos: sizet,
|
||
cls: ast.ClassDef*, indent_level: int) -> sizet:
|
||
"""生成类定义到 buf,返回新的 pos"""
|
||
# 装饰器
|
||
if cls.decorator_list is not None:
|
||
cls_decorator_list: list[ast.AST*]* = cls.decorator_list
|
||
dcn: sizet = len(cls_decorator_list)
|
||
dci: sizet = 0
|
||
while dci < dcn:
|
||
ddec: ast.AST* = cls_decorator_list.get(dci)
|
||
if ddec is not None:
|
||
pos = _PyiIndent(buf, buf_size, pos, indent_level)
|
||
pos = _PyiEmit(buf, buf_size, pos, "@")
|
||
pos = _PyiTypeStr(buf, buf_size, pos, ddec)
|
||
pos = _PyiEmit(buf, buf_size, pos, "\n")
|
||
dci += 1
|
||
|
||
pos = _PyiIndent(buf, buf_size, pos, indent_level)
|
||
pos = _PyiEmit(buf, buf_size, pos, "class ")
|
||
if cls.name is not None:
|
||
pos = _PyiEmit(buf, buf_size, pos, cls.name)
|
||
|
||
# PEP 695 类型参数 (class Foo[T]:)
|
||
if cls.type_params is not None:
|
||
# ClassDef.type_params 的真身是 rawptr[list[str]](**名字串**列表,
|
||
# 见 includes/ast/stmts.vp:475-483 与 parser.vp:3619-3663 的
|
||
# `list[str](ps.pool, 8)`),不是 `list[rawptr[AST]]`(那是 decorator_list
|
||
# 的类型)。原注解从 decorator_list 抄错成 list[ast.AST*]* ⇒ .get() 被解析到
|
||
# list[ast.AST*].get,而实参是 list[str]* ⇒ 严格规则下 fail-fast:
|
||
# "调用 ...list[AST*].get 第 0 个实参 %"...list[str]"* 不能隐式转为形参
|
||
# %"...list[AST*]"*"
|
||
# 全仓其余 8 处 type_params 均为 list[str]*(VpiReader/Phase1Scan/Phase2/
|
||
# ClassGenDef/ClassGenGeneric 等),此处对齐。
|
||
cls_type_params: list[str]* = cls.type_params
|
||
tpn: sizet = len(cls_type_params)
|
||
if tpn > 0:
|
||
pos = _PyiEmit(buf, buf_size, pos, "[")
|
||
tpi: sizet = 0
|
||
while tpi < tpn:
|
||
if tpi > 0:
|
||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||
tpname: str = cls_type_params.get(tpi)
|
||
if tpname is not None:
|
||
pos = _PyiEmit(buf, buf_size, pos, tpname)
|
||
tpi += 1
|
||
pos = _PyiEmit(buf, buf_size, pos, "]")
|
||
|
||
# 基类
|
||
if cls.bases is not None:
|
||
cls_bases: list[ast.AST*]* = cls.bases
|
||
bn: sizet = len(cls_bases)
|
||
if bn > 0:
|
||
pos = _PyiEmit(buf, buf_size, pos, "(")
|
||
bi: sizet = 0
|
||
while bi < bn:
|
||
if bi > 0:
|
||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||
base: ast.AST* = cls_bases.get(bi)
|
||
pos = _PyiTypeStr(buf, buf_size, pos, base)
|
||
bi += 1
|
||
pos = _PyiEmit(buf, buf_size, pos, ")")
|
||
|
||
pos = _PyiEmit(buf, buf_size, pos, ":\n")
|
||
|
||
# 类成员
|
||
has_member: int = 0
|
||
|
||
if cls.children is not None:
|
||
cls_children: list[ast.AST*]* = cls.children
|
||
cn: sizet = len(cls_children)
|
||
ci: sizet = 0
|
||
while ci < cn:
|
||
stmt: ast.AST* = cls_children.get(ci)
|
||
if stmt is not None:
|
||
sk: int = stmt.kind()
|
||
|
||
# 方法
|
||
if sk == ast.ASTKind.FunctionDef:
|
||
mfn: ast.FunctionDef* = ast.FunctionDef*(stmt)
|
||
# __init__ 方法:先提取 self.x: Type 属性
|
||
if mfn.name is not None and string.strcmp(mfn.name, "__init__") == 0:
|
||
if mfn.children is not None:
|
||
mfn_children: list[ast.AST*]* = mfn.children
|
||
icn: sizet = len(mfn_children)
|
||
ici: sizet = 0
|
||
while ici < icn:
|
||
ibody: ast.AST* = mfn_children.get(ici)
|
||
if ibody is not None and ibody.kind() == ast.ASTKind.AnnAssign:
|
||
iaa: ast.AnnAssign* = ast.AnnAssign*(ibody)
|
||
if iaa.target is not None and iaa.target.kind() == ast.ASTKind.Attribute:
|
||
iat: ast.Attribute* = ast.Attribute*(iaa.target)
|
||
# 检查 target.value 是否为 Name("self")
|
||
if iat.value is not None and iat.value.kind() == ast.ASTKind.Name:
|
||
iavn: ast.Name* = ast.Name*(iat.value)
|
||
if iavn.id is None or string.strcmp(iavn.id, "self") != 0:
|
||
ici += 1
|
||
continue
|
||
pos = _PyiIndent(buf, buf_size, pos, indent_level + 1)
|
||
if iat.attr is not None:
|
||
pos = _PyiEmit(buf, buf_size, pos, iat.attr)
|
||
pos = _PyiEmit(buf, buf_size, pos, ": ")
|
||
pos = _PyiTypeStr(buf, buf_size, pos, iaa.annotation)
|
||
pos = _PyiEmit(buf, buf_size, pos, "\n")
|
||
has_member = 1
|
||
ici += 1
|
||
pos = _PyiFunction(buf, buf_size, pos, mfn, indent_level + 1, cls.name)
|
||
has_member = 1
|
||
|
||
# 带注解的属性
|
||
elif sk == ast.ASTKind.AnnAssign:
|
||
aa: ast.AnnAssign* = ast.AnnAssign*(stmt)
|
||
if aa.target is not None and aa.target.kind() == ast.ASTKind.Name:
|
||
tn: ast.Name* = ast.Name*(aa.target)
|
||
pos = _PyiIndent(buf, buf_size, pos, indent_level + 1)
|
||
if tn.id is not None:
|
||
pos = _PyiEmit(buf, buf_size, pos, tn.id)
|
||
pos = _PyiEmit(buf, buf_size, pos, ": ")
|
||
pos = _PyiTypeStr(buf, buf_size, pos, aa.annotation)
|
||
pos = _PyiEmit(buf, buf_size, pos, "\n")
|
||
has_member = 1
|
||
|
||
# 嵌套类
|
||
elif sk == ast.ASTKind.ClassDef:
|
||
ncls: ast.ClassDef* = ast.ClassDef*(stmt)
|
||
pos = _PyiClass(buf, buf_size, pos, ncls, indent_level + 1)
|
||
has_member = 1
|
||
ci += 1
|
||
|
||
# 空类补 pass
|
||
if has_member == 0:
|
||
pos = _PyiIndent(buf, buf_size, pos, indent_level + 1)
|
||
pos = _PyiEmit(buf, buf_size, pos, "pass\n")
|
||
|
||
return pos
|
||
|
||
|
||
# ============================================================
|
||
# _GeneratePyiFromAst - 遍历 AST Module 节点,提取函数签名/类定义/变量声明/import 语句,生成 .vpi 存根文件内容到 buf
|
||
#
|
||
# Args: mb 内存池(保留以符合调用约定,实际未使用);tree AST Module 根节点;rel_path 源文件路径(仅用于报错归因的"当前文件",应传绝对路径以便 fatal_error 读取源码行);buf 输出缓冲区;buf_size 缓冲区大小
|
||
# Returns: 写入的字节数(0 表示失败)
|
||
# ============================================================
|
||
def _GeneratePyiFromAst(mb: memhub.MemBuddy*, tree: ast.AST*,
|
||
rel_path: str, buf: bytes,
|
||
buf_size: sizet) -> sizet:
|
||
"""从 AST 生成 .vpi 存根文件内容到 buf"""
|
||
if tree is None or buf is None or buf_size == 0:
|
||
return 0
|
||
|
||
# 错误归因:把"当前文件"指向正在生成 stub 的这份(rel_path 非 None 时)。
|
||
# 本函数内触发的 fatal_error(如 L227/L303/L430 的注解节点类型未知)应指向
|
||
# 本源文件,而非上一次 set_current_file 的残留文件。
|
||
# 调用侧必须传**绝对路径**:fatal_error 的 _read_source_line 直接用该路径
|
||
# 打开文件读取行,传相对路径会打不开 ⇒ 误报"无法读取该行源码"。
|
||
# 放在函数入口而非各分支:全函数共用同一套遍历/报错路径,逐分支设置会漏掉
|
||
# 中途新增的分支;入口设一次覆盖全部(含后续所有 fatal_error / push_trace)。
|
||
# rel_path 为 None 时不改写 CurrentFile(保持上一次设置值):调用侧确实拿不到
|
||
# 路径时,宁可沿用"上一次设置的文件"也不要把归因抹成 None。
|
||
if rel_path is not None:
|
||
GenApi.set_current_file_type(rel_path)
|
||
|
||
pos: sizet = 0
|
||
|
||
# 预处理:按声明顺序注册本文件 CDefine 到 _g_pyi 缓存(vpi 生成早于翻译阶段注册,直接查全局表为空会使 BinOp 内 Name 引用退化为 0,跨模块读回错误常量)。
|
||
# 必须带 global 声明:TPV 语义下函数内对模块级变量赋值无 global 时会创建局部变量,_lookup_cdefine_for_pyi 读到的仍是模块级 None,缓存永不命中。
|
||
global _g_pyi_cdef_names, _g_pyi_cdef_vals, _g_pyi_cdef_count
|
||
if tree.children is not None:
|
||
pre_children: list[ast.AST*]* = tree.children
|
||
pcn: sizet = len(pre_children)
|
||
# 第一遍:数本文件 t.CDefine 声明数(C 数组需先定长分配)
|
||
_g_pyi_cdef_count = 0
|
||
for pci0 in range(pcn):
|
||
stmt_pc0: ast.AST* = pre_children.get(pci0)
|
||
if stmt_pc0 is not None and stmt_pc0.kind() == ast.ASTKind.AnnAssign:
|
||
aa_pc0: ast.AnnAssign* = ast.AnnAssign*(stmt_pc0)
|
||
if aa_pc0.target is not None and aa_pc0.target.kind() == ast.ASTKind.Name \
|
||
and aa_pc0.annotation is not None:
|
||
tgt_pc0: ast.Name* = ast.Name*(aa_pc0.target)
|
||
if tgt_pc0.id is not None and aa_pc0.annotation.kind() == ast.ASTKind.Attribute:
|
||
ann_pc0: ast.Attribute* = ast.Attribute*(aa_pc0.annotation)
|
||
if ann_pc0.attr is not None and string.strcmp(ann_pc0.attr, "CDefine") == 0:
|
||
_g_pyi_cdef_count += 1
|
||
if _g_pyi_cdef_count > 0:
|
||
_g_pyi_cdef_names = (str | t.CPtr)(mb.alloc(sizet(_g_pyi_cdef_count) * 8))
|
||
_g_pyi_cdef_vals = (int64 | t.CPtr)(mb.alloc(sizet(_g_pyi_cdef_count) * 8))
|
||
# 第二遍:按声明顺序注册(BinOp 内 Name 引用依赖先前注册项)
|
||
pci: sizet = 0
|
||
cdi: int = 0
|
||
for pci in range(pcn):
|
||
stmt_pc: ast.AST* = pre_children.get(pci)
|
||
if stmt_pc is not None and stmt_pc.kind() == ast.ASTKind.AnnAssign:
|
||
aa_pc: ast.AnnAssign* = ast.AnnAssign*(stmt_pc)
|
||
if aa_pc.target is not None and aa_pc.target.kind() == ast.ASTKind.Name \
|
||
and aa_pc.annotation is not None:
|
||
tgt_pc: ast.Name* = ast.Name*(aa_pc.target)
|
||
if tgt_pc.id is not None and aa_pc.annotation.kind() == ast.ASTKind.Attribute:
|
||
ann_pc: ast.Attribute* = ast.Attribute*(aa_pc.annotation)
|
||
if ann_pc.attr is not None and string.strcmp(ann_pc.attr, "CDefine") == 0:
|
||
if _g_pyi_cdef_names is not None and _g_pyi_cdef_vals is not None:
|
||
slot_pc: str | t.CPtr = (str | t.CPtr)(uint64(_g_pyi_cdef_names) + cdi * 8)
|
||
slot_pc[0] = tgt_pc.id
|
||
_g_pyi_cdef_vals[cdi] = _eval_cdefine_value_cache(aa_pc.value)
|
||
cdi += 1
|
||
|
||
# 文件头
|
||
pos = _PyiEmit(buf, buf_size, pos, "\"\"\"Auto-generated Python stub file\"\"\"\n\n")
|
||
|
||
if tree.children is None:
|
||
if pos < buf_size:
|
||
buf[pos] = 0
|
||
return pos
|
||
|
||
tree_children: list[ast.AST*]* = tree.children
|
||
n: sizet = len(tree_children)
|
||
|
||
# 第一遍扫描:检测 import t/c
|
||
has_import_t: int = 0
|
||
has_import_c: int = 0
|
||
for i in range(n):
|
||
stmt: ast.AST* = tree_children.get(i)
|
||
if stmt is not None and stmt.kind() == ast.ASTKind.Import:
|
||
imp: ast.Import* = ast.Import*(stmt)
|
||
if imp.names is not None:
|
||
imp_names: list[ast.AST*]* = imp.names
|
||
an: sizet = len(imp_names)
|
||
for ai in range(an):
|
||
al: ast.Alias* = ast.Alias*(imp_names.get(ai))
|
||
if al is not None and al.name is not None:
|
||
if string.strcmp(al.name, "t") == 0:
|
||
has_import_t = 1
|
||
elif string.strcmp(al.name, "c") == 0:
|
||
has_import_c = 1
|
||
|
||
# 补充缺失的 import t/c
|
||
if has_import_t == 0 and has_import_c == 0:
|
||
pos = _PyiEmit(buf, buf_size, pos, "import t, c\n\n")
|
||
elif has_import_t == 0:
|
||
pos = _PyiEmit(buf, buf_size, pos, "import t\n\n")
|
||
elif has_import_c == 0:
|
||
pos = _PyiEmit(buf, buf_size, pos, "import c\n\n")
|
||
else:
|
||
pos = _PyiEmit(buf, buf_size, pos, "\n")
|
||
|
||
# 第二遍扫描:生成声明
|
||
for i in range(n):
|
||
stmt = tree_children.get(i)
|
||
if stmt is not None:
|
||
k: int = stmt.kind()
|
||
|
||
# Import 语句
|
||
if k == ast.ASTKind.Import:
|
||
imp2: ast.Import* = ast.Import*(stmt)
|
||
pos = _PyiEmit(buf, buf_size, pos, "import ")
|
||
# fail-fast:别名列表为空 ⇒ 写出 `import ` 这种残缺行,import 名字
|
||
# 全丢,包重导出注册随之失效(与下面逐个别名为空的检查互补)。
|
||
if imp2.names is None or len(imp2.names) == 0:
|
||
GenApi.fatal_error(stmt,
|
||
"vpi 生成:import 语句别名列表为空(应为 ≥1 个别名)——AST 构造/解析异常",
|
||
"NameError")
|
||
if imp2.names is not None:
|
||
imp2_names: list[ast.AST*]* = imp2.names
|
||
an2: sizet = len(imp2_names)
|
||
ai2: sizet = 0
|
||
while ai2 < an2:
|
||
if ai2 > 0:
|
||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||
al2: ast.Alias* = ast.Alias*(imp2_names.get(ai2))
|
||
# fail-fast:别名节点或其名字为空 ⇒ 绝不静默写出 "import , "。
|
||
# vpi 里 import 行的名字是**包重导出注册的唯一输入**
|
||
# (VpiReader._inject_reexport_class_declare 靠它把子模块里的类以
|
||
# 包 __init__ 的 sha1 注册别名 entry),名字静默丢失会让 `包.类`
|
||
# 形式的模块限定注解解析落空,下游报出与根因无关的 NameError
|
||
# (实测:ast/__init__.vpi 的 `from .base import , , ,` 名字全空
|
||
# ⇒ ast.AST 报"方法 'Result.__init__' 形参 'elem' 类型注解解析失败")。
|
||
# 两种成因分开报,便于一次定位:节点指针为空 = Alias 构造失败;
|
||
# 节点在而 name 为空 = _copy_str/__init__ 未生效。
|
||
if al2 is None:
|
||
GenApi.fatal_error(stmt,
|
||
"vpi 生成:import 别名**节点指针为空**(Alias(...) 构造未产出对象:"
|
||
"pool.alloc 失败或 __init__ 未执行)——import 名字丢失会破坏包重导出注册",
|
||
"NameError")
|
||
if al2.name is None or al2.name[0] == '\0':
|
||
GenApi.fatal_error(stmt,
|
||
"vpi 生成:import 别名节点存在但 **name 为空**(_copy_str 返回 None / "
|
||
"__init__ 未赋值 name)——import 名字丢失会破坏包重导出注册",
|
||
"NameError")
|
||
pos = _PyiEmit(buf, buf_size, pos, al2.name)
|
||
if al2.asname is not None and string.strlen(al2.asname) > 0:
|
||
pos = _PyiEmit(buf, buf_size, pos, " as ")
|
||
pos = _PyiEmit(buf, buf_size, pos, al2.asname)
|
||
ai2 += 1
|
||
pos = _PyiEmit(buf, buf_size, pos, "\n")
|
||
|
||
# ImportFrom 语句
|
||
elif k == ast.ASTKind.ImportFrom:
|
||
ifr: ast.ImportFrom* = ast.ImportFrom*(stmt)
|
||
pos = _PyiEmit(buf, buf_size, pos, "from ")
|
||
lvl: int = ifr.level
|
||
while lvl > 0:
|
||
pos = _PyiEmit(buf, buf_size, pos, ".")
|
||
lvl -= 1
|
||
if ifr.module is not None:
|
||
pos = _PyiEmit(buf, buf_size, pos, ifr.module)
|
||
pos = _PyiEmit(buf, buf_size, pos, " import ")
|
||
# fail-fast:同 Import 分支——`from X import *` 走的是 Alias("*"),
|
||
# 列表为空或名字为空都说明 AST 坏;静默写出 `from X import ` 会让
|
||
# 包重导出注册失效(star 也用于 re-export 判断)。
|
||
if ifr.names is None or len(ifr.names) == 0:
|
||
GenApi.fatal_error(stmt,
|
||
"vpi 生成:from-import 语句别名列表为空(应为 ≥1 个别名,含 '*')"
|
||
"——AST 构造/解析异常",
|
||
"NameError")
|
||
if ifr.names is not None:
|
||
ifr_names: list[ast.AST*]* = ifr.names
|
||
an3: sizet = len(ifr_names)
|
||
ai3: sizet = 0
|
||
while ai3 < an3:
|
||
if ai3 > 0:
|
||
pos = _PyiEmit(buf, buf_size, pos, ", ")
|
||
al3: ast.Alias* = ast.Alias*(ifr_names.get(ai3))
|
||
# fail-fast:同 Import 分支(两种成因分开报,一次定位)。
|
||
if al3 is None:
|
||
GenApi.fatal_error(stmt,
|
||
"vpi 生成:from-import 别名**节点指针为空**(Alias(...) 构造未产出对象:"
|
||
"pool.alloc 失败或 __init__ 未执行)——包重导出注册会因此失效",
|
||
"NameError")
|
||
if al3.name is None or al3.name[0] == '\0':
|
||
GenApi.fatal_error(stmt,
|
||
"vpi 生成:from-import 别名节点存在但 **name 为空**(_copy_str 返回 None / "
|
||
"__init__ 未赋值 name)——包重导出注册会因此失效",
|
||
"NameError")
|
||
pos = _PyiEmit(buf, buf_size, pos, al3.name)
|
||
if al3.asname is not None and string.strlen(al3.asname) > 0:
|
||
pos = _PyiEmit(buf, buf_size, pos, " as ")
|
||
pos = _PyiEmit(buf, buf_size, pos, al3.asname)
|
||
ai3 += 1
|
||
pos = _PyiEmit(buf, buf_size, pos, "\n")
|
||
|
||
# 函数定义(_PyiFunction 已以 "\n" 收尾,不再补空行)
|
||
elif k == ast.ASTKind.FunctionDef:
|
||
fn: ast.FunctionDef* = ast.FunctionDef*(stmt)
|
||
pos = _PyiFunction(buf, buf_size, pos, fn, 0, "")
|
||
|
||
# 类定义
|
||
elif k == ast.ASTKind.ClassDef:
|
||
cls: ast.ClassDef* = ast.ClassDef*(stmt)
|
||
pos = _PyiClass(buf, buf_size, pos, cls, 0)
|
||
|
||
# 带注解的变量声明
|
||
elif k == ast.ASTKind.AnnAssign:
|
||
aa: ast.AnnAssign* = ast.AnnAssign*(stmt)
|
||
if aa.target is not None and aa.target.kind() == ast.ASTKind.Name:
|
||
nm: ast.Name* = ast.Name*(aa.target)
|
||
if nm.id is not None:
|
||
pos = _PyiEmit(buf, buf_size, pos, nm.id)
|
||
pos = _PyiEmit(buf, buf_size, pos, ": ")
|
||
pos = _PyiTypeStr(buf, buf_size, pos, aa.annotation)
|
||
# 如果有值(如 CDefine 常量),输出 = value
|
||
# CTypedef 特殊处理:值是类型表达式(如 VOIDPTR / t.CPtr),
|
||
# 不是整数,用 _PyiTypeStr 输出类型字符串
|
||
is_ctypedef_ann: int = 0
|
||
if aa.annotation is not None and aa.annotation.kind() == ast.ASTKind.Attribute:
|
||
ctd_at: ast.Attribute* = ast.Attribute*(aa.annotation)
|
||
if ctd_at.attr is not None and string.strcmp(ctd_at.attr, "CTypedef") == 0:
|
||
if ctd_at.value is not None and ctd_at.value.kind() == ast.ASTKind.Name:
|
||
ctd_mod: ast.Name* = ast.Name*(ctd_at.value)
|
||
if ctd_mod.id is not None and string.strcmp(ctd_mod.id, "t") == 0:
|
||
is_ctypedef_ann = 1
|
||
if is_ctypedef_ann != 0 and aa.value is not None:
|
||
pos = _PyiEmit(buf, buf_size, pos, " = ")
|
||
pos = _PyiTypeStr(buf, buf_size, pos, aa.value)
|
||
elif aa.value is not None and aa.value.kind() == ast.ASTKind.Constant:
|
||
cv: ast.Constant* = ast.Constant*(aa.value)
|
||
num_buf: bytes = mb.alloc(32)
|
||
if cv.const_kind == ast.CONST_INT and num_buf is not None:
|
||
viperlib.snprintf(num_buf, 32, " = %lld", cv.int_val)
|
||
pos = _PyiEmit(buf, buf_size, pos, num_buf)
|
||
elif cv.const_kind == ast.CONST_FLOAT:
|
||
# 浮点 CDefine(numpy 的 pi/e 等)必须输出值:读回端「vpi 中任一 CDefine 带值 → 不读源文件」的启发式会被同模块 int CDefine 挡住,无值的 pi 解析不到会退化成 @pi 全局指针导致 float<->ptr 报错;%.17g 保证 double 全精度往返(与读回端缓存格式一致)。
|
||
fbuf_c: bytes = mb.alloc(64)
|
||
if fbuf_c is not None:
|
||
viperlib.snprintf(fbuf_c, 64, " = %.17g", cv.float_val)
|
||
pos = _PyiEmit(buf, buf_size, pos, fbuf_c)
|
||
elif cv.const_kind == ast.CONST_BOOL:
|
||
if cv.int_val != 0:
|
||
pos = _PyiEmit(buf, buf_size, pos, " = True")
|
||
else:
|
||
pos = _PyiEmit(buf, buf_size, pos, " = False")
|
||
elif cv.const_kind == ast.CONST_STR:
|
||
# 字符串 CDefine(pyzlib.ZLIB_VERSION = "1.3.2" 等)必须输出值,让 stub 自包含(读回端按目标名判定会回退源文件)
|
||
sbuf_c: bytes = mb.alloc(string.strlen(cv.str_val) + 6)
|
||
if sbuf_c is not None:
|
||
viperlib.snprintf(sbuf_c, string.strlen(cv.str_val) + 6,
|
||
" = \"%s\"", cv.str_val)
|
||
pos = _PyiEmit(buf, buf_size, pos, sbuf_c)
|
||
elif cv.const_kind == ast.CONST_NONE:
|
||
pos = _PyiEmit(buf, buf_size, pos, " = None")
|
||
elif aa.value is not None and aa.value.kind() == ast.ASTKind.UnaryOp:
|
||
# 处理负值常量(如 INVALID_HANDLE_VALUE = -1)
|
||
# UnaryOp(USub, Constant(1)) → -1
|
||
uop_cv: ast.UnaryOp* = ast.UnaryOp*(aa.value)
|
||
num_buf_u: bytes = mb.alloc(32)
|
||
if uop_cv.op == ast.OpKind.USub and uop_cv.operand is not None \
|
||
and uop_cv.operand.kind() == ast.ASTKind.Constant:
|
||
uop_const: ast.Constant* = ast.Constant*(uop_cv.operand)
|
||
if uop_const.const_kind == ast.CONST_INT and num_buf_u is not None:
|
||
neg_val: int64 = -uop_const.int_val
|
||
viperlib.snprintf(num_buf_u, 32, " = %lld", neg_val)
|
||
pos = _PyiEmit(buf, buf_size, pos, num_buf_u)
|
||
elif aa.value is not None and aa.value.kind() == ast.ASTKind.Call:
|
||
# 处理类型构造函数常量(如 t.CUnsignedLong(-11))
|
||
# 提取第一个参数的整数值并输出
|
||
call_cv: ast.Call* = ast.Call*(aa.value)
|
||
if call_cv.args is not None:
|
||
call_args_cv: list[ast.AST*]* = call_cv.args
|
||
if len(call_args_cv) > 0:
|
||
first_arg: ast.AST* = call_args_cv.get(0)
|
||
if first_arg is not None:
|
||
arg_kind: int = first_arg.kind()
|
||
if arg_kind == ast.ASTKind.Constant:
|
||
ca_cv: ast.Constant* = ast.Constant*(first_arg)
|
||
num_buf_c: bytes = mb.alloc(32)
|
||
if ca_cv.const_kind == ast.CONST_INT and num_buf_c is not None:
|
||
viperlib.snprintf(num_buf_c, 32, " = %lld", ca_cv.int_val)
|
||
pos = _PyiEmit(buf, buf_size, pos, num_buf_c)
|
||
elif ca_cv.const_kind == ast.CONST_FLOAT:
|
||
# Call 包装的浮点常量(如 PI: t.CDefine = float(3.14159...)):
|
||
# stub 必须输出值,否则读回端 vpi 无值 → 退化 0.0。
|
||
# %.17g 保证 double 全精度往返(与上方 CONST_FLOAT 分支一致)。
|
||
fbuf_cc: bytes = mb.alloc(64)
|
||
if fbuf_cc is not None:
|
||
viperlib.snprintf(fbuf_cc, 64, " = %.17g", ca_cv.float_val)
|
||
pos = _PyiEmit(buf, buf_size, pos, fbuf_cc)
|
||
elif arg_kind == ast.ASTKind.UnaryOp:
|
||
uop_ca: ast.UnaryOp* = ast.UnaryOp*(first_arg)
|
||
num_buf_cu: bytes = mb.alloc(32)
|
||
if uop_ca.op == ast.OpKind.USub and uop_ca.operand is not None \
|
||
and uop_ca.operand.kind() == ast.ASTKind.Constant:
|
||
uoc: ast.Constant* = ast.Constant*(uop_ca.operand)
|
||
if uoc.const_kind == ast.CONST_INT and num_buf_cu is not None:
|
||
neg_c_val: int64 = -uoc.int_val
|
||
viperlib.snprintf(num_buf_cu, 32, " = %lld", neg_c_val)
|
||
pos = _PyiEmit(buf, buf_size, pos, num_buf_cu)
|
||
elif uoc.const_kind == ast.CONST_FLOAT:
|
||
# 负浮点 Call 包装(如 t.CDefine = float(-1.5)):
|
||
# 同 CONST_FLOAT,%.17g 全精度往返
|
||
neg_cf: double = -uoc.float_val
|
||
fbuf_cu: bytes = mb.alloc(64)
|
||
if fbuf_cu is not None:
|
||
viperlib.snprintf(fbuf_cu, 64, " = %.17g", neg_cf)
|
||
pos = _PyiEmit(buf, buf_size, pos, fbuf_cu)
|
||
elif arg_kind == ast.ASTKind.BinOp:
|
||
# Call 内部的 BinOp(如 t.CUnsignedLong(A | B))
|
||
# 递归计算 BinOp 值
|
||
binop_val_bo: int64 = _eval_binop_int(first_arg)
|
||
num_buf_bo: bytes = mb.alloc(32)
|
||
if (binop_val_bo != 0 or _eval_binop_valid(first_arg) != 0) \
|
||
and num_buf_bo is not None:
|
||
viperlib.snprintf(num_buf_bo, 32, " = %lld", binop_val_bo)
|
||
pos = _PyiEmit(buf, buf_size, pos, num_buf_bo)
|
||
elif aa.value is not None and aa.value.kind() == ast.ASTKind.BinOp:
|
||
# 处理 BinOp 常量(如 FOREGROUND_COMBO = FOREGROUND_RED | FOREGROUND_GREEN)
|
||
# 递归计算 BinOp 值并输出
|
||
binop_val_av: int64 = _eval_binop_int(aa.value)
|
||
if binop_val_av != 0 or _eval_binop_valid(aa.value) != 0:
|
||
num_buf_b: bytes = mb.alloc(32)
|
||
if num_buf_b is not None:
|
||
viperlib.snprintf(num_buf_b, 32, " = %lld", binop_val_av)
|
||
pos = _PyiEmit(buf, buf_size, pos, num_buf_b)
|
||
elif aa.value is not None and aa.value.kind() == ast.ASTKind.Name:
|
||
# 处理 Name 引用常量(如 ALIAS = OTHER_CONST)
|
||
# 输出引用的名字,让消费方在本地查找
|
||
name_val: ast.Name* = ast.Name*(aa.value)
|
||
if name_val.id is not None:
|
||
pos = _PyiEmit(buf, buf_size, pos, " = ")
|
||
pos = _PyiEmit(buf, buf_size, pos, name_val.id)
|
||
pos = _PyiEmit(buf, buf_size, pos, "\n")
|
||
|
||
# 全局赋值(无注解)— 从 Constant value 推断类型
|
||
elif k == ast.ASTKind.Assign:
|
||
asg: ast.Assign* = ast.Assign*(stmt)
|
||
if asg.targets is not None and asg.value is not None:
|
||
asg_targets: list[ast.AST*]* = asg.targets
|
||
atn: sizet = len(asg_targets)
|
||
if atn == 1:
|
||
atg: ast.AST* = asg_targets.get(0)
|
||
if atg is not None and atg.kind() == ast.ASTKind.Name:
|
||
agn: ast.Name* = ast.Name*(atg)
|
||
aval: ast.AST* = asg.value
|
||
avk: int = aval.kind()
|
||
inferred: int = 0
|
||
if avk == ast.ASTKind.Constant:
|
||
acv: ast.Constant* = ast.Constant*(aval)
|
||
if acv.const_kind == ast.CONST_INT:
|
||
inferred = 1
|
||
elif acv.const_kind == ast.CONST_FLOAT:
|
||
inferred = 2
|
||
elif acv.const_kind == ast.CONST_STR:
|
||
inferred = 3
|
||
elif acv.const_kind == ast.CONST_BOOL:
|
||
inferred = 4
|
||
elif acv.const_kind == ast.CONST_NONE:
|
||
inferred = 5
|
||
if inferred > 0 and agn.id is not None:
|
||
pos = _PyiEmit(buf, buf_size, pos, agn.id)
|
||
pos = _PyiEmit(buf, buf_size, pos, ": ")
|
||
if inferred == 1:
|
||
pos = _PyiEmit(buf, buf_size, pos, "int")
|
||
elif inferred == 2:
|
||
pos = _PyiEmit(buf, buf_size, pos, "t.CDouble")
|
||
elif inferred == 3:
|
||
pos = _PyiEmit(buf, buf_size, pos, "str")
|
||
elif inferred == 4:
|
||
pos = _PyiEmit(buf, buf_size, pos, "bool")
|
||
elif inferred == 5:
|
||
pos = _PyiEmit(buf, buf_size, pos, "None")
|
||
pos = _PyiEmit(buf, buf_size, pos, "\n")
|
||
|
||
# NUL 终止
|
||
if pos < buf_size:
|
||
buf[pos] = 0
|
||
else:
|
||
buf[buf_size - 1] = 0
|
||
return pos
|