Files
TransPyC/lib/vast/Parser.py
T
TermiNexus f19d25782f refactor(tpc): 退役 t/c 模块并将定宽类型升级为内建
删除 lib/includes/t.py、c.py,类型模型迁入 lib/core/TypeSystem.py;移除 IsTModule/_T_MODULE_NAMES 等名称判据,语法糖与内部标记统一为裸名;builtins 的 sizet/intN/uintN/fast/least/uchar/short/long 等改为编译器内建短名。
2026-10-18 13:00:58 +08:00

1854 lines
83 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""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 函数声明(FFI,等价 State)——必须在软关键字 def 分派之前
if v == 'extern':
return self._ParseExternDef()
# export 函数声明(等价 CExport,裸名导出不增加 SHA1 头)——
# 必须在软关键字 def 分派之前
if v == 'export':
return self._ParseExportDef()
# static 存储类软关键字(已从"注解位置"迁出为**语句起始前置**修饰符):
# 仅 `static def 名字` 形态判定为函数定义——判据必须同时要求第二个 token
# 是 `def`,故 `static = 5` / `static x = 5` 不会被误吃成函数定义。
# 变量形式 `static 名字: 类型 = 值` 不在本层处理,由 SymbolUtils 的前置
# 修饰符展开统一脱糖为 `名字: CStatic | 类型 = 值`。
if (v == 'static' and self._Peek(1).Type == NAME
and self._Peek(1).Value == 'def'):
return self._ParseStaticDef()
# define 宏函数定义(与 def 语义一致,返回注解自动追加 CDefine
# 标记为宏函数;软关键字:仅"define + 标识符"形态才判定为函数定义,
# 变量名/调用(define = 5、define(x))不受影响)——必须在软关键字
# def 分派之前
if v == 'define' and self._Peek(1).Type == NAME:
return self._ParseDefineDef()
# 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()
# ==================================================================
# 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` / `CTypedef` / 含它的 `|` 联合)。
用于把 typedef 的右值按**类型位置**解析(`X: CTypedef = const uint16*`
里的 `*` 后缀由 _ParseTypeAnnotation 消费,与注解位同一规则;描述符
`const`/`volatile` 已由 SymbolUtils._ExpandTypeDescriptors 在文本层展开)。
仅按标记名判定,不依赖 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,与 State 作用相当)。
允许语法(均声明不定义,不生成函数体):
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 节点,返回注解改写为 ``<原类型> | State``
以复用 TPC 的 IsState 路径;并设自定义属性 ``Extern = True``
供 Unparser 还原 extern 语法。
"""
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
# 返回注解改写为 <原类型> | State,使 TPC 识别为 State 函数(仅声明)
state_attr: N.expr = N.Name(id='State', ctx=N.Load())
if returns is not None:
node.returns = N.BinOp(left=returns, op=N.BitOr(), right=state_attr)
else:
node.returns = state_attr
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 节点,返回注解改写为 ``<原类型> | 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._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
# 返回注解改写为 <原类型> | CExport,使 TPC 识别为 CExport 函数
# (导出裸名,不增加模块 SHA1 头;有条件情况下导出)
export_attr: N.expr = N.Name(id='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 _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 节点,返回注解改写为 ``<原类型> | CDefine``
(无显式返回注解时单独 ``CDefine``),使 TPC/VPC 复用既有的
CDefine 宏函数识别路径(StubGen 原样保留生成 C #define、
alwaysinline 内联);并设自定义属性 ``Define = True`` 供
Unparser 还原 define 语法。
"""
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
# 返回注解改写为 <原类型> | CDefine,使下游识别为宏函数
# (StubGen 保留原样输出 C #define;TPC 标记 alwaysinline 内联)
define_attr: N.expr = N.Name(id='CDefine', ctx=N.Load())
if returns is not None:
node.returns = N.BinOp(left=returns, op=N.BitOr(), right=define_attr)
else:
node.returns = define_attr
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