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:
1 parent
d13b966604
commit
6350b81307
2 files changed
+186
-13
No files matched your search
+28
-11
@@ -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
@@ -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, "[")) {
|
||||
|
||||
Reference in new issue
Block a user