将 .py 和 .pyi 后缀名改为了 .vp 和 .vpi 后缀名

This commit is contained in:
2026-07-30 16:34:50 +08:00
parent 32af3f93fa
commit d227bee139
74 changed files with 42 additions and 25 deletions

View File

@@ -0,0 +1,746 @@
import t, c
from stdint import *
import ast
import string
import memhub
import viperlib
# ============================================================
# StubGen.Converter - pyi 存根文件生成器
#
# 从 AST 直接生成 .pyi 存根文件,不依赖 CPython 的 PythonToStubConverter。
# 遍历 Module 节点的 children提取函数签名、类定义、变量声明、
# import 语句,生成 Python 类型存根文件。
#
# 本文件使用 Viper 语法实现,可被 TPC 编译为原生码。
# ============================================================
# ============================================================
# _eval_binop_int / _eval_binop_valid - 递归计算 BinOp 常量值
#
# 用于 .pyi 存根文件生成时计算 BinOp 表达式(如 A | B, A + B的整数值。
# 支持 BitOr/BitAnd/Add/Sub 以及嵌套的 Name引用已注册的 CDefine 常量)。
# ============================================================
def _eval_binop_valid(node: ast.AST | t.CPtr) -> int:
"""检查 BinOp 节点是否可计算(所有叶子节点都是常量或已注册的 CDefine"""
if node is None:
return 0
k: int = node.kind()
if k == ast.ASTKind.Constant:
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
if cn.const_kind == ast.CONST_INT:
return 1
return 0
if k == ast.ASTKind.UnaryOp:
uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(node)
if uop.operand is not None:
return _eval_binop_valid(uop.operand)
return 0
if k == ast.ASTKind.BinOp:
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(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 | t.CPtr = (ast.Name | t.CPtr)(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 | t.CPtr) -> int:
"""递归计算 BinOp 节点的整数值"""
if node is None:
return 0
k: int = node.kind()
if k == ast.ASTKind.Constant:
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(node)
if cn.const_kind == ast.CONST_INT:
return cn.int_val
return 0
if k == ast.ASTKind.UnaryOp:
uop: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(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 | t.CPtr = (ast.BinOp | t.CPtr)(node)
if bop.left is None or bop.right is None:
return 0
lv: int = _eval_binop_int(bop.left)
rv: int = _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.Add:
return lv + rv
if bop.op == ast.OpKind.Sub:
return lv - rv
return 0
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(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
def _lookup_cdefine_for_pyi(name: str) -> int:
"""从本地 CDefine 表查找常量值(用于 .pyi 生成时的 BinOp 计算)"""
import lib.core.Handles.HandlesType as HandlesType
val: int = HandlesType.lookup_cdefine_constant(name)
if HandlesType.is_cdefine_found() != 0:
_g_pyi_cdefine_found = 1
return val
_g_pyi_cdefine_found = 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: t.CSizeT, pos: t.CSizeT,
text: str) -> t.CSizeT:
"""追加 text 到 buf 的 pos 位置,返回新的 pos"""
if buf is None or text is None or pos >= buf_size:
return pos
tlen: t.CSizeT = string.strlen(text)
if tlen == 0:
return pos
remain: t.CSizeT = 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: t.CSizeT, pos: t.CSizeT,
level: int) -> t.CSizeT:
"""追加 level*4 个空格到 buf返回新的 pos"""
i: int = 0
while i < level:
pos = _PyiEmit(buf, buf_size, pos, " ")
i += 1
return pos
# ============================================================
# _PyiTypeStr - 递归生成类型注解字符串
#
# 将 AST 类型注解节点转换为字符串表示,写入 buf 的 pos 位置。
# 支持: Name, Attribute, Subscript, BinOp(|), Constant(前向引用), Tuple
# ============================================================
def _PyiTypeStr(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
annot: ast.AST | t.CPtr) -> t.CSizeT:
"""递归生成类型注解字符串,返回新的 pos"""
if annot is None:
return _PyiEmit(buf, buf_size, pos, "t.CInt")
k: int = annot.kind()
# Name: 简单类型名 (如 int, str, MyClass)
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(annot)
if nm.id is not None:
return _PyiEmit(buf, buf_size, pos, nm.id)
return _PyiEmit(buf, buf_size, pos, "t.CInt")
# Attribute: 属性引用 (如 t.CInt, memhub.MemBuddy)
if k == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(annot)
pos = _PyiTypeStr(buf, buf_size, pos, at.value)
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 | t.CPtr = (ast.Subscript | t.CPtr)(annot)
pos = _PyiTypeStr(buf, buf_size, pos, sub.value)
pos = _PyiEmit(buf, buf_size, pos, "[")
pos = _PyiTypeStr(buf, buf_size, pos, sub.slice)
pos = _PyiEmit(buf, buf_size, pos, "]")
return pos
# BinOp: 联合类型 (如 int | str, File | t.CPtr)
if k == ast.ASTKind.BinOp:
bop: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(annot)
pos = _PyiTypeStr(buf, buf_size, pos, bop.left)
pos = _PyiEmit(buf, buf_size, pos, " | ")
pos = _PyiTypeStr(buf, buf_size, pos, bop.right)
return pos
# Constant: 字符串前向引用 (如 'MyClass') 或 None
if k == ast.ASTKind.Constant:
cn: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(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")
return _PyiEmit(buf, buf_size, pos, "t.CInt")
# Tuple: 多参数下标 (如 Dict[str, int])
if k == ast.ASTKind.Tuple:
tup: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(annot)
if tup.elts is not None:
tup_elts: list[ast.AST | t.CPtr] | t.CPtr = tup.elts
tn: t.CSizeT = tup_elts.__len__()
ti: t.CSizeT = 0
while ti < tn:
if ti > 0:
pos = _PyiEmit(buf, buf_size, pos, ", ")
el: ast.AST | t.CPtr = tup_elts.get(ti)
pos = _PyiTypeStr(buf, buf_size, pos, el)
ti += 1
return pos
# Call: 函数调用表达式 (用于装饰器如 @t.NoVTable())
if k == ast.ASTKind.Call:
cl: ast.Call | t.CPtr = (ast.Call | t.CPtr)(annot)
pos = _PyiTypeStr(buf, buf_size, pos, cl.func)
pos = _PyiEmit(buf, buf_size, pos, "(")
if cl.args is not None:
cl_args: list[ast.AST | t.CPtr] | t.CPtr = cl.args
can: t.CSizeT = cl_args.__len__()
cai: t.CSizeT = 0
while cai < can:
if cai > 0:
pos = _PyiEmit(buf, buf_size, pos, ", ")
ca: ast.AST | t.CPtr = cl_args.get(cai)
pos = _PyiTypeStr(buf, buf_size, pos, ca)
cai += 1
pos = _PyiEmit(buf, buf_size, pos, ")")
return pos
# 未知类型,回退到 t.CInt
return _PyiEmit(buf, buf_size, pos, "t.CInt")
# ============================================================
# _PyiFunction - 生成函数签名
#
# 格式: def name(param: Type, ...) -> ReturnType: pass
# ============================================================
def _PyiFunction(buf: bytes, buf_size: t.CSizeT, pos: t.CSizeT,
fn: ast.FunctionDef | t.CPtr,
indent_level: int, class_name: str) -> t.CSizeT:
"""生成函数签名到 buf返回新的 pos"""
# 装饰器
if fn.decorator_list is not None:
fn_decorator_list: list[ast.AST | t.CPtr] | t.CPtr = fn.decorator_list
dn: t.CSizeT = fn_decorator_list.__len__()
di: t.CSizeT = 0
while di < dn:
dec: ast.AST | t.CPtr = 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 | t.CPtr = fn.args
if args_node is not None:
args: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(args_node)
first: int = 1
# 位置参数
if args.args is not None:
args_args: list[ast.AST | t.CPtr] | t.CPtr = args.args
an: t.CSizeT = args_args.__len__()
ai: t.CSizeT = 0
while ai < an:
if first == 0:
pos = _PyiEmit(buf, buf_size, pos, ", ")
first = 0
ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(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)
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 | t.CPtr = (ast.Arg | t.CPtr)(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 | t.CPtr = (ast.Arg | t.CPtr)(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)
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: t.CSizeT, pos: t.CSizeT,
cls: ast.ClassDef | t.CPtr, indent_level: int) -> t.CSizeT:
"""生成类定义到 buf返回新的 pos"""
# 装饰器
if cls.decorator_list is not None:
cls_decorator_list: list[ast.AST | t.CPtr] | t.CPtr = cls.decorator_list
dcn: t.CSizeT = cls_decorator_list.__len__()
dci: t.CSizeT = 0
while dci < dcn:
ddec: ast.AST | t.CPtr = 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:
cls_type_params: list[ast.AST | t.CPtr] | t.CPtr = cls.type_params
tpn: t.CSizeT = cls_type_params.__len__()
if tpn > 0:
pos = _PyiEmit(buf, buf_size, pos, "[")
tpi: t.CSizeT = 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 | t.CPtr] | t.CPtr = cls.bases
bn: t.CSizeT = cls_bases.__len__()
if bn > 0:
pos = _PyiEmit(buf, buf_size, pos, "(")
bi: t.CSizeT = 0
while bi < bn:
if bi > 0:
pos = _PyiEmit(buf, buf_size, pos, ", ")
base: ast.AST | t.CPtr = 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 | t.CPtr] | t.CPtr = cls.children
cn: t.CSizeT = cls_children.__len__()
ci: t.CSizeT = 0
while ci < cn:
stmt: ast.AST | t.CPtr = cls_children.get(ci)
if stmt is not None:
sk: int = stmt.kind()
# 方法
if sk == ast.ASTKind.FunctionDef:
mfn: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(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 | t.CPtr] | t.CPtr = mfn.children
icn: t.CSizeT = mfn_children.__len__()
ici: t.CSizeT = 0
while ici < icn:
ibody: ast.AST | t.CPtr = mfn_children.get(ici)
if ibody is not None and ibody.kind() == ast.ASTKind.AnnAssign:
iaa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(ibody)
if iaa.target is not None and iaa.target.kind() == ast.ASTKind.Attribute:
iat: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(iaa.target)
# 检查 target.value 是否为 Name("self")
if iat.value is not None and iat.value.kind() == ast.ASTKind.Name:
iavn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(iat.value)
if iavn.id is not None and string.strcmp(iavn.id, "self") == 0:
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 | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt)
if aa.target is not None and aa.target.kind() == ast.ASTKind.Name:
tn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(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 | t.CPtr = (ast.ClassDef | t.CPtr)(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")
pos = _PyiEmit(buf, buf_size, pos, "\n")
return pos
# ============================================================
# _GeneratePyiFromAst - 从 AST 生成 .pyi 存根文件
#
# 遍历 AST Module 节点提取函数签名、类定义、变量声明、import 语句,
# 生成 Python 类型存根文件内容到 buf。
#
# Args:
# mb: 内存池(保留以符合调用约定,实际未使用)
# tree: AST Module 根节点
# rel_path: 相对路径(用于模块名,当前未使用)
# buf: 输出缓冲区
# buf_size: 缓冲区大小
#
# Returns:
# 写入的字节数0 表示失败)
# ============================================================
def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
rel_path: str, buf: bytes,
buf_size: t.CSizeT) -> t.CSizeT:
"""从 AST 生成 .pyi 存根文件内容到 buf"""
if tree is None or buf is None or buf_size == 0:
return 0
pos: t.CSizeT = 0
# 文件头
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 | t.CPtr] | t.CPtr = tree.children
n: t.CSizeT = tree_children.__len__()
# 第一遍扫描:检测 import t/c
has_import_t: int = 0
has_import_c: int = 0
i: t.CSizeT = 0
while i < n:
stmt: ast.AST | t.CPtr = tree_children.get(i)
if stmt is not None and stmt.kind() == ast.ASTKind.Import:
imp: ast.Import | t.CPtr = (ast.Import | t.CPtr)(stmt)
if imp.names is not None:
imp_names: list[ast.AST | t.CPtr] | t.CPtr = imp.names
an: t.CSizeT = imp_names.__len__()
ai: t.CSizeT = 0
while ai < an:
al: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(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
ai += 1
i += 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")
# 第二遍扫描:生成声明
i = 0
while i < n:
stmt = tree_children.get(i)
if stmt is not None:
k: int = stmt.kind()
# Import 语句
if k == ast.ASTKind.Import:
imp2: ast.Import | t.CPtr = (ast.Import | t.CPtr)(stmt)
pos = _PyiEmit(buf, buf_size, pos, "import ")
if imp2.names is not None:
imp2_names: list[ast.AST | t.CPtr] | t.CPtr = imp2.names
an2: t.CSizeT = imp2_names.__len__()
ai2: t.CSizeT = 0
while ai2 < an2:
if ai2 > 0:
pos = _PyiEmit(buf, buf_size, pos, ", ")
al2: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(imp2_names.get(ai2))
if al2 is not None and al2.name is not None:
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 | t.CPtr = (ast.ImportFrom | t.CPtr)(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 ")
if ifr.names is not None:
ifr_names: list[ast.AST | t.CPtr] | t.CPtr = ifr.names
an3: t.CSizeT = ifr_names.__len__()
ai3: t.CSizeT = 0
while ai3 < an3:
if ai3 > 0:
pos = _PyiEmit(buf, buf_size, pos, ", ")
al3: ast.Alias | t.CPtr = (ast.Alias | t.CPtr)(ifr_names.get(ai3))
if al3 is not None and al3.name is not None:
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")
# 函数定义
elif k == ast.ASTKind.FunctionDef:
fn: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(stmt)
pos = _PyiFunction(buf, buf_size, pos, fn, 0, "")
pos = _PyiEmit(buf, buf_size, pos, "\n")
# 类定义
elif k == ast.ASTKind.ClassDef:
cls: ast.ClassDef | t.CPtr = (ast.ClassDef | t.CPtr)(stmt)
pos = _PyiClass(buf, buf_size, pos, cls, 0)
# 带注解的变量声明
elif k == ast.ASTKind.AnnAssign:
aa: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(stmt)
if aa.target is not None and aa.target.kind() == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(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
if aa.value is not None and aa.value.kind() == ast.ASTKind.Constant:
cv: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(aa.value)
if cv.const_kind == ast.CONST_INT:
num_buf: bytes = mb.alloc(32)
if num_buf is not None:
viperlib.snprintf(num_buf, 32, " = %d", cv.int_val)
pos = _PyiEmit(buf, buf_size, pos, num_buf)
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_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 | t.CPtr = (ast.UnaryOp | t.CPtr)(aa.value)
if uop_cv.op == ast.OpKind.USub and uop_cv.operand is not None:
if uop_cv.operand.kind() == ast.ASTKind.Constant:
uop_const: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(uop_cv.operand)
if uop_const.const_kind == ast.CONST_INT:
neg_val: int = -uop_const.int_val
num_buf_u: bytes = mb.alloc(32)
if num_buf_u is not None:
viperlib.snprintf(num_buf_u, 32, " = %d", 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 | t.CPtr = (ast.Call | t.CPtr)(aa.value)
if call_cv.args is not None:
call_args_cv: list[ast.AST | t.CPtr] | t.CPtr = call_cv.args
if call_args_cv.__len__() > 0:
first_arg: ast.AST | t.CPtr = 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 | t.CPtr = (ast.Constant | t.CPtr)(first_arg)
if ca_cv.const_kind == ast.CONST_INT:
num_buf_c: bytes = mb.alloc(32)
if num_buf_c is not None:
viperlib.snprintf(num_buf_c, 32, " = %d", ca_cv.int_val)
pos = _PyiEmit(buf, buf_size, pos, num_buf_c)
elif arg_kind == ast.ASTKind.UnaryOp:
uop_ca: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(first_arg)
if uop_ca.op == ast.OpKind.USub and uop_ca.operand is not None:
if uop_ca.operand.kind() == ast.ASTKind.Constant:
uoc: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(uop_ca.operand)
if uoc.const_kind == ast.CONST_INT:
neg_c_val: int = -uoc.int_val
num_buf_cu: bytes = mb.alloc(32)
if num_buf_cu is not None:
viperlib.snprintf(num_buf_cu, 32, " = %d", neg_c_val)
pos = _PyiEmit(buf, buf_size, pos, num_buf_cu)
elif arg_kind == ast.ASTKind.BinOp:
# Call 内部的 BinOp如 t.CUnsignedLong(A | B)
# 递归计算 BinOp 值
binop_val_bo: int = _eval_binop_int(first_arg)
if binop_val_bo != 0 or _eval_binop_valid(first_arg) != 0:
num_buf_bo: bytes = mb.alloc(32)
if num_buf_bo is not None:
viperlib.snprintf(num_buf_bo, 32, " = %d", 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: int = _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, " = %d", 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 | t.CPtr = (ast.Name | t.CPtr)(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 | t.CPtr = (ast.Assign | t.CPtr)(stmt)
if asg.targets is not None and asg.value is not None:
asg_targets: list[ast.AST | t.CPtr] | t.CPtr = asg.targets
atn: t.CSizeT = asg_targets.__len__()
if atn == 1:
atg: ast.AST | t.CPtr = asg_targets.get(0)
if atg is not None and atg.kind() == ast.ASTKind.Name:
agn: ast.Name | t.CPtr = (ast.Name | t.CPtr)(atg)
aval: ast.AST | t.CPtr = asg.value
avk: int = aval.kind()
inferred: int = 0
if avk == ast.ASTKind.Constant:
acv: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(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, "t.CInt")
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")
i += 1
# NUL 终止
if pos < buf_size:
buf[pos] = 0
else:
buf[buf_size - 1] = 0
return pos