From aa9042173eb99d29e62bf84923b6f41580fa393d Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Mon, 17 Aug 2026 10:22:29 +0800 Subject: [PATCH] =?UTF-8?q?fix(vast):=20=E4=BF=AE=E5=A4=8D=20match=20?= =?UTF-8?q?=E7=B1=BB=E6=A8=A1=E5=BC=8F=E4=B8=8E=20or=20=E6=A8=A1=E5=BC=8F?= =?UTF-8?q?=E8=A7=A3=E6=9E=90=E4=B8=8E=20CPython=20=E4=B8=8D=E4=B8=80?= =?UTF-8?q?=E8=87=B4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - case ClassName.attr(...) 类模式:扫描属性链末尾判断 '(', 此前只查首 token 后 '(',LLVMType.Ptr(...) 被误解析为 MatchValue(Call) → TPC 对 renum match 走值模式分支,对枚举 构造表达式运行时求值生成 ptrtoint SSA,LLVM switch 报 'case value is not a constant integer' - case 0 | 1 值模式:字面量/符号不再消费顶层 '|',留给 _ParsePattern 组 MatchOr(此前 ParseExpr 吞掉 '|' 成 BinOp) --- lib/vast/Parser.py | 50 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 10 deletions(-) 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()