From 6350b81307f7d514f13f8b403a5b46aae9c561cb Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Tue, 18 Aug 2026 06:59:10 +0800 Subject: [PATCH] =?UTF-8?q?feat(vast=5Fc):=20extern/export=20=E5=AE=8C?= =?UTF-8?q?=E6=95=B4=E8=AF=AD=E4=B9=89=EF=BC=88=E6=B3=A8=E8=A7=A3=E6=94=B9?= =?UTF-8?q?=E5=86=99+=E6=A0=87=E8=AE=B0=EF=BC=89=E5=B9=B6=E6=8E=A5?= =?UTF-8?q?=E5=85=A5=20vast.parse?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 输出一致 --- lib/vast/__init__.py | 39 ++++++++--- lib/vast_c/vast_c.c | 160 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 186 insertions(+), 13 deletions(-) diff --git a/lib/vast/__init__.py b/lib/vast/__init__.py index 6a32436..95583a3 100644 --- a/lib/vast/__init__.py +++ b/lib/vast/__init__.py @@ -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 = '', 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 = '', 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 = '', 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', diff --git a/lib/vast_c/vast_c.c b/lib/vast_c/vast_c.c index ae04fd4..cb24e05 100644 --- a/lib/vast_c/vast_c.c +++ b/lib/vast_c/vast_c.c @@ -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, "[")) {