类型注解不再接受任何 T1 | T2;const/volatile/static/export/extern/inline/define/typedef/__attribute__/BigEndian/LittleEndian/Bit 改为注解节点字段 Markers/Attributes/ByteOrder/BitWidth;指针与引用改为 CPtr[T]/CRef[T]/CTempRef[T]/CArrayPtr[T]/CAutoPtr[T];Python 与 vast_c 两套解析器、类型解析与声明端同步;C 扩展早于 vast_c.c 时自动回退纯 Python 解析器。
1934 lines
86 KiB
Python
1934 lines
86 KiB
Python
"""vast.parser - Viper/Python 语句级语法分析器
|
||
|
||
基于 vast.tokenizer + vast.exprparser,实现与 CPython 3.12 ``ast.parse``
|
||
结构完全一致的语句解析:
|
||
|
||
- 简单语句:赋值/增强赋值/带注解赋值/表达式/import/from-import/global/
|
||
nonlocal/del/assert/pass/break/continue/return/raise
|
||
- 复合语句:if/while/for/try/with/match/def/class/async def-for-with
|
||
- 装饰器、嵌套块(INDENT/DEDENT)、分号分隔、类型注解
|
||
- Viper 软关键字 fn/fun/func/function → FunctionDef(并入解析器,无需
|
||
ExpandSoftKeywords 预处理)
|
||
|
||
产出与 CPython ast 完全一致的节点,含 4 位置属性。
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
from lib.vast import Nodes as N
|
||
from lib.vast.ExprParser import ExprParserMixin
|
||
from lib.vast.Tokenizer import (
|
||
Token, NAME, NUMBER, STRING, FSTRING, OP, NEWLINE, NL, INDENT, DEDENT,
|
||
ENDMARKER, SOFT_KEYWORDS,
|
||
)
|
||
|
||
|
||
# ======================================================================
|
||
# virtual / novirtual 修饰符(软关键字)
|
||
# ======================================================================
|
||
# 语法:`virtual class` / `novirtual class` / `virtual def` / `novirtual def`
|
||
# (修饰符写在 class/def **之前**,允许与修饰对象同行,也允许各占一行)。
|
||
#
|
||
# 语义:与既有装饰器**同一套表示**——virtual → `@CVTable`,
|
||
# novirtual → `@NoVTable`。本层只"合成装饰器节点",不新增第二套表示:
|
||
# - 类级:CVTable 强制有 vtable / NoVTable 强制无 vtable
|
||
# (TPC:HandlesClassDef._resolve_class_flags 读 ClassDef.decorator_list
|
||
# 的 CVTable/NoVTable;VPC:ClassGenBase._detect_vtable_status)
|
||
# - 方法级:CVTable 进虚表槽 / NoVTable 不进虚表槽
|
||
# (VPC:ClassGenBase._should_method_be_virtual;TPC:同判据见
|
||
# SymbolUtils.ClassVtableSlotMethods / 方法收集处)
|
||
#
|
||
# 行号守恒:合成节点的位置取"修饰符 token"的位置,ClassDef/FunctionDef 自身的
|
||
# lineno/col_offset 仍是源码里 class/def 的真实位置 ⇒ 与手写装饰器形态在
|
||
# 行号上也不产生任何偏移(vs 文本插入装饰器行会整篇 +1 行)。
|
||
#
|
||
# 软关键字边界(非保留字):
|
||
# - 只在**语句起始**且后随 class/def 时生效;作标识符的其它位置
|
||
# (`x.virtual` / `f(virtual)` / `d = {"virtual": 1}`)逐字不变;
|
||
# - 语句起始但后随非 class/def ⇒ **响亮失败**(绝不静默丢弃修饰符);
|
||
# - `virtual def` / `novirtual def` 出现在类体之外(模块级 / 函数体 / 分支体)
|
||
# ⇒ **响亮失败**。
|
||
_VIRTUAL_MARKERS: dict[str, str] = {'virtual': 'CVTable', 'novirtual': 'NoVTable'}
|
||
# def 的别名(与 Tokenizer.SOFT_KEYWORDS 的 def 系列同集合,**不含** extern——
|
||
# extern 由 _ParseExternDef 单独解析,不能走 _ParseFunctionDef)
|
||
_DEF_ALIASES: tuple[str, ...] = ('fn', 'fun', 'func', 'function')
|
||
_VIRTUAL_POSITION_HINT: str = (
|
||
'可写位置:类级 `virtual class C:` / `novirtual class C:`;'
|
||
'方法级 `virtual def m(self): ...` / `novirtual def m(self): ...`'
|
||
'(**只能写在类体内**:virtual class / class / novirtual class 的类体)'
|
||
)
|
||
_VIRTUAL_EXAMPLE: str = (
|
||
'virtual class Shape: / novirtual class Node: / '
|
||
'class A: virtual def run(self) -> int: ... / '
|
||
'novirtual class B: novirtual def helper(self) -> int: ...'
|
||
)
|
||
|
||
# tls 修饰符(软关键字):`tls def f(...)` ⇒ 合成既有装饰器 `@TLS`
|
||
#(一次性初始化守卫,见 HandlesFunctions 的 TLS 分支)。与 virtual/novirtual 同一套
|
||
# "软关键字 + 合成既有装饰器"表示,不新增第二套语义;只在语句起始且后随 def 时生效,
|
||
# 故 `tls: local = local()` / `tls.set(...)` 等把 tls 当标识符的写法逐字不变。
|
||
_TLS_KEYWORD: str = 'tls'
|
||
|
||
# ======================================================================
|
||
# struct 纯数据类型定义关键字(软关键字)
|
||
# ======================================================================
|
||
# 语法:`struct X:` / `struct X(Base):`(与 class 同形,含类型参数 [T] 与关键字实参)
|
||
# 语义(用户 2026-10-01 定):与 class 同形,但**只能表示数据类型**:
|
||
# - 禁止 virtual / novirtual 修饰(见 _ParseVirtualModified 的显式拦截);
|
||
# - 禁止类体内定义 def(见 _ParseStructDef 的 fail-fast);
|
||
# - 解析期合成 `@NoVTable` 装饰器 + 追加 `CStruct` 标记基类,
|
||
# 与手写 `@NoVTable class X(CStruct):` 逐字段同形 ⇒ 下游
|
||
# (HandlesClassDef._resolve_class_flags / _MARKER_BASES)零新增判据。
|
||
# - 允许出现在 REnum 内部(REnum 变体本就是嵌套 ClassDef),也允许 struct 内
|
||
# 再写 struct(与 class 内写 class 同口径)。
|
||
# struct 纯数据类型定义(硬关键字):语句起始一律按 struct 定义解析
|
||
# (`struct = 5` / `x.struct` 之类把 struct 当标识符的写法已不再允许)。
|
||
_STRUCT_KEYWORD: str = 'struct'
|
||
_STRUCT_EXAMPLE: str = (
|
||
'struct Point: x: int / struct Point: x: int(换行缩进)y: int / '
|
||
'struct Node(Base): value: int'
|
||
)
|
||
|
||
# switch 多分支语句(硬关键字,C switch 语义):`switch <expr>:` + `case <常量>:`
|
||
# / `default:`。默认不穿透,case 体内写 `fallthrough` 才落到下一个 case。
|
||
# 解析时 desugar 为 is_switch=True 的 N.Match。
|
||
_SWITCH_KEYWORD: str = 'switch'
|
||
|
||
# fallthrough 关键字(硬):仅在 switch 的 case 体内合法,脱糖为 `NoBreak()`
|
||
# 标记调用(switch 生成侧据此让 case 体不自动跳出 switch,落到下一个 case)。
|
||
_FALLTHROUGH_KEYWORD: str = 'fallthrough'
|
||
|
||
# ======================================================================
|
||
# cif / celif / celse 编译期条件编译(软关键字)
|
||
# ======================================================================
|
||
# 语法:`cif <编译期常量表达式>:` / `celif <...>:` / `celse:`
|
||
# 语义:只有 cif 能开链;celif/celse 必须属于同一条 cif 链。
|
||
# 解析期 desugar 为既有「If + CIf 族标记调用」形状(与 Viper 侧口径一致):
|
||
# cif E: → If(test=c.@CIf(E), body, orelse)
|
||
# celif E: → 同链下一个 If(test=c.@CIf(E), ...)(挂在上一支 orelse)
|
||
# celse: → 普通 orelse
|
||
# defined(N) → c.@CIfdef(N) 标记调用
|
||
# 标记(c.@CIf / c.@CIfdef)是内部表示:用户写 CIf(...) 在 ExprParser 处报错。
|
||
_CIF_KEYWORD: str = 'cif'
|
||
_CELIF_KEYWORD: str = 'celif'
|
||
_CELSE_KEYWORD: str = 'celse'
|
||
# 内部 CIf 族标记:desugar 产出的调用名(用户不可写)。
|
||
# 与 Viper 侧解析器(includes/ast/parser.vp 的 _MakeCifMarker)同拼写:属性名带前导 '@',
|
||
# 词法器无法产出该拼写,故用户写的 CIf(...) 永远不会命中此标记(会被 ExprParser 拒绝)。
|
||
_CIF_MARKER: str = '@CIf'
|
||
_CIFDEF_MARKER: str = '@CIfdef'
|
||
# cif 语句起始判定:语句起始 NAME('cif') 后紧跟这些运算符时按普通语句(赋值/注解)
|
||
# 处理,避免 `cif = 5` / `cif: int = 5` 被误判为 cif 语句。
|
||
_CIF_NON_STATEMENT_OPS: frozenset[str] = frozenset({
|
||
'=', ':', '+=', '-=', '*=', '/=', '//=', '%=', '**=',
|
||
'<<=', '>>=', '&=', '|=', '^=', '@=',
|
||
})
|
||
|
||
|
||
class Parser(ExprParserMixin):
|
||
"""Viper/Python 完整语法分析器。"""
|
||
|
||
# virtual / novirtual 修饰符:语句起始 + 紧跟 class/def 时才生效(软关键字)。
|
||
# _InClassBody:当前正在解析的套件的**直接拥有者**是否为 ClassDef
|
||
# (由 _ParseSuite 按 owner_is_class 维护),用于 fail-fast
|
||
# "virtual def / novirtual def 只能直接写在类体内"。
|
||
_InClassBody: bool = False
|
||
|
||
# _InCIfCond:当前是否正在解析 cif/celif 的条件表达式。用于判定 `defined(NAME)`
|
||
# 谓词的合法位置(仅 cif/celif 条件内合法,其余位置 FailFast)。
|
||
_InCIfCond: bool = False
|
||
|
||
# ==================================================================
|
||
# 模块级入口
|
||
# ==================================================================
|
||
def ParseModule(self) -> N.Module:
|
||
"""解析整个模块:返回 Module(body=..., type_ignores=[])。"""
|
||
body: list[N.stmt] = []
|
||
self._SkipNEWLINE()
|
||
while self._Peek().Type != ENDMARKER:
|
||
stmt: N.stmt = self.ParseStatement()
|
||
body.append(stmt)
|
||
# 分号分隔后续语句(简单语句一行多条)
|
||
while self._AtOp(';'):
|
||
self._Next()
|
||
if self._At(NEWLINE):
|
||
break
|
||
extra: N.stmt = self.ParseStatement()
|
||
body.append(extra)
|
||
self._SkipNEWLINE()
|
||
module: N.Module = N.Module(body=body, type_ignores=[])
|
||
return module
|
||
|
||
# ==================================================================
|
||
# 语句分派
|
||
# ==================================================================
|
||
def ParseStatement(self) -> N.stmt:
|
||
"""解析单条语句(含复合语句分派)。"""
|
||
tok: Token = self._Peek()
|
||
if tok.Type == NAME:
|
||
v: str = tok.Value
|
||
# extern:变量声明 `extern 名字: 类型`(禁止初值)与函数声明
|
||
# `extern [def] 名字(...)` 共用起始关键字;第二个 token 是 NAME 且
|
||
# 再后随 ':' / '=' 时按变量声明解析,否则按函数声明解析。
|
||
if v == 'extern':
|
||
if self._IsStorageVarStart():
|
||
return self._ParseStorageVar('extern')
|
||
return self._ParseExternDef()
|
||
# export:变量声明 `export 名字: 类型 [= 初值]` 与函数声明
|
||
# `export [def] 名字(...)` 同理分派。
|
||
if v == 'export':
|
||
if self._IsStorageVarStart():
|
||
return self._ParseStorageVar('export')
|
||
return self._ParseExportDef()
|
||
# static:`static def 名字` 为函数定义;`static 名字: 类型` 为变量声明。
|
||
# 判据要求第二个 token 是 NAME 且再后随 ':' / '=',故
|
||
# `static = 5` / `static x` 不会被误吃成修饰声明。
|
||
if v == 'static':
|
||
if (self._Peek(1).Type == NAME
|
||
and self._Peek(1).Value == 'def'):
|
||
return self._ParseStaticDef()
|
||
if self._IsStorageVarStart():
|
||
return self._ParseStorageVar('static')
|
||
# define:`define 名字 = 值` / `define 名字: 类型 = 值` 为编译期常量
|
||
# 声明;`define 名字(...)` / `define 名字[T](...)` 为宏函数定义。
|
||
if v == 'define' and self._Peek(1).Type == NAME:
|
||
if self._IsStorageVarStart():
|
||
return self._ParseDefineVar()
|
||
return self._ParseDefineDef()
|
||
# typedef 名字 = 类型:类型别名声明(右值按类型注解解析)。
|
||
if v == 'typedef' and self._Peek(1).Type == NAME:
|
||
return self._ParseTypedefVar()
|
||
# virtual / novirtual 修饰符(软关键字):只在"语句起始 + 紧跟 class/def"
|
||
# 时生效,合成既有装饰器 @CVTable / @NoVTable(见 _ParseVirtualModified)。
|
||
# 放在 def/class 分派之前:修饰符必须先被消费,class/def 才能照常分派。
|
||
# 与软关键字 fn→def 的先后关系:`.vp` 源码在进入本解析器之前已过
|
||
# SymbolUtils.ExpandSoftKeywords(fn/fun/func/function → def),
|
||
# 故 `virtual fn m()` 在此已是 `virtual def m()`;本层只认 class/def。
|
||
if v in _VIRTUAL_MARKERS:
|
||
return self._ParseVirtualModified()
|
||
# tls 修饰符(软关键字):语句起始 + 紧跟 def 时生效,合成既有装饰器 @TLS。
|
||
if v == _TLS_KEYWORD and self._IsTlsDefStart():
|
||
return self._ParseTlsModified()
|
||
# 软关键字函数定义:fn/fun/func/function + 标识符
|
||
if v in SOFT_KEYWORDS and self._Peek(1).Type == NAME:
|
||
return self._ParseFunctionDef()
|
||
if v == 'async':
|
||
nxt: Token = self._Peek(1)
|
||
if nxt.Type == NAME and nxt.Value == 'def':
|
||
return self._ParseFunctionDef(is_async=True)
|
||
if nxt.Type == NAME and nxt.Value == 'for':
|
||
return self._ParseFor(is_async=True)
|
||
if nxt.Type == NAME and nxt.Value == 'with':
|
||
return self._ParseWith(is_async=True)
|
||
if v == 'def':
|
||
return self._ParseFunctionDef()
|
||
if v == 'class':
|
||
return self._ParseClassDef()
|
||
# struct 纯数据类型定义(硬关键字):语句起始一律按 struct 定义解析。
|
||
if v == _STRUCT_KEYWORD:
|
||
return self._ParseStructDef()
|
||
# cif 编译期条件编译(软关键字):语句起始 + 非赋值/注解形态。
|
||
if v == _CIF_KEYWORD and self._IsCIfStatementStart():
|
||
return self._ParseCIf()
|
||
# celif / celse 必须属于某条 cif 链(由 _ParseCIf 直接消费);
|
||
# 语句起始独立出现 ⇒ FailFast。
|
||
if v == _CELIF_KEYWORD or v == _CELSE_KEYWORD:
|
||
raise SyntaxError(
|
||
f"'{v}' must belong to a 'cif' chain (no matching 'cif') "
|
||
f"at line {tok.Line}")
|
||
if v == 'if':
|
||
return self._ParseIf()
|
||
if v == 'while':
|
||
return self._ParseWhile()
|
||
if v == 'for':
|
||
return self._ParseFor()
|
||
if v == 'try':
|
||
return self._ParseTry()
|
||
if v == 'with':
|
||
return self._ParseWith()
|
||
# match 多模式匹配(硬关键字):语句起始一律按 match 语句解析。
|
||
if v == 'match':
|
||
return self._ParseMatch()
|
||
# switch 多分支(硬关键字,C switch 语义):desugar 为 is_switch=True 的 Match。
|
||
if v == _SWITCH_KEYWORD:
|
||
return self._ParseSwitch()
|
||
# fallthrough 关键字(硬):仅在 switch 的 case 体内合法,脱糖为
|
||
# `NoBreak()` 标记调用,由 switch 生成侧消费(case 体因此不自动
|
||
# 跳出 switch)。合法位置由生成侧判定:写进 match 或 switch 之外
|
||
# 一律 FailFastError。
|
||
if v == _FALLTHROUGH_KEYWORD:
|
||
return self._ParseFallThrough()
|
||
if v == 'return':
|
||
return self._ParseReturn()
|
||
if v == 'raise':
|
||
return self._ParseRaise()
|
||
if v == 'import':
|
||
return self._ParseImport()
|
||
if v == 'from':
|
||
return self._ParseImportFrom()
|
||
if v == 'global':
|
||
return self._ParseGlobal('global')
|
||
if v == 'nonlocal':
|
||
return self._ParseGlobal('nonlocal')
|
||
if v == 'del':
|
||
return self._ParseDelete()
|
||
if v == 'assert':
|
||
return self._ParseAssert()
|
||
if v == 'pass':
|
||
self._Next()
|
||
node: N.Pass = N.Pass()
|
||
self._FixLoc(node, tok)
|
||
return node
|
||
if v == 'break':
|
||
self._Next()
|
||
node = N.Break()
|
||
self._FixLoc(node, tok)
|
||
return node
|
||
if v == 'continue':
|
||
self._Next()
|
||
node = N.Continue()
|
||
self._FixLoc(node, tok)
|
||
return node
|
||
if v == 'yield':
|
||
# yield 作为表达式语句
|
||
return self._ParseExprStmt()
|
||
if tok.Type == OP and tok.Value == '@':
|
||
return self._ParseDecorated()
|
||
return self._ParseSimpleStmt()
|
||
|
||
# ==================================================================
|
||
# 语句级变量修饰形态(static / export / extern / define / typedef)
|
||
# ==================================================================
|
||
def _IsStorageVarStart(self) -> bool:
|
||
"""当前修饰词之后是否为变量声明形态:`修饰词 名字 :` 或 `修饰词 名字 =`。"""
|
||
if self._Peek(1).Type != NAME:
|
||
return False
|
||
nxt: Token = self._Peek(2)
|
||
return nxt.Type == OP and nxt.Value in (':', '=')
|
||
|
||
@staticmethod
|
||
def _AddTypeMarkers(node: N.AST, marker: str) -> None:
|
||
"""把修饰词追加到类型节点的 Markers 字段(保持出现顺序、去重)。"""
|
||
if not hasattr(type(node), 'Markers'):
|
||
return
|
||
existing: tuple[str, ...] = tuple(getattr(node, 'Markers', ()) or ())
|
||
if marker not in existing:
|
||
node.Markers = existing + (marker,)
|
||
|
||
def _ParseStorageVar(self, marker: str) -> N.AnnAssign:
|
||
"""解析 `static|export|extern 名字: 类型 [= 初值]` 为 AnnAssign。
|
||
|
||
`extern` 变量只声明不定义,禁止初值。
|
||
"""
|
||
start: Token = self._Next() # 修饰词
|
||
name_tok: Token = self._ExpectName()
|
||
if not self._AtOp(':'):
|
||
raise SyntaxError(
|
||
f"[vast] `{marker} 名字` 变量声明必须带类型注解:"
|
||
f"期望 `{marker} {name_tok.Value}: 类型"
|
||
f"{' [= 初值]' if marker != 'extern' else ''}`。")
|
||
self._Next() # ':'
|
||
annotation: N.expr = self._ParseTypeAnnotation()
|
||
value: N.expr | None = None
|
||
if self._AtOp('='):
|
||
if marker == 'extern':
|
||
raise SyntaxError(
|
||
f"[vast] extern 变量声明不能带初始值(符号定义在外部):"
|
||
f"`extern {name_tok.Value}: 类型`。")
|
||
self._Next()
|
||
value = self.ParseExpr()
|
||
self._AddTypeMarkers(annotation, marker)
|
||
target: N.Name = N.Name(id=name_tok.Value, ctx=N.Store())
|
||
self._FixLoc(target, name_tok)
|
||
node: N.AnnAssign = N.AnnAssign(
|
||
target=target, annotation=annotation, value=value, simple=1)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParseDefineVar(self) -> N.AnnAssign:
|
||
"""解析 `define 名字[: 类型] = 值` 为编译期常量声明(Markers += 'define')。"""
|
||
start: Token = self._Next() # 'define'
|
||
name_tok: Token = self._ExpectName()
|
||
annotation: N.expr | None = None
|
||
if self._AtOp(':'):
|
||
self._Next()
|
||
annotation = self._ParseTypeAnnotation()
|
||
if not self._AtOp('='):
|
||
raise SyntaxError(
|
||
f"[vast] define 常量声明缺少初值:"
|
||
f"期望 `define {name_tok.Value}[: 类型] = 值`。")
|
||
self._Next() # '='
|
||
value: N.expr = self.ParseExpr()
|
||
if annotation is None:
|
||
# 未标注类型:注解占位为 CDefine(Markers 仍承载 'define')。
|
||
annotation = N.Name(id='CDefine', ctx=N.Load())
|
||
self._FixLoc(annotation, start)
|
||
self._AddTypeMarkers(annotation, 'define')
|
||
target: N.Name = N.Name(id=name_tok.Value, ctx=N.Store())
|
||
self._FixLoc(target, name_tok)
|
||
node: N.AnnAssign = N.AnnAssign(
|
||
target=target, annotation=annotation, value=value, simple=1)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParseTypedefVar(self) -> N.AnnAssign:
|
||
"""解析 `typedef 名字 = 类型` 为类型别名声明(Markers += 'typedef')。
|
||
|
||
右值按类型注解解析(支持 `T*` 等 C 风格后缀)。
|
||
"""
|
||
start: Token = self._Next() # 'typedef'
|
||
name_tok: Token = self._ExpectName()
|
||
if not self._AtOp('='):
|
||
raise SyntaxError(
|
||
f"[vast] typedef 语法错误:"
|
||
f"期望 `typedef {name_tok.Value} = 类型`。")
|
||
self._Next() # '='
|
||
type_node: N.expr = self._ParseTypeAnnotation()
|
||
self._AddTypeMarkers(type_node, 'typedef')
|
||
target: N.Name = N.Name(id=name_tok.Value, ctx=N.Store())
|
||
self._FixLoc(target, name_tok)
|
||
node: N.AnnAssign = N.AnnAssign(
|
||
target=target, annotation=type_node, value=type_node, simple=1)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
# ==================================================================
|
||
# fallthrough 关键字(语句级)
|
||
# ==================================================================
|
||
def _ParseFallThrough(self) -> N.stmt:
|
||
"""`fallthrough` 脱糖为 `NoBreak()`(switch 生成侧识别的 fallthrough 标记)
|
||
|
||
合法位置只有 switch 的 case 体;写进 match 或 switch 之外由生成侧
|
||
(HandlesMatch / HandlesBody)fail-fast。
|
||
"""
|
||
tok: Token = self._Peek()
|
||
self._Next()
|
||
marker: N.Call = N.Call(
|
||
func=N.Name(id='NoBreak', ctx=N.Load()),
|
||
args=[], keywords=[])
|
||
node: N.Expr = N.Expr(value=marker)
|
||
self._FixLoc(node, tok)
|
||
return node
|
||
|
||
# ==================================================================
|
||
# 简单语句
|
||
# ==================================================================
|
||
def _ParseSimpleStmt(self) -> N.stmt:
|
||
"""解析简单语句(赋值/增强赋值/带注解赋值/表达式)。
|
||
|
||
不消费分号/NEWLINE,由调用方循环(ParseModule/_ParseSuite)统一处理。
|
||
"""
|
||
start: Token = self._Peek()
|
||
# 尝试带注解赋值 x: T [= v]
|
||
ann: N.stmt | None = self._TryParseAnnAssign()
|
||
if ann is not None:
|
||
return ann
|
||
# 表达式/赋值(testlist_star_expr)
|
||
expr: N.expr = self.ParseExprList()
|
||
# 赋值链
|
||
if self._AtOp('='):
|
||
targets: list[N.expr] = [self._AsLoadTarget(expr)]
|
||
while True:
|
||
self._Next() # '='
|
||
value: N.expr = self.ParseExprList()
|
||
if self._AtOp('='):
|
||
targets.append(self._AsLoadTarget(value))
|
||
continue
|
||
break
|
||
node: N.Assign = N.Assign(targets=targets, value=value, type_comment=None)
|
||
self._FixLoc(node, start)
|
||
stmt = node
|
||
elif self._AtOp('+='):
|
||
self._Next()
|
||
value = self.ParseExpr()
|
||
node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.Add(), value=value)
|
||
self._FixLoc(node, start)
|
||
stmt = node
|
||
elif self._AtOp('-='):
|
||
self._Next()
|
||
value = self.ParseExpr()
|
||
node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.Sub(), value=value)
|
||
self._FixLoc(node, start)
|
||
stmt = node
|
||
elif self._AtOp('*='):
|
||
self._Next()
|
||
value = self.ParseExpr()
|
||
node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.Mult(), value=value)
|
||
self._FixLoc(node, start)
|
||
stmt = node
|
||
elif self._AtOp('/='):
|
||
self._Next()
|
||
value = self.ParseExpr()
|
||
node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.Div(), value=value)
|
||
self._FixLoc(node, start)
|
||
stmt = node
|
||
elif self._AtOp('//='):
|
||
self._Next()
|
||
value = self.ParseExpr()
|
||
node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.FloorDiv(), value=value)
|
||
self._FixLoc(node, start)
|
||
stmt = node
|
||
elif self._AtOp('%='):
|
||
self._Next()
|
||
value = self.ParseExpr()
|
||
node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.Mod(), value=value)
|
||
self._FixLoc(node, start)
|
||
stmt = node
|
||
elif self._AtOp('**='):
|
||
self._Next()
|
||
value = self.ParseExpr()
|
||
node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.Pow(), value=value)
|
||
self._FixLoc(node, start)
|
||
stmt = node
|
||
elif self._AtOp('<<='):
|
||
self._Next()
|
||
value = self.ParseExpr()
|
||
node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.LShift(), value=value)
|
||
self._FixLoc(node, start)
|
||
stmt = node
|
||
elif self._AtOp('>>='):
|
||
self._Next()
|
||
value = self.ParseExpr()
|
||
node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.RShift(), value=value)
|
||
self._FixLoc(node, start)
|
||
stmt = node
|
||
elif self._AtOp('&='):
|
||
self._Next()
|
||
value = self.ParseExpr()
|
||
node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.BitAnd(), value=value)
|
||
self._FixLoc(node, start)
|
||
stmt = node
|
||
elif self._AtOp('|='):
|
||
self._Next()
|
||
value = self.ParseExpr()
|
||
node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.BitOr(), value=value)
|
||
self._FixLoc(node, start)
|
||
stmt = node
|
||
elif self._AtOp('^='):
|
||
self._Next()
|
||
value = self.ParseExpr()
|
||
node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.BitXor(), value=value)
|
||
self._FixLoc(node, start)
|
||
stmt = node
|
||
elif self._AtOp('@='):
|
||
self._Next()
|
||
value = self.ParseExpr()
|
||
node = N.AugAssign(target=self._AsLoadTarget(expr), op=N.MatMult(), value=value)
|
||
self._FixLoc(node, start)
|
||
stmt = node
|
||
else:
|
||
node = N.Expr(value=expr)
|
||
self._FixLoc(node, start)
|
||
stmt = node
|
||
return stmt
|
||
|
||
def _AsLoadTarget(self, expr: N.expr) -> N.expr:
|
||
"""将已解析表达式(Load 上下文)转为赋值目标(Store 上下文)。"""
|
||
self._SetStoreContext(expr)
|
||
return expr
|
||
|
||
@staticmethod
|
||
def _IsCTypedefAnnotation(annotation: N.expr | None) -> bool:
|
||
"""注解是否为 typedef 标记(裸 `CTypedef` / 含它的 `|` 联合)。
|
||
|
||
用于把 typedef 的右值按**类型位置**解析(`X: CTypedef = T` 里的 `*`
|
||
后缀由 _ParseTypeAnnotation 消费,与注解位同一规则)。仅按标记名判定,
|
||
不依赖 import 别名表(与 VPC `_IsCTypedefAnnotation` 同口径)。
|
||
"""
|
||
if annotation is None:
|
||
return False
|
||
if isinstance(annotation, N.Attribute):
|
||
return getattr(annotation, 'attr', None) == 'CTypedef'
|
||
if isinstance(annotation, N.Name):
|
||
return getattr(annotation, 'id', None) == 'CTypedef'
|
||
if isinstance(annotation, N.BinOp):
|
||
return (Parser._IsCTypedefAnnotation(getattr(annotation, 'left', None))
|
||
or Parser._IsCTypedefAnnotation(getattr(annotation, 'right', None)))
|
||
return False
|
||
|
||
def _TryParseAnnAssign(self) -> N.AnnAssign | None:
|
||
"""尝试解析带注解赋值:x: T [= v] 或 x: T(目标为 Name/Attribute/Subscript)。
|
||
|
||
注意:仅当目标为简单 Name/Attribute/Subscript 且后随 ':' 时匹配;
|
||
元组/列表解包不做注解(返回 None 走普通路径)。
|
||
|
||
`CTypedef` 注解的右值是**类型**而非一般表达式(`const str` / `uint16*`),
|
||
故走 `_ParseTypeAnnotation`(与注解位同一路径,支持 C 式指针后缀)。
|
||
"""
|
||
start: Token = self._Peek()
|
||
# 名称
|
||
if self._At(NAME) and self._Peek(1).Type == OP and self._Peek(1).Value == ':':
|
||
name_tok: Token = self._Next()
|
||
self._Next() # ':'
|
||
annotation: N.expr = self._ParseTypeAnnotation()
|
||
value: N.expr | None = None
|
||
if self._AtOp('='):
|
||
self._Next()
|
||
if self._IsCTypedefAnnotation(annotation):
|
||
value = self._ParseTypeAnnotation()
|
||
else:
|
||
value = self.ParseExpr()
|
||
target: N.Name = N.Name(id=name_tok.Value, ctx=N.Store())
|
||
self._FixLoc(target, name_tok)
|
||
node: N.AnnAssign = N.AnnAssign(target=target, annotation=annotation,
|
||
value=value, simple=1)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
# 属性/下标目标(无简单解包)
|
||
if self._At(NAME) or (self._At(OP) and self._Peek().Value in ('(', '[')):
|
||
save: int = self.Idx
|
||
try:
|
||
expr: N.expr = self.ParseExpr()
|
||
except SyntaxError:
|
||
self.Idx = save
|
||
return None
|
||
if self._AtOp(':') and isinstance(expr, (N.Name, N.Attribute, N.Subscript)):
|
||
self._Next()
|
||
annotation = self._ParseTypeAnnotation()
|
||
value = None
|
||
if self._AtOp('='):
|
||
self._Next()
|
||
if self._IsCTypedefAnnotation(annotation):
|
||
value = self._ParseTypeAnnotation()
|
||
else:
|
||
value = self.ParseExpr()
|
||
self._SetStoreContext(expr)
|
||
simple: int = 1 if isinstance(expr, N.Name) else 0
|
||
node = N.AnnAssign(target=expr, annotation=annotation, value=value, simple=simple)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
self.Idx = save
|
||
return None
|
||
|
||
# ------------------------------------------------------------------
|
||
# return / raise / import / global / del / assert
|
||
# ------------------------------------------------------------------
|
||
def _ParseReturn(self) -> N.Return:
|
||
start: Token = self._Next() # 'return'
|
||
value: N.expr | None = None
|
||
if not self._At(NEWLINE) and not self._AtOp(';'):
|
||
value = self.ParseExprList()
|
||
node: N.Return = N.Return(value=value)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParseRaise(self) -> N.Raise:
|
||
start: Token = self._Next() # 'raise'
|
||
exc: N.expr | None = None
|
||
cause: N.expr | None = None
|
||
if not self._At(NEWLINE) and not self._AtOp(';'):
|
||
exc = self.ParseExpr()
|
||
if self._AtName('from'):
|
||
self._Next()
|
||
cause = self.ParseExpr()
|
||
node: N.Raise = N.Raise(exc=exc, cause=cause)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParseImport(self) -> N.Import:
|
||
start: Token = self._Next() # 'import'
|
||
names: list[N.alias] = []
|
||
while True:
|
||
# 点分模块名:alias 位置从首个名称起、到末个名称(或 asname)止
|
||
name_tok: Token = self._ExpectName()
|
||
end_tok: Token = name_tok
|
||
name_parts: list[str] = [name_tok.Value]
|
||
while self._AtOp('.'):
|
||
self._Next()
|
||
end_tok = self._ExpectName()
|
||
name_parts.append(end_tok.Value)
|
||
full: str = '.'.join(name_parts)
|
||
asname: str | None = None
|
||
if self._AtName('as'):
|
||
self._Next()
|
||
as_tok: Token = self._ExpectName()
|
||
asname = as_tok.Value
|
||
end_tok = as_tok
|
||
alias: N.alias = N.alias(name=full, asname=asname)
|
||
self._FixLoc(alias, name_tok, end_tok)
|
||
names.append(alias)
|
||
if self._AtOp(','):
|
||
self._Next()
|
||
continue
|
||
break
|
||
node: N.Import = N.Import(names=names)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParseImportFrom(self) -> N.ImportFrom:
|
||
start: Token = self._Next() # 'from'
|
||
level: int = 0
|
||
while self._AtOp('.'):
|
||
self._Next()
|
||
level += 1
|
||
module: str | None = None
|
||
# from . import x → 点后直接是 import(无模块名)
|
||
if not self._AtName('import'):
|
||
parts: list[str] = [self._ExpectName().Value]
|
||
while self._AtOp('.'):
|
||
self._Next()
|
||
parts.append(self._ExpectName().Value)
|
||
module = '.'.join(parts)
|
||
self._ExpectName('import')
|
||
names: list[N.alias] = []
|
||
# from x import * | (a, b) | a, b
|
||
if self._AtOp('('):
|
||
self._Next()
|
||
self._SkipNL()
|
||
if not self._AtOp(')'):
|
||
while True:
|
||
names.append(self._ParseImportAlias())
|
||
self._SkipNL()
|
||
if self._AtOp(','):
|
||
self._Next()
|
||
self._SkipNL()
|
||
if self._AtOp(')'):
|
||
break
|
||
continue
|
||
break
|
||
self._ExpectOp(')')
|
||
else:
|
||
if self._AtOp('*'):
|
||
star_tok: Token = self._Next()
|
||
alias = N.alias(name='*', asname=None)
|
||
self._FixLoc(alias, star_tok)
|
||
names.append(alias)
|
||
else:
|
||
while True:
|
||
names.append(self._ParseImportAlias())
|
||
if self._AtOp(','):
|
||
self._Next()
|
||
continue
|
||
break
|
||
node: N.ImportFrom = N.ImportFrom(module=module, names=names, level=level)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParseImportAlias(self) -> N.alias:
|
||
"""解析单个 import 别名:name [as alias]。
|
||
|
||
alias 节点位置与 CPython 一致:起点为首个名称 token,
|
||
终点为 asname(存在时)或名称结束 token。
|
||
"""
|
||
name_tok: Token = self._ExpectName()
|
||
asname: str | None = None
|
||
end_tok: Token = name_tok
|
||
if self._AtName('as'):
|
||
self._Next()
|
||
as_tok: Token = self._ExpectName()
|
||
asname = as_tok.Value
|
||
end_tok = as_tok
|
||
alias: N.alias = N.alias(name=name_tok.Value, asname=asname)
|
||
self._FixLoc(alias, name_tok, end_tok)
|
||
return alias
|
||
|
||
def _ParseGlobal(self, kw: str) -> N.AST:
|
||
start: Token = self._Next()
|
||
names: list[str] = []
|
||
while True:
|
||
names.append(self._ExpectName().Value)
|
||
if self._AtOp(','):
|
||
self._Next()
|
||
continue
|
||
break
|
||
node: N.AST = N.Global(names=names) if kw == 'global' else N.Nonlocal(names=names)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParseDelete(self) -> N.Delete:
|
||
start: Token = self._Next() # 'del'
|
||
targets: list[N.expr] = []
|
||
while True:
|
||
expr: N.expr = self.ParseExpr()
|
||
self._SetDelContext(expr)
|
||
targets.append(expr)
|
||
if self._AtOp(','):
|
||
self._Next()
|
||
continue
|
||
break
|
||
node: N.Delete = N.Delete(targets=targets)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _SetDelContext(self, node: N.AST) -> None:
|
||
"""将 Load 上下文节点递归改为 Del(del 语句目标)。"""
|
||
if isinstance(node, N.Name):
|
||
node.ctx = N.Del()
|
||
elif isinstance(node, N.Attribute):
|
||
node.ctx = N.Del()
|
||
elif isinstance(node, N.Subscript):
|
||
node.ctx = N.Del()
|
||
elif isinstance(node, (N.Tuple, N.List)):
|
||
node.ctx = N.Del()
|
||
for elt in node.elts:
|
||
self._SetDelContext(elt)
|
||
|
||
def _ParseAssert(self) -> N.Assert:
|
||
start: Token = self._Next() # 'assert'
|
||
test: N.expr = self.ParseExpr()
|
||
msg: N.expr | None = None
|
||
if self._AtOp(','):
|
||
self._Next()
|
||
msg = self.ParseExpr()
|
||
node: N.Assert = N.Assert(test=test, msg=msg)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ConsumeSemicolons(self) -> None:
|
||
"""消费语句后的分号(允许空语句 ;;)。"""
|
||
while self._AtOp(';'):
|
||
self._Next()
|
||
|
||
# ------------------------------------------------------------------
|
||
# 表达式语句(含 yield)
|
||
# ------------------------------------------------------------------
|
||
def _ParseExprStmt(self) -> N.stmt:
|
||
start: Token = self._Peek()
|
||
# yield 语句:yield [expr_list]
|
||
if self._AtName('yield'):
|
||
expr: N.expr = self._ParseYield()
|
||
else:
|
||
expr = self.ParseExprList()
|
||
node: N.Expr = N.Expr(value=expr)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
# ==================================================================
|
||
# 装饰器
|
||
# ==================================================================
|
||
def _ParseDecorated(self) -> N.stmt:
|
||
"""解析装饰器列表 + def/class。"""
|
||
decorator_list: list[N.expr] = []
|
||
while self._AtOp('@'):
|
||
deco_start: Token = self._Next() # '@'
|
||
deco: N.expr = self.ParseExpr()
|
||
self._FixLoc(deco, deco_start)
|
||
decorator_list.append(deco)
|
||
self._ExpectNEWLINE()
|
||
self._SkipNEWLINE()
|
||
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 == 'static' and self._Peek(1).Type == NAME
|
||
and self._Peek(1).Value == 'def'):
|
||
return self._ParseStaticDef(decorators=decorator_list)
|
||
if tok.Type == NAME and tok.Value == 'define':
|
||
return self._ParseDefineDef(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':
|
||
nxt: Token = self._Peek(1)
|
||
if nxt.Type == NAME and nxt.Value == 'def':
|
||
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)
|
||
if tok.Type == NAME and tok.Value == _TLS_KEYWORD and self._IsTlsDefStart():
|
||
# `@deco` 与 `tls def` 组合:合成 @TLS 追加在既有装饰器之后
|
||
return self._ParseTlsModified(decorators=decorator_list)
|
||
raise SyntaxError(f"decorator must be followed by def/class, got {tok.Value!r}")
|
||
|
||
# ==================================================================
|
||
# virtual / novirtual 修饰符 + class/def
|
||
# ==================================================================
|
||
def _SourceLine(self, lineno: int) -> str:
|
||
"""取 lineno 行的源码文本(去掉行终止符),供 fail-fast 报文附源码片段。"""
|
||
starts: list[int] = self.LineStarts
|
||
if lineno < 1 or lineno > len(starts):
|
||
return ''
|
||
begin: int = starts[lineno - 1]
|
||
end: int = starts[lineno] if lineno < len(starts) else len(self.Source)
|
||
return self.Source[begin:end].rstrip('\n').rstrip('\r')
|
||
|
||
def _VirtualSyntaxError(self, detail: str, tok: Token, extra: str = '') -> SyntaxError:
|
||
"""构造 virtual/novirtual 修饰符非法形态的 fail-fast 报文。
|
||
|
||
报文含 行:列 + 源码片段 + 该修饰符允许出现的位置 + 正确示例;行尾另附
|
||
`at line N`(TPC 既有诊断路径按该正则兜底提取行号,见
|
||
HandlesImports._ParseFailureSite),文件名由调用方补全。
|
||
"""
|
||
return SyntaxError(
|
||
f"[TPC] virtual/novirtual 修饰符非法({detail}):行 {tok.Line} 列 {tok.Col},"
|
||
f"源码片段 {self._SourceLine(tok.Line).strip()!r}。"
|
||
f"{_VIRTUAL_POSITION_HINT}。正确示例:{_VIRTUAL_EXAMPLE}。"
|
||
+ (f" {extra}" if extra else '')
|
||
+ " (修饰符不会被静默忽略:非法形态一律终止编译)"
|
||
+ f" at line {tok.Line}"
|
||
)
|
||
|
||
def _ParseVirtualModified(self, decorators: list[N.expr] | None = None) -> N.stmt:
|
||
"""`virtual class` / `novirtual class` / `virtual def` / `novirtual def`。
|
||
|
||
合成 `@CVTable` / `@NoVTable` 装饰器后交给 _ParseClassDef /
|
||
_ParseFunctionDef,产出与**手写同名装饰器**逐字段同形的 AST
|
||
(decorator_list 多一个 Name('CVTable'|'NoVTable', Load)),
|
||
故下游(_resolve_class_flags / _should_method_be_virtual 同族判据)零新增分支。
|
||
|
||
非法形态**响亮失败**(不静默丢修饰符):
|
||
- 后随非 class/def;
|
||
- `virtual def` / `novirtual def` 不在类体内(模块级 / 函数体 / 分支体)。
|
||
"""
|
||
mod: Token = self._Peek() # virtual / novirtual
|
||
nxt: Token = self._Peek(1)
|
||
marker: str = _VIRTUAL_MARKERS[mod.Value]
|
||
# 后随必须是 class / def;def 的别名 fn/fun/func/function 同样接受
|
||
# (与 VPC 的 _is_funcdef_kw 口径一致)。注意:ExpandSoftKeywords 的
|
||
# fn→def 展开只命中**行首**的 fn,`virtual fn m()` 不会被先展开,
|
||
# 故此处必须显式接受别名(否则两端对同一源码一端报错一端通过)。
|
||
if nxt.Type != NAME or (nxt.Value != 'class'
|
||
and nxt.Value != 'def'
|
||
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 天然无虚表(解析期已合成 @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)"
|
||
f"之前生效;若此处本意是普通标识符名,"
|
||
f"请改名(该词在语句起始会被判为修饰符)。")
|
||
if nxt.Value == 'def' and not self._InClassBody:
|
||
raise self._VirtualSyntaxError(
|
||
f'{mod.Value} def 出现在类体之外', mod,
|
||
f'{mod.Value} def 描述的是「类体内方法的虚/非虚」,'
|
||
f'模块级 / 函数体 / 分支体内没有可归属的类。')
|
||
self._Next() # 消费修饰符
|
||
deco: N.expr = N.Name(id=marker, ctx=N.Load())
|
||
self._FixLoc(deco, mod)
|
||
deco_list: list[N.expr] = list(decorators or [])
|
||
deco_list.append(deco)
|
||
if nxt.Value == 'class':
|
||
return self._ParseClassDef(decorators=deco_list)
|
||
return self._ParseFunctionDef(decorators=deco_list)
|
||
|
||
# ==================================================================
|
||
# tls 修饰符 + def
|
||
# ==================================================================
|
||
def _IsTlsDefStart(self) -> bool:
|
||
"""下一个 token 是否为 `tls` 修饰符后的函数定义起点(def / 其别名 + '(' / '[')。"""
|
||
nxt: Token = self._Peek(1)
|
||
if nxt.Type != NAME:
|
||
return False
|
||
if nxt.Value == 'def':
|
||
return True
|
||
if nxt.Value in _DEF_ALIASES:
|
||
nxt2: Token = self._Peek(2)
|
||
return nxt2.Type == OP and nxt2.Value in ('(', '[')
|
||
return False
|
||
|
||
def _ParseTlsModified(self, decorators: list[N.expr] | None = None) -> N.stmt:
|
||
"""`tls def f(...)`:消费 tls,合成 `@TLS` 后交给 _ParseFunctionDef。
|
||
|
||
与手写 `@TLS` 逐字段同形(decorator_list 追加
|
||
Name('TLS', Load)),故下游一次性初始化的守卫生成路径
|
||
(HandlesFunctions 的 TLS 分支)零新增判据。tls 对方法与模块级函数同样生效。
|
||
"""
|
||
mod: Token = self._Peek() # tls
|
||
self._Next() # 消费修饰符
|
||
deco: N.expr = N.Name(id='TLS', ctx=N.Load())
|
||
self._FixLoc(deco, mod)
|
||
deco_list: list[N.expr] = list(decorators or [])
|
||
deco_list.append(deco)
|
||
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 天然无虚表,已内置 @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):` → 与 `@NoVTable class X(CStruct):`
|
||
逐字段同形的 ClassDef(与 VPC 的 _parse_structdef 同口径)。
|
||
|
||
实现:复用 _ParseClassDef 的完整解析路径(类型参数 / 基类 / 关键字实参 /
|
||
类体套件),只在**解析前后**补三件事:
|
||
· 解析前把合成的 `@NoVTable` 追加进装饰器列表(与 virtual/novirtual
|
||
同款表示)⇒ 类级强制无虚表,即使父类带虚表;
|
||
· 解析后把 `CStruct` 标记基类**追加**到 bases 末尾(不提位用户基类,
|
||
真实父类解析顺序不变)⇒ 数据类语义(_MARKER_BASES 认它,不当真实父类);
|
||
· 解析后校验类体**直接子节点**里没有 def —— struct 只能表示数据类型。
|
||
_ParseClassDef 的首个 `_Next()` 消费的正是 `struct` 关键字本身,故本函数
|
||
不预先消费,行号/列号与写法均继承自该 token。
|
||
"""
|
||
start: Token = self._Peek() # struct(由 _ParseClassDef 的 _Next() 消费)
|
||
deco: N.expr = N.Name(id='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.Name(id='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)
|
||
# ==================================================================
|
||
def _ParseFunctionDef(self, is_async: bool = False,
|
||
decorators: list[N.expr] | None = None) -> N.FunctionDef:
|
||
start: Token = self._Next() # def/fn/...(或 async)
|
||
if start.Value == 'async':
|
||
start = self._Next() # def
|
||
name_tok: Token = self._ExpectName()
|
||
# 类型参数(PEP 695):def f[T](
|
||
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._ParseTypeAnnotation()
|
||
self._ExpectOp(':')
|
||
body: list[N.stmt] = self._ParseSuite()
|
||
cls: type = N.AsyncFunctionDef if is_async else N.FunctionDef
|
||
node: N.FunctionDef = cls(
|
||
name=name_tok.Value, args=args, body=body,
|
||
decorator_list=decorators or [], returns=returns,
|
||
type_comment=None, type_params=type_params,
|
||
)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParseExternDef(self, decorators: list[N.expr] | None = None) -> N.FunctionDef:
|
||
"""解析 extern 函数声明(FFI,仅声明不定义)。
|
||
|
||
允许语法(均声明不定义,不生成函数体):
|
||
extern def A(x: int) -> int: pass
|
||
extern A(x: int) -> int: pass
|
||
extern def A(x: int) -> int
|
||
extern A(x: int) -> int
|
||
|
||
产出标准 FunctionDef 节点,``Extern = True`` 供 Unparser 还原 extern 语法;
|
||
返回注解保持源码原样(不追加 `| State`)。
|
||
"""
|
||
start: Token = self._Next() # 'extern'
|
||
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._ParseTypeAnnotation()
|
||
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.Extern = True
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParseExportDef(self, decorators: list[N.expr] | None = None) -> N.FunctionDef:
|
||
"""解析 export 函数声明(等价 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 节点,``Export = True`` 供 Unparser 还原 export 语法;
|
||
返回注解保持源码原样(不追加 `| CExport`)。
|
||
"""
|
||
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._ParseTypeAnnotation()
|
||
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
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParseStaticDef(self, decorators: list[N.expr] | None = None) -> N.FunctionDef:
|
||
"""解析 static 函数定义(等价 ``@CStatic``,与 ViperC 的
|
||
`_ParseStaticModified` 同源)。
|
||
|
||
允许语法(与 export/extern 对称,配不配 def 都一样):
|
||
static def A(x: int) -> int: ...
|
||
static A(x: int) -> int: ...
|
||
|
||
与 export/extern 的**两处不同**:
|
||
- **不改写返回注解**(不追加 `| CStatic` / `| State`):CStatic 是
|
||
函数属性,由下面的合成装饰器承载,返回类型语义逐字不变;
|
||
- **合成 `@CStatic` 装饰器**追加在既有装饰器之后,产出与**手写
|
||
`@CStatic`** 逐字段同形(decorator_list 多一个
|
||
Name('CStatic', Load)),下游零新增判据。
|
||
|
||
另设自定义属性 ``Static = True`` 供 Unparser 还原 static 语法
|
||
(镜像 Extern/Export;因 FunctionDef 的 __slots__ 槽位未含 Static 且
|
||
补槽位需改第三个文件,此处仅在槽位存在时设置,解析不会因此中断)。
|
||
"""
|
||
start: Token = self._Next() # 'static'
|
||
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._ParseTypeAnnotation()
|
||
body: list[N.stmt] = []
|
||
if self._AtOp(':'):
|
||
self._Next()
|
||
body = self._ParseSuite()
|
||
# 合成 @CStatic 装饰器(追加在既有装饰器之后)
|
||
static_attr: N.expr = N.Name(id='CStatic', ctx=N.Load())
|
||
self._FixLoc(static_attr, start)
|
||
deco_list: list[N.expr] = list(decorators or [])
|
||
deco_list.append(static_attr)
|
||
node: N.FunctionDef = N.FunctionDef(
|
||
name=name_tok.Value, args=args, body=body,
|
||
decorator_list=deco_list, returns=returns,
|
||
type_comment=None, type_params=type_params,
|
||
)
|
||
# 自定义属性 Static = True 供 Unparser 还原 static 语法(镜像 Extern/Export)。
|
||
# 注:FunctionDef 是 __slots__ 类(见 vast/Nodes.py 的 _FUNC_ATTRS,当前槽位
|
||
# 为 Extern/Export/Define,未含 Static)——补槽位需改第三个文件(本次不许可),
|
||
# 故仅在槽位存在时设置,避免 AttributeError 中断解析;下游对 static 函数的
|
||
# 识别靠上面合成的 @CStatic 装饰器(HandlesFunctions 的存储类装饰器分支),
|
||
# 与 virtual/novirtual 仅合成装饰器同构。
|
||
if hasattr(type(node), 'Static'):
|
||
node.Static = True
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParseDefineDef(self, decorators: list[N.expr] | None = None) -> N.FunctionDef:
|
||
"""解析 define 宏函数定义(语法与 def 完全一致,但固定为宏函数)。
|
||
|
||
允许语法(与 def 相同,函数体必填):
|
||
define A(x: int) -> int: ...
|
||
define A(x: int): ...
|
||
|
||
产出标准 FunctionDef 节点,``Define = True`` 供 Unparser 还原 define 语法;
|
||
返回注解保持源码原样(不追加 `| CDefine`)。
|
||
"""
|
||
start: Token = self._Next() # 'define'
|
||
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._ParseTypeAnnotation()
|
||
self._ExpectOp(':')
|
||
body: list[N.stmt] = 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.Define = True
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParseTypeParams(self) -> list[N.AST]:
|
||
"""解析 PEP 695 类型参数:[T, *Ts, **P, U: Bound]"""
|
||
self._ExpectOp('[')
|
||
self._SkipNL()
|
||
params: list[N.AST] = []
|
||
if not self._AtOp(']'):
|
||
while True:
|
||
self._SkipNL()
|
||
star: int = 0
|
||
if self._AtOp('*'):
|
||
self._Next()
|
||
star = 1
|
||
elif self._AtOp('**'):
|
||
self._Next()
|
||
star = 2
|
||
name_tok: Token = self._ExpectName()
|
||
bound: N.expr | None = None
|
||
if star == 0 and self._AtOp(':'):
|
||
self._Next()
|
||
bound = self.ParseExpr()
|
||
if star == 1:
|
||
tvt: N.TypeVarTuple = N.TypeVarTuple(name=name_tok.Value)
|
||
self._FixLoc(tvt, name_tok)
|
||
params.append(tvt)
|
||
elif star == 2:
|
||
ps: N.ParamSpec = N.ParamSpec(name=name_tok.Value)
|
||
self._FixLoc(ps, name_tok)
|
||
params.append(ps)
|
||
else:
|
||
tv: N.TypeVar = N.TypeVar(name=name_tok.Value, bound=bound)
|
||
self._FixLoc(tv, name_tok)
|
||
params.append(tv)
|
||
self._SkipNL()
|
||
if self._AtOp(','):
|
||
self._Next()
|
||
continue
|
||
break
|
||
self._ExpectOp(']')
|
||
return params
|
||
|
||
# ==================================================================
|
||
# 类定义
|
||
# ==================================================================
|
||
def _ParseClassDef(self, decorators: list[N.expr] | None = None) -> N.ClassDef:
|
||
start: Token = self._Next() # class
|
||
name_tok: Token = self._ExpectName()
|
||
type_params: list[N.AST] = []
|
||
if self._AtOp('['):
|
||
type_params = self._ParseTypeParams()
|
||
bases: list[N.expr] = []
|
||
keywords: list[N.keyword] = []
|
||
if self._AtOp('('):
|
||
self._Next()
|
||
self._SkipNL()
|
||
if not self._AtOp(')'):
|
||
while True:
|
||
self._SkipNL()
|
||
if self._AtOp('**'):
|
||
self._Next()
|
||
value: N.expr = self.ParseExpr()
|
||
kw: N.keyword = N.keyword(arg=None, value=value)
|
||
self._FixLoc(kw, self._Prev())
|
||
keywords.append(kw)
|
||
elif self._At(NAME) and self._Peek(1).Type == OP and self._Peek(1).Value == '=':
|
||
arg_tok: Token = self._Next()
|
||
self._Next() # '='
|
||
value = self.ParseExpr()
|
||
kw = N.keyword(arg=arg_tok.Value, value=value)
|
||
self._FixLoc(kw, arg_tok)
|
||
keywords.append(kw)
|
||
else:
|
||
bases.append(self.ParseExpr())
|
||
self._SkipNL()
|
||
if self._AtOp(','):
|
||
self._Next()
|
||
self._SkipNL()
|
||
if self._AtOp(')'):
|
||
break
|
||
continue
|
||
break
|
||
self._ExpectOp(')')
|
||
self._ExpectOp(':')
|
||
body: list[N.stmt] = self._ParseSuite(owner_is_class=True)
|
||
node: N.ClassDef = N.ClassDef(
|
||
name=name_tok.Value, bases=bases, keywords=keywords, body=body,
|
||
decorator_list=decorators or [], type_params=type_params,
|
||
)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
# ==================================================================
|
||
# 语句块(套件)
|
||
# ==================================================================
|
||
def _ParseSuite(self, owner_is_class: bool = False) -> list[N.stmt]:
|
||
"""解析语句块:':' NEWLINE INDENT ... DEDENT 或单行简单语句。
|
||
|
||
块首允许出现空行/注释行(NL),跳过后再检测 INDENT。
|
||
|
||
owner_is_class:本套件的**直接拥有者**是否 ClassDef。套件解析期间置
|
||
`_InClassBody`,供 `_ParseVirtualModified` 判 `virtual def`/`novirtual def`
|
||
是否"直接写在类体内"(函数体 / 分支体 / 循环体都不算)。默认 False ⇒
|
||
除类体外的所有套件拥有者天然正确,无需逐个改动。
|
||
"""
|
||
prev_in_class: bool = self._InClassBody
|
||
self._InClassBody = owner_is_class
|
||
# 已消费 ':' 后的情况:检查是否换行
|
||
if self._At(NEWLINE):
|
||
self._Next()
|
||
# 跳过空行/注释行
|
||
while self._At(NL):
|
||
self._Next()
|
||
if self._At(INDENT):
|
||
self._Next()
|
||
body: list[N.stmt] = []
|
||
self._SkipNEWLINE()
|
||
while self._Peek().Type != DEDENT and self._Peek().Type != ENDMARKER:
|
||
stmt: N.stmt = self.ParseStatement()
|
||
body.append(stmt)
|
||
# 分号分隔后续语句
|
||
while self._AtOp(';'):
|
||
self._Next()
|
||
if self._At(NEWLINE):
|
||
break
|
||
extra: N.stmt = self.ParseStatement()
|
||
body.append(extra)
|
||
self._SkipNEWLINE()
|
||
self._Expect(DEDENT)
|
||
self._InClassBody = prev_in_class
|
||
return body
|
||
# 空套件(语法错误,宽松返回空)
|
||
self._InClassBody = prev_in_class
|
||
return []
|
||
# 单行套件:statement (; statement)* NEWLINE
|
||
body = [self.ParseStatement()]
|
||
while self._AtOp(';'):
|
||
self._Next()
|
||
if self._At(NEWLINE):
|
||
break
|
||
body.append(self.ParseStatement())
|
||
self._ExpectNEWLINE()
|
||
# 吞掉紧跟在单行套件之后的注释行/空行 NL:多行套件分支在 DEDENT 之前
|
||
# 已由循环内 _SkipNEWLINE 吞掉这些 NL,单行套件没有 DEDENT,若不在此吞掉,
|
||
# 调用方紧随其后的 elif/else/except/finally 续接子句会被 NL 挡住 → 分支链断裂。
|
||
self._SkipNL()
|
||
self._InClassBody = prev_in_class
|
||
return body
|
||
|
||
def _Expect(self, tok_type: str, value: str | None = None) -> Token:
|
||
"""期望指定类型的 token。"""
|
||
tok: Token = self._Next()
|
||
if tok.Type != tok_type or (value is not None and tok.Value != value):
|
||
raise SyntaxError(
|
||
f"expected {tok_type}({value!r}), got {tok.Type}({tok.Value!r}) "
|
||
f"at line {tok.Line}"
|
||
)
|
||
return tok
|
||
|
||
def _ConsumeNewlines(self) -> None:
|
||
"""消费连续 NEWLINE(空行)。"""
|
||
while self._At(NEWLINE):
|
||
self._Next()
|
||
|
||
# ==================================================================
|
||
# if / while / for / try / with / match
|
||
# ==================================================================
|
||
def _ParseIf(self) -> N.If:
|
||
start: Token = self._Next() # if
|
||
test: N.expr = self.ParseExpr()
|
||
self._ExpectOp(':')
|
||
body: list[N.stmt] = self._ParseSuite()
|
||
orelse: list[N.stmt] = []
|
||
if self._AtName('elif'):
|
||
# elif → 嵌套 If 于 orelse
|
||
orelse.append(self._ParseIf())
|
||
elif self._AtName('else'):
|
||
self._Next()
|
||
self._ExpectOp(':')
|
||
orelse = self._ParseSuite()
|
||
node: N.If = N.If(test=test, body=body, orelse=orelse)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
# ==================================================================
|
||
# cif / celif / celse 编译期条件编译(软关键字,desugar 到 CIf 标记)
|
||
# ==================================================================
|
||
def _IsCIfStatementStart(self) -> bool:
|
||
"""语句起始 NAME('cif') 是否按 cif 语句解析。
|
||
|
||
排除赋值/注解形态(`cif = 5` / `cif: int = 5` / `cif += 1`):
|
||
第二种 token 为 '=' ':' 或增强赋值运算符时按普通语句处理。
|
||
"""
|
||
nxt: Token = self._Peek(1)
|
||
if nxt.Type == OP and nxt.Value in _CIF_NON_STATEMENT_OPS:
|
||
return False
|
||
return True
|
||
|
||
def _MakeCIfMarkerCall(self, attr: str, expr: N.expr, start: Token) -> N.Call:
|
||
"""构造内部标记调用 `<attr>(expr)`(用户不可写;cif/defined 的 desugar)。"""
|
||
func: N.Name = N.Name(id=attr, ctx=N.Load())
|
||
self._FixLoc(func, start)
|
||
call: N.Call = N.Call(func=func, args=[expr], keywords=[])
|
||
self._FixLoc(call, start)
|
||
return call
|
||
|
||
def _ParseCIf(self) -> N.If:
|
||
"""`cif <expr>:`(+ 可选 celif/celse 链)。"""
|
||
start: Token = self._Next() # cif
|
||
test: N.expr = self._ParseCIfCondition()
|
||
self._ExpectOp(':')
|
||
body: list[N.stmt] = self._ParseSuite()
|
||
orelse: list[N.stmt] = self._ParseCIfChainTail()
|
||
node: N.If = N.If(test=self._MakeCIfMarkerCall(_CIF_MARKER, test, start),
|
||
body=body, orelse=orelse)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParseCIfCondition(self) -> N.expr:
|
||
"""解析 cif/celif 条件表达式,期间允许 `defined(NAME)` 谓词。"""
|
||
prev: bool = self._InCIfCond
|
||
self._InCIfCond = True
|
||
try:
|
||
return self.ParseExpr()
|
||
finally:
|
||
self._InCIfCond = prev
|
||
|
||
def _ParseCIfChainTail(self) -> list[N.stmt]:
|
||
"""解析 cif 链尾部(celif/celse),返回 orelse 列表。
|
||
|
||
- 无 celif/celse:返回空(cif 链正常收尾)。
|
||
- 出现普通 elif/else:FailFast(cif 链必须以 celse 收尾)。
|
||
"""
|
||
if self._AtName(_CELIF_KEYWORD):
|
||
return [self._ParseCelif()]
|
||
if self._AtName(_CELSE_KEYWORD):
|
||
self._Next() # celse
|
||
self._ExpectOp(':')
|
||
body: list[N.stmt] = self._ParseSuite()
|
||
# celse 之后不得再出现 celif / celse(同缩进层级会落在本方法可见处)。
|
||
if self._AtName(_CELIF_KEYWORD) or self._AtName(_CELSE_KEYWORD):
|
||
bad_tok: Token = self._Peek()
|
||
raise SyntaxError(
|
||
f"'{bad_tok.Value}' cannot follow 'celse' (the 'celse' branch must be "
|
||
f"the last of the 'cif' chain) at line {bad_tok.Line}")
|
||
return body
|
||
if self._AtName('elif') or self._AtName('else'):
|
||
kind: str = self._Peek().Value
|
||
raise SyntaxError(
|
||
f"a 'cif' chain must be closed with 'celse', not '{kind}', "
|
||
f"at line {self._Peek().Line}")
|
||
return []
|
||
|
||
def _ParseCelif(self) -> N.If:
|
||
"""`celif <expr>:`(cif 链的后续分支)。"""
|
||
start: Token = self._Next() # celif
|
||
test: N.expr = self._ParseCIfCondition()
|
||
self._ExpectOp(':')
|
||
body: list[N.stmt] = self._ParseSuite()
|
||
orelse: list[N.stmt] = self._ParseCIfChainTail()
|
||
node: N.If = N.If(test=self._MakeCIfMarkerCall(_CIF_MARKER, test, start),
|
||
body=body, orelse=orelse)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParseWhile(self) -> N.While:
|
||
start: Token = self._Next() # while
|
||
test: N.expr = self.ParseExpr()
|
||
self._ExpectOp(':')
|
||
body: list[N.stmt] = self._ParseSuite()
|
||
orelse: list[N.stmt] = []
|
||
if self._AtName('else'):
|
||
self._Next()
|
||
self._ExpectOp(':')
|
||
orelse = self._ParseSuite()
|
||
node: N.While = N.While(test=test, body=body, orelse=orelse)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParseFor(self, is_async: bool = False) -> N.For:
|
||
start: Token = self._Next()
|
||
if start.Value == 'async':
|
||
start = self._Next() # for
|
||
target: N.expr = self._ParseTargetList()
|
||
self._ExpectName('in')
|
||
iterable: N.expr = self.ParseExpr()
|
||
self._ExpectOp(':')
|
||
body: list[N.stmt] = self._ParseSuite()
|
||
orelse: list[N.stmt] = []
|
||
if self._AtName('else'):
|
||
self._Next()
|
||
self._ExpectOp(':')
|
||
orelse = self._ParseSuite()
|
||
cls: type = N.AsyncFor if is_async else N.For
|
||
node: N.For = cls(target=target, iter=iterable, body=body, orelse=orelse,
|
||
type_comment=None)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParseTargetList(self) -> N.expr:
|
||
"""解析 for 目标列表(支持裸元组 a, b = ...)。"""
|
||
start: Token = self._Peek()
|
||
first: N.expr = self._ParseTarget()
|
||
if self._AtOp(','):
|
||
elts: list[N.expr] = [first]
|
||
while self._AtOp(','):
|
||
self._Next()
|
||
self._SkipNL()
|
||
elts.append(self._ParseTarget())
|
||
tup: N.Tuple = N.Tuple(elts=elts, ctx=N.Store())
|
||
self._FixLoc(tup, start)
|
||
return tup
|
||
return first
|
||
|
||
def _ParseTry(self) -> N.Try:
|
||
start: Token = self._Next() # try
|
||
self._ExpectOp(':')
|
||
body: list[N.stmt] = self._ParseSuite()
|
||
handlers: list[N.ExceptHandler] = []
|
||
orelse: list[N.stmt] = []
|
||
finalbody: list[N.stmt] = []
|
||
is_star: bool = False
|
||
while self._AtName('except'):
|
||
self._Next()
|
||
if self._AtOp('*'):
|
||
is_star = True
|
||
self._Next()
|
||
handlers.append(self._ParseExceptHandler())
|
||
if self._AtName('else'):
|
||
self._Next()
|
||
self._ExpectOp(':')
|
||
orelse = self._ParseSuite()
|
||
if self._AtName('finally'):
|
||
self._Next()
|
||
self._ExpectOp(':')
|
||
finalbody = self._ParseSuite()
|
||
cls: type = N.TryStar if is_star else N.Try
|
||
node: N.Try = cls(body=body, handlers=handlers, orelse=orelse, finalbody=finalbody)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParseExceptHandler(self) -> N.ExceptHandler:
|
||
start: Token = self._Peek()
|
||
exc_type: N.expr | None = None
|
||
name: str | None = None
|
||
if not self._AtOp(':'):
|
||
exc_type = self.ParseExpr()
|
||
if self._AtName('as'):
|
||
self._Next()
|
||
name = self._ExpectName().Value
|
||
self._ExpectOp(':')
|
||
handler_body: list[N.stmt] = self._ParseSuite()
|
||
node: N.ExceptHandler = N.ExceptHandler(type=exc_type, name=name, body=handler_body)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParseWith(self, is_async: bool = False) -> N.With:
|
||
start: Token = self._Next()
|
||
if start.Value == 'async':
|
||
start = self._Next() # with
|
||
items: list[N.withitem] = []
|
||
while True:
|
||
ctx: N.expr = self.ParseExpr()
|
||
optional_vars: N.expr | None = None
|
||
if self._AtName('as'):
|
||
self._Next()
|
||
optional_vars = self._ParseTarget()
|
||
item: N.withitem = N.withitem(context_expr=ctx, optional_vars=optional_vars)
|
||
self._FixLoc(item, start)
|
||
items.append(item)
|
||
if self._AtOp(','):
|
||
self._Next()
|
||
continue
|
||
break
|
||
self._ExpectOp(':')
|
||
body: list[N.stmt] = self._ParseSuite()
|
||
cls: type = N.AsyncWith if is_async else N.With
|
||
node: N.With = cls(items=items, body=body, type_comment=None)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
# ==================================================================
|
||
# match 语句(PEP 634)与 switch 语句(C switch 语义)
|
||
# ==================================================================
|
||
def _ParseMatch(self) -> N.Match:
|
||
start: Token = self._Next() # match
|
||
subject: N.expr = self.ParseExpr()
|
||
self._ExpectOp(':')
|
||
self._ExpectNEWLINE()
|
||
self._Expect(INDENT)
|
||
cases: list[N.match_case] = []
|
||
self._SkipNEWLINE()
|
||
while self._AtName('case'):
|
||
case_start: Token = self._Next() # case
|
||
pattern: N.pattern = self._ParsePattern()
|
||
guard: N.expr | None = None
|
||
if self._AtName('if'):
|
||
self._Next()
|
||
guard = self.ParseExpr()
|
||
self._ExpectOp(':')
|
||
case_body: list[N.stmt] = self._ParseSuite()
|
||
mc: N.match_case = N.match_case(pattern=pattern, guard=guard, body=case_body)
|
||
self._FixLoc(mc, case_start)
|
||
cases.append(mc)
|
||
self._SkipNEWLINE()
|
||
self._Expect(DEDENT)
|
||
node: N.Match = N.Match(subject=subject, cases=cases, is_switch=False)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParseSwitch(self) -> N.Match:
|
||
"""switch 语句(C switch 语义):脱糖为 is_switch=True 的 N.Match。
|
||
|
||
switch <expr>:
|
||
case <常量 | 枚举变体>: # 可 `case 1 | 2:` 多值
|
||
...
|
||
default:
|
||
...
|
||
|
||
- case 默认不穿透,case 体内写 `fallthrough` 才落到下一个 case;
|
||
- case 标签只支持常量字面量 / 枚举变体 / 多值或模式,不接受序列、
|
||
映射、捕获等结构化模式;不支持 if 守卫。
|
||
"""
|
||
start: Token = self._Next() # switch
|
||
subject: N.expr = self.ParseExpr()
|
||
self._ExpectOp(':')
|
||
self._ExpectNEWLINE()
|
||
self._Expect(INDENT)
|
||
cases: list[N.match_case] = []
|
||
self._SkipNEWLINE()
|
||
while True:
|
||
if self._AtName('case'):
|
||
case_start: Token = self._Next() # case
|
||
pattern: N.pattern = self._ParsePattern()
|
||
pattern = self._SwitchLabelFromPattern(pattern)
|
||
self._CheckSwitchCasePattern(pattern)
|
||
if self._AtName('if'):
|
||
raise SyntaxError("switch 的 case 不支持 if 守卫")
|
||
self._ExpectOp(':')
|
||
case_body: list[N.stmt] = self._ParseSuite()
|
||
mc: N.match_case = N.match_case(pattern=pattern, guard=None, body=case_body)
|
||
self._FixLoc(mc, case_start)
|
||
cases.append(mc)
|
||
elif self._AtName('default') and self._PeekIsOp(':'):
|
||
def_start: Token = self._Next() # default
|
||
self._ExpectOp(':')
|
||
body: list[N.stmt] = self._ParseSuite()
|
||
# default: 等价 `case _`(MatchAs 通配)
|
||
wild: N.pattern = N.MatchAs(pattern=None, name=None)
|
||
self._FixLoc(wild, def_start)
|
||
mc = N.match_case(pattern=wild, guard=None, body=body)
|
||
self._FixLoc(mc, def_start)
|
||
cases.append(mc)
|
||
else:
|
||
break
|
||
self._SkipNEWLINE()
|
||
self._Expect(DEDENT)
|
||
node: N.Match = N.Match(subject=subject, cases=cases, is_switch=True)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
@staticmethod
|
||
def _SwitchLabelFromPattern(Pattern: N.pattern) -> N.pattern:
|
||
"""switch 的 case 标签修正:裸名按**值引用**处理
|
||
|
||
match 里裸名是捕获模式(`MatchAs(pattern=None, name=X)`),switch 里应对齐
|
||
C 的 `case NAME:` 语义 —— 归一为 `MatchValue(Name('X'))`;`_` 仍是通配符
|
||
(留作 MatchAs 通配,等价 `default:`)。
|
||
"""
|
||
if isinstance(Pattern, N.MatchAs) and Pattern.pattern is None and Pattern.name is not None:
|
||
Ref: N.Name = N.Name(id=Pattern.name, ctx=N.Load())
|
||
Val: N.MatchValue = N.MatchValue(value=Ref)
|
||
Val.lineno = Pattern.lineno
|
||
Val.col_offset = Pattern.col_offset
|
||
Val.end_lineno = Pattern.end_lineno
|
||
Val.end_col_offset = Pattern.end_col_offset
|
||
return Val
|
||
return Pattern
|
||
|
||
def _PeekIsOp(self, value: str) -> bool:
|
||
"""下一个 token 是否为运算符 `value`(不消费)"""
|
||
nxt: Token = self._Peek(1)
|
||
return nxt.Type == OP and nxt.Value == value
|
||
|
||
def _CheckSwitchCasePattern(self, pattern: N.pattern) -> None:
|
||
"""校验 switch 的 case 标签:只允许常量 / 枚举变体 / 多值或模式。
|
||
|
||
与其他语法错误一致地 fail-fast(SyntaxError 向上冒泡终止编译),
|
||
绝不静默接受结构化模式。
|
||
"""
|
||
def _IsAllowed(p: N.pattern) -> bool:
|
||
if isinstance(p, (N.MatchValue, N.MatchSingleton, N.MatchClass)):
|
||
return True
|
||
# 通配 `case _`(MatchAs 无子模式)等价 default
|
||
if isinstance(p, N.MatchAs):
|
||
return p.pattern is None
|
||
if isinstance(p, N.MatchOr):
|
||
return len(p.patterns) > 0 and all(_IsAllowed(x) for x in p.patterns)
|
||
return False
|
||
if not _IsAllowed(pattern):
|
||
raise SyntaxError(
|
||
"switch 的 case 标签非法:只支持常量字面量或枚举变体"
|
||
"(可多值 `case 1 | 2:`),不接受序列/映射/捕获等结构化模式。"
|
||
"正确示例:case 1: / case \"a\": / case Color.Red: / case Opt.Some():")
|
||
|
||
def _ParsePattern(self) -> N.pattern:
|
||
"""解析 match 模式(顶层,处理 | 或模式)。"""
|
||
start: Token = self._Peek()
|
||
patterns: list[N.pattern] = [self._ParsePatternOr()]
|
||
while self._AtOp('|'):
|
||
self._Next()
|
||
patterns.append(self._ParsePatternOr())
|
||
if len(patterns) == 1:
|
||
return patterns[0]
|
||
node: N.MatchOr = N.MatchOr(patterns=patterns)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParsePatternOr(self) -> N.pattern:
|
||
"""解析单模式(含 as 绑定)。"""
|
||
start: Token = self._Peek()
|
||
pat: N.pattern = self._ParsePatternAtom()
|
||
if self._AtName('as'):
|
||
self._Next()
|
||
name: str = self._ExpectName().Value
|
||
node: N.MatchAs = N.MatchAs(pattern=pat, name=name)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
return pat
|
||
|
||
def _ParsePatternAtom(self) -> N.pattern:
|
||
"""解析模式原子:字面量/捕获/序列/映射/类/通配符。"""
|
||
start: Token = self._Peek()
|
||
tok: Token = self._Peek()
|
||
# 通配符 / 捕获
|
||
if tok.Type == NAME:
|
||
# 字面量 True/False/None
|
||
if tok.Value in ('True', 'False', 'None'):
|
||
self._Next()
|
||
node: N.MatchSingleton = N.MatchSingleton(
|
||
value={'True': True, 'False': False, 'None': None}[tok.Value])
|
||
self._FixLoc(node, tok)
|
||
return node
|
||
# 类模式:Name(...) 或 a.b.c(...)——扫描属性链末尾判断 '('
|
||
peek_i: int = 1
|
||
while (self._Peek(peek_i).Type == OP and self._Peek(peek_i).Value == '.'
|
||
and self._Peek(peek_i + 1).Type == NAME):
|
||
peek_i += 2
|
||
if self._Peek(peek_i).Type == OP and self._Peek(peek_i).Value == '(':
|
||
return self._ParseMatchClass()
|
||
# 属性值模式 a.b(无括号)
|
||
if self._Peek(1).Type == OP and self._Peek(1).Value == '.':
|
||
return self._ParseMatchValueAttr()
|
||
# 捕获模式(含 _ 通配符;_ 产生空 MatchAs 与 CPython 一致)
|
||
self._Next()
|
||
node = N.MatchAs(pattern=None, name=None if tok.Value == '_' else tok.Value)
|
||
self._FixLoc(node, tok)
|
||
return node
|
||
# 序列模式 [a, b] / (a, b)
|
||
if tok.Type == OP and tok.Value in ('[', '('):
|
||
return self._ParseMatchSequence()
|
||
# 映射模式 {k: v, **rest}
|
||
if tok.Type == OP and tok.Value == '{':
|
||
return self._ParseMatchMapping()
|
||
# 值模式:数字/字符串/f-string/带符号字面量(不消费顶层 '|',留给 _ParsePattern 组 MatchOr)
|
||
if tok.Type == NUMBER or tok.Type == STRING or tok.Type == FSTRING or (
|
||
tok.Type == OP and tok.Value in ('-', '+')):
|
||
value: N.expr = self._ParsePatternValue()
|
||
node = N.MatchValue(value=value)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
if tok.Type == OP and tok.Value == '*':
|
||
self._Next()
|
||
name = None
|
||
if not self._At(NEWLINE) and not self._AtOp(','):
|
||
name = self._ExpectName().Value
|
||
node = N.MatchStar(name=name)
|
||
self._FixLoc(node, tok)
|
||
return node
|
||
raise SyntaxError(f"unexpected pattern token {tok.Type}({tok.Value!r})")
|
||
|
||
def _ParsePatternValue(self) -> N.expr:
|
||
"""解析值模式表达式:带可选 +/- 前缀的字面量。
|
||
|
||
与 CPython 一致:'|' 是模式或分隔符,这里只解析单个字面量
|
||
(数字/字符串/f-string),不消费顶层 '|'。
|
||
"""
|
||
start: Token = self._Peek()
|
||
tok: Token = self._Peek()
|
||
if tok.Type == OP and tok.Value in ('-', '+'):
|
||
op_tok: Token = self._Next()
|
||
inner: N.expr
|
||
if self._Peek().Type == NUMBER:
|
||
inner = self._ParseNumber()
|
||
elif self._Peek().Type in (STRING, FSTRING):
|
||
inner = self._ParseStringConcat()
|
||
else:
|
||
raise SyntaxError(
|
||
f"expected literal after '{op_tok.Value}' in pattern at line {op_tok.Line}"
|
||
)
|
||
node: N.expr
|
||
if op_tok.Value == '-':
|
||
node = N.UnaryOp(op=N.USub(), operand=inner)
|
||
else:
|
||
node = N.UnaryOp(op=N.UAdd(), operand=inner)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
if tok.Type == NUMBER:
|
||
return self._ParseNumber()
|
||
return self._ParseStringConcat()
|
||
|
||
def _ParseMatchValueAttr(self) -> N.pattern:
|
||
"""解析值模式属性访问:a.b.c(无括号)。"""
|
||
start: Token = self._Peek()
|
||
expr: N.expr = self.ParseExpr()
|
||
node: N.MatchValue = N.MatchValue(value=expr)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParseMatchClass(self) -> N.pattern:
|
||
"""解析类模式:Name(pos, kw=v, ...) 或 a.b.c(...)。
|
||
|
||
类名仅解析 Name/Attribute 链(不消费调用括号),括号由本方法消费。
|
||
"""
|
||
start: Token = self._Peek()
|
||
cls_name: N.expr = self._ParsePatternClassName()
|
||
self._ExpectOp('(')
|
||
self._SkipNL()
|
||
patterns: list[N.pattern] = []
|
||
kwd_attrs: list[str] = []
|
||
kwd_patterns: list[N.pattern] = []
|
||
if not self._AtOp(')'):
|
||
while True:
|
||
self._SkipNL()
|
||
if self._AtOp('*'):
|
||
self._Next()
|
||
patterns.append(self._ParsePattern())
|
||
elif self._At(NAME) and self._Peek(1).Type == OP and self._Peek(1).Value == '=':
|
||
attr_tok: Token = self._Next()
|
||
self._Next() # '='
|
||
kwd_attrs.append(attr_tok.Value)
|
||
kwd_patterns.append(self._ParsePattern())
|
||
else:
|
||
patterns.append(self._ParsePattern())
|
||
self._SkipNL()
|
||
if self._AtOp(','):
|
||
self._Next()
|
||
if self._AtOp(')'):
|
||
break
|
||
continue
|
||
break
|
||
self._ExpectOp(')')
|
||
node: N.MatchClass = N.MatchClass(cls=cls_name, patterns=patterns,
|
||
kwd_attrs=kwd_attrs, kwd_patterns=kwd_patterns)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParsePatternClassName(self) -> N.expr:
|
||
"""解析类模式的类名(Name / a.b.c 属性链,不含调用括号)。"""
|
||
start: Token = self._Peek()
|
||
name_tok: Token = self._ExpectName()
|
||
node: N.expr = N.Name(id=name_tok.Value, ctx=N.Load())
|
||
self._FixLoc(node, name_tok)
|
||
while self._AtOp('.'):
|
||
self._Next()
|
||
attr_tok: Token = self._ExpectName()
|
||
attr_node: N.Attribute = N.Attribute(value=node, attr=attr_tok.Value, ctx=N.Load())
|
||
self._FixLoc(attr_node, start)
|
||
node = attr_node
|
||
return node
|
||
|
||
def _ParseMatchSequence(self) -> N.pattern:
|
||
start: Token = self._Next() # '[' 或 '('
|
||
close: str = ']' if start.Value == '[' else ')'
|
||
patterns: list[N.pattern] = []
|
||
self._SkipNL()
|
||
if not self._AtOp(close):
|
||
while True:
|
||
self._SkipNL()
|
||
patterns.append(self._ParsePattern())
|
||
self._SkipNL()
|
||
if self._AtOp(','):
|
||
self._Next()
|
||
if self._AtOp(close):
|
||
break
|
||
continue
|
||
break
|
||
self._ExpectOp(close)
|
||
node: N.MatchSequence = N.MatchSequence(patterns=patterns)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
def _ParseMatchMapping(self) -> N.pattern:
|
||
start: Token = self._Next() # '{'
|
||
keys: list[N.expr] = []
|
||
patterns: list[N.pattern] = []
|
||
rest: str | None = None
|
||
self._SkipNL()
|
||
if not self._AtOp('}'):
|
||
while True:
|
||
self._SkipNL()
|
||
if self._AtOp('**'):
|
||
self._Next()
|
||
rest = self._ExpectName().Value
|
||
else:
|
||
key: N.expr = self.ParseExpr()
|
||
self._ExpectOp(':')
|
||
keys.append(key)
|
||
patterns.append(self._ParsePattern())
|
||
self._SkipNL()
|
||
if self._AtOp(','):
|
||
self._Next()
|
||
if self._AtOp('}'):
|
||
break
|
||
continue
|
||
break
|
||
self._ExpectOp('}')
|
||
node: N.MatchMapping = N.MatchMapping(keys=keys, patterns=patterns, rest=rest)
|
||
self._FixLoc(node, start)
|
||
return node
|
||
|
||
|
||
def Parse(source: str) -> N.Module:
|
||
"""便捷入口:源码字符串 → Module AST(供 vast.parse 调用)。"""
|
||
from lib.vast.Tokenizer import Tokenizer
|
||
|
||
tokens = Tokenizer(source).Tokenize()
|
||
line_starts: list[int] = [0]
|
||
# 从 token 流重建行起始表(由 Tokenizer 维护,此处直接计算)
|
||
line_starts = _ComputeLineStarts(source)
|
||
parser: Parser = Parser(tokens, source, line_starts)
|
||
return parser.ParseModule()
|
||
|
||
|
||
def _ComputeLineStarts(source: str) -> list[int]:
|
||
"""计算源码所有行起始字符索引(含首行 0)。
|
||
|
||
Uses C-level str.find instead of a per-character Python loop (large .vp
|
||
sources: millions of characters scanned once per parse).
|
||
"""
|
||
starts: list[int] = [0]
|
||
Find = source.find
|
||
i: int = Find('\n')
|
||
while i >= 0:
|
||
starts.append(i + 1)
|
||
i = Find('\n', i + 1)
|
||
return starts
|