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)
|
||||
# ==================================================================
|
||||
|
||||
Reference in new issue
Block a user