diff --git a/lib/vast/Parser.py b/lib/vast/Parser.py index 507366a..e11f83c 100644 --- a/lib/vast/Parser.py +++ b/lib/vast/Parser.py @@ -883,8 +883,12 @@ class Parser(ExprParserMixin): value={'True': True, 'False': False, 'None': None}[tok.Value]) self._FixLoc(node, tok) return node - # 类模式:Name(...) 或 a.b(...) - if self._Peek(1).Type == OP and self._Peek(1).Value == '(': + # 类模式: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 == '.': @@ -900,14 +904,10 @@ class Parser(ExprParserMixin): # 映射模式 {k: v, **rest} if tok.Type == OP and tok.Value == '{': return self._ParseMatchMapping() - # 字面量:数字/字符串/负号 - if tok.Type == NUMBER or tok.Type == STRING or tok.Type == FSTRING: - value: N.expr = self.ParseExpr() - node = N.MatchValue(value=value) - self._FixLoc(node, start) - return node - if tok.Type == OP and tok.Value in ('-', '+'): - value = self.ParseExpr() + # 值模式:数字/字符串/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 @@ -921,6 +921,36 @@ class Parser(ExprParserMixin): 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()