feat(struct): TPC 前端支持 struct 关键字(含 C 加速解析器)
与 TransPyV/includes 侧(c27ebc1)逐点对齐:`struct X:` / `struct X(Base):` 脱糖为 `@t.NoVTable class X(t.CStruct):`,禁止 virtual/novirtual 修饰、禁止类体内 def。 - lib/vast/Parser.py:软关键字分派(语句起始 + 后随标识符;`struct = 5` 不受影响)、 _ParseStructDef(复用 _ParseClassDef 全路径 + 合成 @t.NoVTable + 追加 t.CStruct 标记基类 + 类体禁 def 校验)、_StructSyntaxError 报文、_ParseVirtualModified 显式拦截 `virtual/novirtual struct`;@deco 前缀同样支持。 - lib/vast_c/vast_c.c:同构实现(ParseStatement / ParseDecorated 分派、 ParseStructDef、ParseVirtualModified 拦截)。 - lib/vast_c/_parser.pyd:按 README §4.3 的命令重建(gcc 15.2.0)。 验证(两条路径逐一对照):bases=[t.CStruct] / [Base, t.CStruct]、 decos=[t.NoVTable];`virtual struct` 与 `struct 内 def` 均 fail-fast; `struct = 5` 仍解析为普通赋值。
This commit is contained in:
1 parent
85d68e5913
commit
a8f6ca006d
3 files changed
+177
No files matched your search
@@ -62,6 +62,26 @@ _VIRTUAL_EXAMPLE: str = (
|
||||
'novirtual class B: novirtual def helper(self) -> int: ...'
|
||||
)
|
||||
|
||||
# ======================================================================
|
||||
# struct 纯数据类型定义关键字(软关键字)
|
||||
# ======================================================================
|
||||
# 语法:`struct X:` / `struct X(Base):`(与 class 同形,含类型参数 [T] 与关键字实参)
|
||||
# 语义(用户 2026-10-01 定):与 class 同形,但**只能表示数据类型**:
|
||||
# - 禁止 virtual / novirtual 修饰(见 _ParseVirtualModified 的显式拦截);
|
||||
# - 禁止类体内定义 def(见 _ParseStructDef 的 fail-fast);
|
||||
# - 解析期合成 `@t.NoVTable` 装饰器 + 追加 `t.CStruct` 标记基类,
|
||||
# 与手写 `@t.NoVTable class X(t.CStruct):` 逐字段同形 ⇒ 下游
|
||||
# (HandlesClassDef._resolve_class_flags / _MARKER_BASES)零新增判据。
|
||||
# - 允许出现在 REnum 内部(REnum 变体本就是嵌套 ClassDef),也允许 struct 内
|
||||
# 再写 struct(与 class 内写 class 同口径)。
|
||||
# 软关键字边界:只在"语句起始 + 后随标识符"时判定,故 `struct = 5` / `x.struct`
|
||||
# 等作标识符的写法逐字不变。
|
||||
_STRUCT_KEYWORD: str = 'struct'
|
||||
_STRUCT_EXAMPLE: str = (
|
||||
'struct Point: x: int / struct Point: x: int(换行缩进)y: int / '
|
||||
'struct Node(Base): value: int'
|
||||
)
|
||||
|
||||
|
||||
class Parser(ExprParserMixin):
|
||||
"""Viper/Python 完整语法分析器。"""
|
||||
@@ -145,6 +165,10 @@ class Parser(ExprParserMixin):
|
||||
return self._ParseFunctionDef()
|
||||
if v == 'class':
|
||||
return self._ParseClassDef()
|
||||
# struct 纯数据类型定义(软关键字):仅"语句起始 + 后随标识符"时判定,
|
||||
# 故 `struct = 5` / `x.struct` 等作标识符的写法逐字不变。
|
||||
if v == _STRUCT_KEYWORD and self._Peek(1).Type == NAME:
|
||||
return self._ParseStructDef()
|
||||
if v == 'if':
|
||||
return self._ParseIf()
|
||||
if v == 'while':
|
||||
@@ -586,6 +610,8 @@ class Parser(ExprParserMixin):
|
||||
return self._ParseFunctionDef(is_async=True, decorators=decorator_list)
|
||||
if tok.Type == NAME and tok.Value == 'class':
|
||||
return self._ParseClassDef(decorators=decorator_list)
|
||||
if tok.Type == NAME and tok.Value == _STRUCT_KEYWORD and self._Peek(1).Type == NAME:
|
||||
return self._ParseStructDef(decorators=decorator_list)
|
||||
if tok.Type == NAME and tok.Value in _VIRTUAL_MARKERS:
|
||||
# `@deco` 与 `virtual class`/`virtual def` 组合:合成标记追加在既有装饰器之后
|
||||
return self._ParseVirtualModified(decorators=decorator_list)
|
||||
@@ -643,6 +669,13 @@ class Parser(ExprParserMixin):
|
||||
and nxt.Value not in _DEF_ALIASES):
|
||||
nxt_text: str = ('(行尾)' if nxt.Type in (NEWLINE, NL, ENDMARKER)
|
||||
else repr(nxt.Value))
|
||||
if nxt.Type == NAME and nxt.Value == _STRUCT_KEYWORD:
|
||||
# struct 是纯数据类型:禁止 virtual / novirtual 修饰(用户 2026-10-01 定)。
|
||||
# 单独报文(而不是落到通用"后随非 class/def")以便直接给出修法。
|
||||
raise self._StructSyntaxError(
|
||||
f'{mod.Value} struct 非法:struct 禁止 virtual/novirtual 修饰', mod,
|
||||
'struct 天然无虚表(解析期已合成 @t.NoVTable),请直接写 `struct X:`;'
|
||||
'需要虚表语义请改用 class。')
|
||||
raise self._VirtualSyntaxError(
|
||||
f"{mod.Value!r} 后随 {nxt_text}(非 class/def)", mod,
|
||||
f"`{mod.Value}` 只在 class/def(def 的别名 fn/fun/func/function)"
|
||||
@@ -663,6 +696,63 @@ class Parser(ExprParserMixin):
|
||||
return self._ParseClassDef(decorators=deco_list)
|
||||
return self._ParseFunctionDef(decorators=deco_list)
|
||||
|
||||
# ==================================================================
|
||||
# struct 纯数据类型定义(软关键字:`struct X:` / `struct X(Base):`)
|
||||
# ==================================================================
|
||||
def _StructSyntaxError(self, detail: str, tok: Token, extra: str = '') -> SyntaxError:
|
||||
"""构造 struct 非法形态的 fail-fast 报文(与 _VirtualSyntaxError 同结构)。
|
||||
|
||||
含 行:列 + 源码片段 + struct 的三条约束 + 正确示例;行尾附 `at line N`
|
||||
供 TPC 既有诊断路径兜底提取行号(见 HandlesImports._ParseFailureSite)。
|
||||
"""
|
||||
return SyntaxError(
|
||||
f"[TPC] struct 定义非法({detail}):行 {tok.Line} 列 {tok.Col},"
|
||||
f"源码片段 {self._SourceLine(tok.Line).strip()!r}。"
|
||||
f"struct 与 class 同形,但**只能表示数据类型**:"
|
||||
f"① 禁止 virtual / novirtual 修饰(struct 天然无虚表,已内置 @t.NoVTable);"
|
||||
f"② 禁止在 struct 内定义 def(需要方法请改用 class);"
|
||||
f"③ 允许在 REnum 内作为变体、也允许 struct 内再写 struct。"
|
||||
f"正确示例:{_STRUCT_EXAMPLE}。"
|
||||
+ (f" {extra}" if extra else '')
|
||||
+ " (struct 的约束不会被静默忽略:非法形态一律终止编译)"
|
||||
+ f" at line {tok.Line}"
|
||||
)
|
||||
|
||||
def _ParseStructDef(self, decorators: list[N.expr] | None = None) -> N.ClassDef:
|
||||
"""`struct X:` / `struct X(Base):` → 与 `@t.NoVTable class X(t.CStruct):`
|
||||
逐字段同形的 ClassDef(与 TPV 的 _parse_structdef 同口径)。
|
||||
|
||||
实现:复用 _ParseClassDef 的完整解析路径(类型参数 / 基类 / 关键字实参 /
|
||||
类体套件),只在**解析前后**补三件事:
|
||||
· 解析前把合成的 `@t.NoVTable` 追加进装饰器列表(与 virtual/novirtual
|
||||
同款表示)⇒ 类级强制无虚表,即使父类带虚表;
|
||||
· 解析后把 `t.CStruct` 标记基类**追加**到 bases 末尾(不提位用户基类,
|
||||
真实父类解析顺序不变)⇒ 数据类语义(_MARKER_BASES 认它,不当真实父类);
|
||||
· 解析后校验类体**直接子节点**里没有 def —— struct 只能表示数据类型。
|
||||
_ParseClassDef 的首个 `_Next()` 消费的正是 `struct` 关键字本身,故本函数
|
||||
不预先消费,行号/列号与写法均继承自该 token。
|
||||
"""
|
||||
start: Token = self._Peek() # struct(由 _ParseClassDef 的 _Next() 消费)
|
||||
deco: N.expr = N.Attribute(value=N.Name(id='t', ctx=N.Load()),
|
||||
attr='NoVTable', ctx=N.Load())
|
||||
self._FixLoc(deco, start)
|
||||
deco_list: list[N.expr] = list(decorators or [])
|
||||
deco_list.append(deco)
|
||||
node: N.ClassDef = self._ParseClassDef(decorators=deco_list)
|
||||
marker_base: N.expr = N.Attribute(value=N.Name(id='t', ctx=N.Load()),
|
||||
attr='CStruct', ctx=N.Load())
|
||||
self._FixLoc(marker_base, start)
|
||||
node.bases.append(marker_base)
|
||||
for item in node.body:
|
||||
if isinstance(item, N.FunctionDef):
|
||||
bad: Token = start
|
||||
raise self._StructSyntaxError(
|
||||
f"struct {node.name!r} 内定义 def {getattr(item, 'name', '(anonymous)')!r}",
|
||||
bad,
|
||||
'struct 只表示数据类型(与 C 的 struct 同口径);'
|
||||
'若确实需要方法与虚表,请把该类型写成 class。')
|
||||
return node
|
||||
|
||||
# ==================================================================
|
||||
# 函数定义(含软关键字 fn/fun/func/function)
|
||||
# ==================================================================
|
||||
|
||||
Binary file not shown.
@@ -4343,6 +4343,7 @@ static PyObject *ParseDelete(Parser *P);
|
||||
static PyObject *ParseAssert(Parser *P);
|
||||
static PyObject *ParseDecorated(Parser *P);
|
||||
static PyObject *ParseVirtualModified(Parser *P, PyObject *Decorators);
|
||||
static PyObject *ParseStructDef(Parser *P, PyObject *Decorators);
|
||||
static PyObject *ParseTypeParams(Parser *P);
|
||||
static PyObject *ParseExceptHandler(Parser *P);
|
||||
static PyObject *ParseTargetList(Parser *P);
|
||||
@@ -4429,6 +4430,11 @@ static PyObject *ParseStatement(Parser *P) {
|
||||
if (TokIsName(T, "class")) {
|
||||
return ParseClassDef(P, NULL);
|
||||
}
|
||||
/* struct 纯数据类型定义(软关键字:仅"语句起始 + 后随标识符"生效,
|
||||
* 故 `struct = 5` / `x.struct` 作标识符的写法不受影响) */
|
||||
if (TokIsName(T, "struct") && PeekTok(P, 1)->Kind == TK_NAME) {
|
||||
return ParseStructDef(P, NULL);
|
||||
}
|
||||
if (TokIsName(T, "if")) {
|
||||
return ParseIf(P);
|
||||
}
|
||||
@@ -5161,6 +5167,10 @@ static PyObject *ParseDecorated(Parser *P) {
|
||||
if (T->Kind == TK_NAME && TokIsName(T, "class")) {
|
||||
return ParseClassDef(P, DecoratorList);
|
||||
}
|
||||
if (T->Kind == TK_NAME && TokIsName(T, "struct")
|
||||
&& PeekTok(P, 1)->Kind == TK_NAME) {
|
||||
return ParseStructDef(P, DecoratorList);
|
||||
}
|
||||
if (T->Kind == TK_NAME && (TokIsName(T, "virtual") || TokIsName(T, "novirtual"))) {
|
||||
return ParseVirtualModified(P, DecoratorList);
|
||||
}
|
||||
@@ -5189,6 +5199,14 @@ static PyObject *ParseVirtualModified(Parser *P, PyObject *Decorators) {
|
||||
IsDef = 1;
|
||||
}
|
||||
}
|
||||
if (Nxt->Kind == TK_NAME && TokIsName(Nxt, "struct")) {
|
||||
/* struct 是纯数据类型:禁止 virtual / novirtual 修饰(用户 2026-10-01 定)。
|
||||
* struct 解析期已合成 @t.NoVTable,无需也无法再显式声明虚/非虚。 */
|
||||
SyntaxErrorAt(P, Mod,
|
||||
"virtual/novirtual is not allowed on struct "
|
||||
"(struct is data-only, use class for vtable)");
|
||||
return NULL;
|
||||
}
|
||||
if (!IsClass && !IsDef) {
|
||||
SyntaxErrorAt(P, Mod, "virtual/novirtual must precede class/def");
|
||||
return NULL;
|
||||
@@ -5730,6 +5748,75 @@ static PyObject *ParseClassDef(Parser *P, PyObject *Decorators) {
|
||||
return Node;
|
||||
}
|
||||
|
||||
/* struct 纯数据类型定义(对齐 vast Parser._ParseStructDef):
|
||||
* `struct X:` / `struct X(Base):` ≡ `@t.NoVTable class X(t.CStruct):`。
|
||||
* 复用 ParseClassDef 的完整解析路径(类型参数/基类/关键字实参/类体套件)——
|
||||
* ParseClassDef 的首个 NextTok 消费的正是 `struct` 关键字本身,故此处不预消费。
|
||||
* 解析前后各补:合成 @t.NoVTable 装饰器(类级强制无虚表)、追加 t.CStruct
|
||||
* 标记基类(数据类语义,_MARKER_BASES 认它)、校验类体内没有 def。 */
|
||||
static PyObject *ParseStructDef(Parser *P, PyObject *Decorators) {
|
||||
Token *Start = PeekTok(P, 0); /* struct */
|
||||
PyObject *Deco = MakeTAttrNode(P, "NoVTable");
|
||||
if (Deco == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
FixLoc(P, Deco, Start);
|
||||
PyObject *DecoList = NewList();
|
||||
if (DecoList == NULL) {
|
||||
Py_DECREF(Deco);
|
||||
return NULL;
|
||||
}
|
||||
if (Decorators != NULL) {
|
||||
Py_ssize_t N = PyList_GET_SIZE(Decorators);
|
||||
for (Py_ssize_t I = 0; I < N; I++) {
|
||||
PyList_Append(DecoList, PyList_GET_ITEM(Decorators, I));
|
||||
}
|
||||
}
|
||||
PyList_Append(DecoList, Deco);
|
||||
Py_DECREF(Deco);
|
||||
PyObject *Node = ParseClassDef(P, DecoList);
|
||||
Py_DECREF(DecoList);
|
||||
if (Node == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
/* 数据类标记基类:追加在用户基类之后(真实父类解析顺序不变) */
|
||||
PyObject *Bases = PyObject_GetAttrString(Node, "bases");
|
||||
if (Bases == NULL) {
|
||||
PyErr_Clear();
|
||||
} else {
|
||||
PyObject *MarkerBase = MakeTAttrNode(P, "CStruct");
|
||||
if (MarkerBase == NULL) {
|
||||
Py_DECREF(Bases);
|
||||
Py_DECREF(Node);
|
||||
return NULL;
|
||||
}
|
||||
FixLoc(P, MarkerBase, Start);
|
||||
PyList_Append(Bases, MarkerBase);
|
||||
Py_DECREF(MarkerBase);
|
||||
Py_DECREF(Bases);
|
||||
}
|
||||
/* struct 禁止 def:检查类体直接子节点(嵌套 struct 由其自身解析自检) */
|
||||
PyObject *Body = PyObject_GetAttrString(Node, "body");
|
||||
if (Body == NULL) {
|
||||
PyErr_Clear();
|
||||
return Node;
|
||||
}
|
||||
Py_ssize_t BN = PyList_GET_SIZE(Body);
|
||||
for (Py_ssize_t I = 0; I < BN; I++) {
|
||||
PyObject *Item = PyList_GET_ITEM(Body, I);
|
||||
if (Item != NULL && NodeIs(Item, "FunctionDef")) {
|
||||
SyntaxErrorAt(P, Start,
|
||||
"def is not allowed inside struct "
|
||||
"(struct is data-only, use class for methods)");
|
||||
Py_DECREF(Body);
|
||||
Py_DECREF(Node);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
Py_DECREF(Body);
|
||||
return Node;
|
||||
}
|
||||
|
||||
/* 语句块(套件) */
|
||||
static PyObject *ParseSuiteImpl(Parser *P) {
|
||||
if (PeekTok(P, 0)->Kind == TK_NEWLINE) {
|
||||
|
||||
Reference in new issue
Block a user