feat(vast_c): extern/export 完整语义(注解改写+标记)并接入 vast.parse

- ParseExternDef:支持 4 种语法(extern/export [def] A(...) -> T [': pass']),返回注解改写为 <原类型> | t.State(extern)/ <原类型> | t.CExport(export),节点设 Extern=True/Export=True(对齐 vast Parser._ParseExternDef/_ParseExportDef)
- MakeTAttrNode:构造 t.Attr 注解节点(Attribute(Name('t'), attr))
- vast.parse 接入:默认走 vast_c C 加速路径(VAST_USE_C=0 禁用,=strict fail-fast 直接抛),异常回退纯 Python vast
- 差分测试 83/83 全绿(新增 7 个 extern/export 用例);includes/ 与 TransPyV/App 4 个真实 .vp 文件 C 路径与纯 Python 输出一致
This commit is contained in:
TermiNexus committed 2026-08-18 06:59:10 +08:00
1 parent d13b966604
commit 6350b81307
2 files changed
+186 -13

No files matched your search

+28 -11
View File
@@ -18,6 +18,7 @@ ExpandSoftKeywords 预处理。
"""
from __future__ import annotations
import os as _os
import sys as _sys
from lib.vast.Nodes import AST
@@ -36,17 +37,8 @@ from lib.vast.Unparser import Unparse as unparse # noqa: E402
from lib.vast.Tokenizer import SOFT_KEYWORDS # noqa: E402
def parse(source: str, filename: str = '<unknown>', mode: str = 'exec', *,
type_comments: bool = False, feature_version: tuple[int, int] | int | None = None) -> AST:
"""解析源码字符串为 AST(与 ast.parse 同签名、同结构)。
Args:
source: 源码文本
filename: 文件名(仅用于错误报告,vast 保留)
mode: 'exec'(模块)/ 'eval'(单表达式)/ 'single'(交互式)
type_comments: 是否解析 # type: 注释(vast 暂返回 None 字段)
feature_version: 目标 Python 版本(vast 忽略,保持兼容)
"""
def _ParsePure(source: str, mode: str) -> AST:
"""纯 Python vast 解析(vast_c 不可用或回退时使用)。"""
tree: AST = Parse(source)
if mode == 'exec':
return tree
@@ -62,6 +54,31 @@ def parse(source: str, filename: str = '<unknown>', mode: str = 'exec', *,
raise ValueError(f"invalid mode {mode!r}")
# C 加速解析器(vast_c 扩展):可用则优先,输出与 vast.parse 结构完全一致。
# VAST_USE_C=0 禁用 C 路径;=strict 时 C 路径异常直接抛出(fail-fast)。
_VAST_C_PARSE = None
try:
from lib.vast_c import parse as _VAST_C_PARSE
except Exception:
_VAST_C_PARSE = None
def parse(source: str, filename: str = '<unknown>', mode: str = 'exec', *,
type_comments: bool = False, feature_version: tuple[int, int] | int | None = None) -> AST:
"""解析源码字符串为 AST(与 ast.parse 同签名、同结构)。
优先使用 C 加速解析器 vast_c(输出结构完全一致),异常时回退纯 Python vast;
环境变量 VAST_USE_C:'0' 禁用 C 路径,'strict' 时 C 路径异常直接抛出。
"""
if _VAST_C_PARSE is not None and _os.environ.get('VAST_USE_C', '1') != '0':
try:
return _VAST_C_PARSE(source, mode)
except Exception:
if _os.environ.get('VAST_USE_C') == 'strict':
raise
return _ParsePure(source, mode)
__all__: list[str] = [
'AST', 'parse', 'dump', 'walk', 'iter_fields', 'iter_child_nodes',
'unparse', 'copy_location', 'fix_missing_locations',
+158 -2
View File
@@ -3930,6 +3930,7 @@ static PyObject *ParseMatch(Parser *P);
static PyObject *ParseFunctionDef(Parser *P, int IsAsync, PyObject *Decorators);
static PyObject *ParseClassDef(Parser *P, PyObject *Decorators);
static PyObject *ParseExprList(Parser *P);
static PyObject *ParseExternDef(Parser *P, int IsExport, PyObject *Decorators);
static PyObject *TryParseAnnAssign(Parser *P);
static PyObject *ParseExprStmt(Parser *P);
static PyObject *ParseImport(Parser *P);
@@ -3990,10 +3991,10 @@ static PyObject *ParseStatement(Parser *P) {
Token *T = PeekTok(P, 0);
if (T->Kind == TK_NAME) {
if (TokIsName(T, "extern")) {
return ParseFunctionDef(P, 0, NULL); /* extern 简化为普通 def(测试未覆盖,宽松) */
return ParseExternDef(P, 0, NULL);
}
if (TokIsName(T, "export")) {
return ParseFunctionDef(P, 0, NULL);
return ParseExternDef(P, 1, NULL);
}
if ((TokIsName(T, "fn") || TokIsName(T, "fun") || TokIsName(T, "func")
|| TokIsName(T, "function"))
@@ -4834,6 +4835,161 @@ static PyObject *ParseFunctionDef(Parser *P, int IsAsync, PyObject *Decorators)
return Node;
}
/* 构造 t.Attr 注解节点:Attribute(value=Name('t', Load), attr=AttrName, ctx=Load) */
static PyObject *MakeTAttrNode(Parser *P, const char *AttrName) {
PyObject *Load = MakeCtx(P, "Load");
PyObject *TName = PyUnicode_FromString("t");
if (Load == NULL || TName == NULL) {
Py_XDECREF(Load);
Py_XDECREF(TName);
return NULL;
}
PyObject *ArgvN[2] = { TName, Load };
PyObject *TNode = NewNode(P, "Name", ArgvN, 2);
Py_DECREF(TName);
Py_DECREF(Load);
if (TNode == NULL) {
return NULL;
}
PyObject *Load2 = MakeCtx(P, "Load");
PyObject *AttrStr = PyUnicode_FromString(AttrName);
if (Load2 == NULL || AttrStr == NULL) {
Py_XDECREF(TNode);
Py_XDECREF(Load2);
Py_XDECREF(AttrStr);
return NULL;
}
PyObject *ArgvA[3] = { TNode, AttrStr, Load2 };
PyObject *AttrNode = NewNode(P, "Attribute", ArgvA, 3);
Py_DECREF(TNode);
Py_DECREF(AttrStr);
Py_DECREF(Load2);
return AttrNode;
}
/* extern/export 函数声明(FFI/裸名导出,对齐 vast Parser._ParseExternDef/_ParseExportDef)。
* 允许语法(4 种,配不配 def 都一样,无 `:` 时 body 为空):
* extern [def] A(x: int) -> int [': pass']
* 产出标准 FunctionDef:返回注解改写为 <原类型> | t.State(extern)/ <原类型> | t.CExport(export),
* 并设 Extern=True / Export=True 供 Unparser 还原。 */
static PyObject *ParseExternDef(Parser *P, int IsExport, PyObject *Decorators) {
Token *Start = NextTok(P); /* 'extern' / 'export' */
if (AtName(P, "def")) {
NextTok(P);
}
Token *NameTok = ExpectName(P, NULL);
if (NameTok == NULL) {
return NULL;
}
PyObject *TypeParams = NewList();
if (TypeParams == NULL) {
return NULL;
}
if (AtOp(P, "[")) {
Py_DECREF(TypeParams);
TypeParams = ParseTypeParams(P);
if (TypeParams == NULL) {
return NULL;
}
}
PyObject *Args = ParseArguments(P, 0, 0);
if (Args == NULL) {
Py_DECREF(TypeParams);
return NULL;
}
PyObject *Returns = NULL;
if (AtOp(P, "->")) {
NextTok(P);
Returns = ParseExpr(P);
if (Returns == NULL) {
Py_DECREF(Args);
Py_DECREF(TypeParams);
return NULL;
}
}
PyObject *Body = NewList();
if (Body == NULL) {
Py_DECREF(Args);
Py_XDECREF(Returns);
Py_DECREF(TypeParams);
return NULL;
}
if (AtOp(P, ":")) {
NextTok(P);
Py_DECREF(Body);
Body = ParseSuite(P);
if (Body == NULL) {
Py_DECREF(Args);
Py_XDECREF(Returns);
Py_DECREF(TypeParams);
return NULL;
}
}
PyObject *Name = PyUnicode_FromStringAndSize(NameTok->Start, NameTok->End - NameTok->Start);
if (Name == NULL) {
Py_DECREF(Args);
Py_XDECREF(Returns);
Py_DECREF(TypeParams);
Py_DECREF(Body);
return NULL;
}
PyObject *Argv[7];
Argv[0] = Name;
Argv[1] = Args;
Argv[2] = Body;
Argv[3] = Decorators ? Decorators : NewList();
Argv[4] = Returns ? Returns : Py_None;
Argv[5] = Py_None; /* type_comment */
Argv[6] = TypeParams;
if (Argv[3] == NULL) {
Py_DECREF(Name);
Py_DECREF(Args);
Py_DECREF(Body);
Py_XDECREF(Returns);
Py_DECREF(TypeParams);
return NULL;
}
PyObject *Node = NewNode(P, "FunctionDef", Argv, 7);
Py_DECREF(Name);
Py_DECREF(Args);
Py_DECREF(Body);
if (Argv[3] != Decorators) {
Py_DECREF(Argv[3]);
}
Py_DECREF(TypeParams);
if (Node == NULL) {
Py_XDECREF(Returns);
return NULL;
}
/* 标记 extern/export(Unparser 据此还原语法) */
PyObject_SetAttrString(Node, IsExport ? "Export" : "Extern", Py_True);
/* 返回注解改写:<原类型> | t.State / <原类型> | t.CExport(NewNode 后 Returns 引用仍有效) */
PyObject *TAttr = MakeTAttrNode(P, IsExport ? "CExport" : "State");
if (TAttr != NULL) {
if (Returns != NULL) {
PyObject *Op = MakeSingleton(P, "BitOr");
if (Op != NULL) {
PyObject *ArgvB[3];
ArgvB[0] = Returns;
ArgvB[1] = Op;
ArgvB[2] = TAttr;
PyObject *Bin = NewNode(P, "BinOp", ArgvB, 3);
if (Bin != NULL) {
PyObject_SetAttrString(Node, "returns", Bin);
Py_DECREF(Bin);
}
Py_DECREF(Op);
}
} else {
PyObject_SetAttrString(Node, "returns", TAttr);
}
Py_DECREF(TAttr);
}
Py_XDECREF(Returns);
FixLoc(P, Node, Start);
return Node;
}
/* PEP 695 类型参数:[T, *Ts, **P, U: Bound] */
static PyObject *ParseTypeParams(Parser *P) {
if (!ExpectOp(P, "[")) {