feat(vast/ast): 新增 export 软关键字声明 CExport 函数(等价 t.CExport)
允许 4 种语法(配不配 def 都一样):export def A(...) / export A(...), 与 extern 对称。返回注解改写为 <原类型> | t.CExport,复用既有 CExport 路径(符号名裸名、不加模块 SHA1 头);无 body 形式消费本行 NewLine。 TPC 侧 vast:_ParseExportDef + Unparser 还原(Export=True); TPV 侧 includes/ast:Keyword.Export + FLAG_IS_EXPORT=16(追加末尾)+ _is_funcdef_kw/_parse_funcdef 支持。
This commit is contained in:
1 parent
451e7a0391
commit
5d93692baa
5 files changed
+99
-10
No files matched your search
@@ -155,6 +155,7 @@ FLAG_IS_ASYNC: t.CDefine = 1
|
||||
FLAG_SIMPLE: t.CDefine = 2
|
||||
FLAG_HAS_STAR: t.CDefine = 4
|
||||
FLAG_IS_EXTERN: t.CDefine = 8
|
||||
FLAG_IS_EXPORT: t.CDefine = 16
|
||||
|
||||
|
||||
# ============================================================
|
||||
|
||||
+29
-8
@@ -10,7 +10,7 @@ from .base import (
|
||||
_set_pos, _binop_from_op, _augop_from_op, _cmpop_from_op, _copy_str, _inherit_pos,
|
||||
_init_ast,
|
||||
CONST_INT, CONST_FLOAT, CONST_STR, CONST_BOOL, CONST_NONE, CONST_CHAR,
|
||||
FLAG_IS_ASYNC, FLAG_IS_EXTERN,
|
||||
FLAG_IS_ASYNC, FLAG_IS_EXTERN, FLAG_IS_EXPORT,
|
||||
)
|
||||
from .exprs import (
|
||||
BoolOp, BinOp, UnaryOp, Lambda, IfExp, Dict, Set,
|
||||
@@ -95,18 +95,20 @@ def _cur_kw(ps: Parser | t.CPtr) -> t.CInt:
|
||||
|
||||
def _is_funcdef_kw(ps: Parser | t.CPtr, kw: t.CInt) -> int:
|
||||
"""判断当前 token 是否为函数定义关键字(def 及其别名 fn/fun/func/function,
|
||||
以及 extern 声明关键字)
|
||||
以及 extern/export 声明关键字)
|
||||
|
||||
def 是硬关键字直接判定;fn/fun/func/function/extern 是软关键字,
|
||||
def 是硬关键字直接判定;fn/fun/func/function/extern/export 是软关键字,
|
||||
仅当下一个 token 是 Name 且再下一个是 '('(或泛型 '[T]' 前的 '[')时
|
||||
判定为函数定义。extern 还允许 'extern def A(...)' 形式(下一个是 def)。
|
||||
判定为函数定义。extern 还允许 'extern def A(...)' 形式(下一个是 def),
|
||||
export 同样允许 'export def A(...)' 形式。
|
||||
否则按普通标识符处理,兼容既有代码把 func 用作
|
||||
字段/参数名(如 AST 节点 func 字段、Call.func 注解 `func: AST | t.CPtr`)。
|
||||
"""
|
||||
if kw == Keyword.Def:
|
||||
return 1
|
||||
if kw == Keyword.Extern:
|
||||
# extern def A(...) 或 extern A(...)(extern 后是 def 或 Name+'(/'[')
|
||||
if kw == Keyword.Extern or kw == Keyword.Export:
|
||||
# extern/export def A(...) 或 extern/export A(...)
|
||||
# (extern/export 后是 def 或 Name+'(/'[')
|
||||
nxt: Token | t.CPtr = ps.cur.next
|
||||
if nxt is None:
|
||||
return 0
|
||||
@@ -2229,12 +2231,19 @@ def _parse_funcdef(ps: Parser | t.CPtr, is_async: t.CInt) -> AST | t.CPtr:
|
||||
lineno: t.CInt = _cur_lineno(ps)
|
||||
col: t.CInt = _cur_col(ps)
|
||||
is_extern_fd: t.CInt = 0
|
||||
is_export_fd: t.CInt = 0
|
||||
if _cur_kw(ps) == Keyword.Extern:
|
||||
# extern 声明:extern [def] A(...) [-> T] [": pass" 可选]
|
||||
is_extern_fd = 1
|
||||
_advance(ps) # extern
|
||||
if _cur_kw(ps) == Keyword.Def:
|
||||
_advance(ps)
|
||||
elif _cur_kw(ps) == Keyword.Export:
|
||||
# export 声明:export [def] A(...) [-> T] [": pass" 可选]
|
||||
is_export_fd = 1
|
||||
_advance(ps) # export
|
||||
if _cur_kw(ps) == Keyword.Def:
|
||||
_advance(ps)
|
||||
else:
|
||||
_advance(ps) # def / fn / ...
|
||||
if _cur_type(ps) != TokenType.Name:
|
||||
@@ -2280,16 +2289,28 @@ def _parse_funcdef(ps: Parser | t.CPtr, is_async: t.CInt) -> AST | t.CPtr:
|
||||
returns = BinOp(ps.pool, returns, OpKind.BitOr, state_attr_fd)
|
||||
else:
|
||||
returns = state_attr_fd
|
||||
elif is_export_fd:
|
||||
# export 声明:返回注解改写为 <原类型> | t.CExport,复用既有
|
||||
# CExport 识别路径(vpi 注解含 "CExport" → 定义端裸名 + 不加模块 SHA1 头)
|
||||
export_attr_fd: AST | t.CPtr = Attribute(ps.pool,
|
||||
Name(ps.pool, "t", ASTCtx.Load),
|
||||
"CExport", ASTCtx.Load)
|
||||
if returns != None:
|
||||
returns = BinOp(ps.pool, returns, OpKind.BitOr, export_attr_fd)
|
||||
else:
|
||||
returns = export_attr_fd
|
||||
dec_list: list[AST | t.CPtr] | t.CPtr = ps.pending_decorators
|
||||
ps.pending_decorators = None
|
||||
node: FunctionDef | t.CPtr = FunctionDef(ps.pool, name, args, dec_list, returns, is_async, type_params_fd)
|
||||
if is_extern_fd:
|
||||
node.flags = node.flags | FLAG_IS_EXTERN
|
||||
if is_extern_fd == 0 or _match_op(ps, TokOp.Colon):
|
||||
if is_export_fd:
|
||||
node.flags = node.flags | FLAG_IS_EXPORT
|
||||
if (is_extern_fd == 0 and is_export_fd == 0) or _match_op(ps, TokOp.Colon):
|
||||
_expect_op(ps, TokOp.Colon)
|
||||
_parse_suite_into_children(ps, node)
|
||||
else:
|
||||
# extern 无 ': pass' 形式(extern A(...) -> int):body 为空,仅声明。
|
||||
# extern/export 无 ': pass' 形式(extern A(...) -> int):body 为空,仅声明。
|
||||
# 必须消费本行 NewLine:模块级/类体语句循环只 _skip_nl(Nl),
|
||||
# 残留 NewLine 会被下一轮当表达式解析(_parse_atom → error_count++)
|
||||
# → parse_tokens 返回 None(TPV 编译 extern 文件报 7 个扫描失败的根因)
|
||||
|
||||
@@ -79,6 +79,8 @@ class Keyword(t.CEnum):
|
||||
Function: t.State
|
||||
# extern 函数声明关键字(FFI,等价 t.State 标记;软判定见 _is_funcdef_kw)
|
||||
Extern: t.State
|
||||
# export 函数声明关键字(等价 t.CExport,裸名导出不加 SHA1 头;软判定见 _is_funcdef_kw)
|
||||
Export: t.State
|
||||
|
||||
|
||||
# ============================================================
|
||||
@@ -258,7 +260,8 @@ def _init_keywords(pool: memhub.MemManager | t.CPtr):
|
||||
_kw_intern(pool, "fun", Keyword.Fun)
|
||||
_kw_intern(pool, "func", Keyword.Func)
|
||||
_kw_intern(pool, "function", Keyword.Function)
|
||||
_kw_intern(pool, "extern", Keyword.Extern)
|
||||
_kw_intern(pool, "extern", Keyword.Extern)
|
||||
_kw_intern(pool, "export", Keyword.Export)
|
||||
|
||||
|
||||
# ============================================================
|
||||
|
||||
@@ -57,6 +57,10 @@ class Parser(ExprParserMixin):
|
||||
# extern 函数声明(FFI,等价 t.State)——必须在软关键字 def 分派之前
|
||||
if v == 'extern':
|
||||
return self._ParseExternDef()
|
||||
# export 函数声明(等价 t.CExport,裸名导出不增加 SHA1 头)——
|
||||
# 必须在软关键字 def 分派之前
|
||||
if v == 'export':
|
||||
return self._ParseExportDef()
|
||||
# 软关键字函数定义:fn/fun/func/function + 标识符
|
||||
if v in SOFT_KEYWORDS and self._Peek(1).Type == NAME:
|
||||
return self._ParseFunctionDef()
|
||||
@@ -498,6 +502,8 @@ class Parser(ExprParserMixin):
|
||||
tok: Token = self._Peek()
|
||||
if tok.Type == NAME and tok.Value == 'extern':
|
||||
return self._ParseExternDef(decorators=decorator_list)
|
||||
if tok.Type == NAME and tok.Value == 'export':
|
||||
return self._ParseExportDef(decorators=decorator_list)
|
||||
if tok.Type == NAME and tok.Value == 'def':
|
||||
return self._ParseFunctionDef(decorators=decorator_list)
|
||||
if tok.Type == NAME and tok.Value == 'async':
|
||||
@@ -582,6 +588,52 @@ class Parser(ExprParserMixin):
|
||||
self._FixLoc(node, start)
|
||||
return node
|
||||
|
||||
def _ParseExportDef(self, decorators: list[N.expr] | None = None) -> N.FunctionDef:
|
||||
"""解析 export 函数声明(等价 t.CExport,导出裸名、不加模块 SHA1 头)。
|
||||
|
||||
允许语法(与 extern 对称,配不配 def 都一样):
|
||||
export def A(x: int) -> int: pass
|
||||
export A(x: int) -> int: pass
|
||||
export def A(x: int) -> int
|
||||
export A(x: int) -> int
|
||||
|
||||
产出标准 FunctionDef 节点,返回注解改写为 ``<原类型> | t.CExport``
|
||||
以复用 TPC 的 CExport 路径(符号名不增加 SHA1 前缀);并设自定义
|
||||
属性 ``Export = True`` 供 Unparser 还原 export 语法。
|
||||
"""
|
||||
start: Token = self._Next() # 'export'
|
||||
if self._AtName('def'):
|
||||
self._Next()
|
||||
name_tok: Token = self._ExpectName()
|
||||
type_params: list[N.AST] = []
|
||||
if self._AtOp('['):
|
||||
type_params = self._ParseTypeParams()
|
||||
args: N.arguments = self._ParseArguments()
|
||||
returns: N.expr | None = None
|
||||
if self._AtOp('->'):
|
||||
self._Next()
|
||||
returns = self.ParseExpr()
|
||||
body: list[N.stmt] = []
|
||||
if self._AtOp(':'):
|
||||
self._Next()
|
||||
body = self._ParseSuite()
|
||||
node: N.FunctionDef = N.FunctionDef(
|
||||
name=name_tok.Value, args=args, body=body,
|
||||
decorator_list=decorators or [], returns=returns,
|
||||
type_comment=None, type_params=type_params,
|
||||
)
|
||||
node.Export = True
|
||||
# 返回注解改写为 <原类型> | t.CExport,使 TPC 识别为 CExport 函数
|
||||
# (导出裸名,不增加模块 SHA1 头;有条件情况下导出)
|
||||
export_attr: N.expr = N.Attribute(value=N.Name(id='t', ctx=N.Load()),
|
||||
attr='CExport', ctx=N.Load())
|
||||
if returns is not None:
|
||||
node.returns = N.BinOp(left=returns, op=N.BitOr(), right=export_attr)
|
||||
else:
|
||||
node.returns = export_attr
|
||||
self._FixLoc(node, start)
|
||||
return node
|
||||
|
||||
def _ParseTypeParams(self) -> list[N.AST]:
|
||||
"""解析 PEP 695 类型参数:[T, *Ts, **P, U: Bound]"""
|
||||
self._ExpectOp('[')
|
||||
|
||||
+13
-1
@@ -73,7 +73,13 @@ class Unparser:
|
||||
|
||||
def _FunctionDef(self, node: N.FunctionDef) -> str:
|
||||
is_extern: bool = bool(getattr(node, 'Extern', False))
|
||||
kw: str = 'async def' if isinstance(node, N.AsyncFunctionDef) else ('extern def' if is_extern else 'def')
|
||||
is_export: bool = bool(getattr(node, 'Export', False))
|
||||
if is_extern:
|
||||
kw: str = 'extern def'
|
||||
elif is_export:
|
||||
kw = 'export def'
|
||||
else:
|
||||
kw = 'async def' if isinstance(node, N.AsyncFunctionDef) else 'def'
|
||||
decos: str = ''.join(f'@{self._expr(d)}\n' for d in node.decorator_list)
|
||||
params: str = self._Arguments(node.args)
|
||||
ret: str = ''
|
||||
@@ -84,6 +90,12 @@ class Unparser:
|
||||
if (isinstance(right, N.Attribute) and right.attr == 'State'
|
||||
and isinstance(right.value, N.Name) and right.value.id == 't'):
|
||||
returns = returns.left
|
||||
if is_export and isinstance(returns, N.BinOp) and isinstance(returns.op, N.BitOr):
|
||||
# 还原 export 原始注解:去掉改写时追加的 | t.CExport
|
||||
right = returns.right
|
||||
if (isinstance(right, N.Attribute) and right.attr == 'CExport'
|
||||
and isinstance(right.value, N.Name) and right.value.id == 't'):
|
||||
returns = returns.left
|
||||
if returns is not None:
|
||||
ret = f' -> {self._expr(returns)}'
|
||||
body: str = self._Block(node.body)
|
||||
|
||||
Reference in new issue
Block a user