|
83 | 83 | from mcpyrate.core import Done |
84 | 84 | from mcpyrate.walkers import ASTTransformer, ASTVisitor |
85 | 85 |
|
86 | | -from .astcompat import TryStar |
| 86 | +from .astcompat import TryStar, MatchStar, MatchMapping, MatchClass, MatchAs |
87 | 87 |
|
88 | 88 | from ..it import uniqify |
89 | 89 |
|
@@ -313,6 +313,12 @@ def get_names_in_store_context(tree): |
313 | 313 | by ``get_lexical_variables`` for the nearest lexically surrounding parent |
314 | 314 | tree that represents a scope. |
315 | 315 | """ |
| 316 | + class MatchCapturesCollector(ASTVisitor): # Python 3.10+: `match`/`case` |
| 317 | + def examine(self, tree): |
| 318 | + if type(tree) is Name: |
| 319 | + self.collect(tree.id) |
| 320 | + self.generic_visit(tree) |
| 321 | + |
316 | 322 | class StoreNamesCollector(ASTVisitor): |
317 | 323 | # def _collect_name_or_list(self, t): |
318 | 324 | # if type(t) is Name: |
@@ -346,6 +352,29 @@ def examine(self, tree): |
346 | 352 | # TODO: `try`, even inside the `except` blocks, will be bound in the whole parent scope. |
347 | 353 | for h in tree.handlers: |
348 | 354 | self.collect(h.name) |
| 355 | + # Python 3.10+: `match`/`case` uses names in `Load` context to denote captures. |
| 356 | + # Also there are some bare strings, and sometimes `None` actually means "_" (but doesn't capture). |
| 357 | + # So we special-case all of this. |
| 358 | + elif type(tree) in (MatchAs, MatchStar): # a `MatchSequence` also consists of these |
| 359 | + if tree.name is not None: |
| 360 | + self.collect(tree.name) |
| 361 | + elif type(tree) is MatchMapping: |
| 362 | + mcc = MatchCapturesCollector(tree.patterns) |
| 363 | + mcc.visit() |
| 364 | + for name in mcc.collected: |
| 365 | + self.collect(name) |
| 366 | + if tree.rest is not None: # `rest` is a capture if present |
| 367 | + self.collect(tree.rest) |
| 368 | + elif type(tree) is MatchClass: |
| 369 | + mcc = MatchCapturesCollector(tree.patterns) |
| 370 | + mcc.visit() |
| 371 | + for name in mcc.collected: |
| 372 | + self.collect(name) |
| 373 | + mcc = MatchCapturesCollector(tree.kwd_patterns) |
| 374 | + mcc.visit() |
| 375 | + for name in mcc.collected: |
| 376 | + self.collect(name) |
| 377 | + |
349 | 378 | # Python 3.12+: `TypeAlias` uses a name in `Store` context on its LHS so it needs no special handling here. |
350 | 379 |
|
351 | 380 | # Same note as for for loops. |
|
0 commit comments