Repository navigation
Add support for match statements to parser - #4519
Conversation
5265ca2 to
85e8243
Compare
|
The main challenge here is that match = re.match(pattern, str)
if match is not None:
print(match[1])that uses We typically don’t know whether match *a + b, c # ((match * a) + b), c
match *a + b, c: # match ((*(a + b)), c):
match *(a + b), c # (match * (a + b)), c
match *(a + b), c: # match ((*(a + b)), c):
match (*a + b, c) # match ((*(a + b)), c)
match (*a + b, c): # match ((*(a + b)), c):match -a * b + c # (match - (a * b)) + c
match -a * b + c: # match (((-a) * b) + c):
match -(a * b) + c # (match - (a * b)) + c
match -(a * b) + c: # match ((-(a * b) + c):
match (-a) * b + c # (match (-(a * b))) + c
match (-a) * b + c: # match (((-a) * b) + c):match ().a # (match()).a
match ().a: # match (().a):
match (()).a # (match(())).a
match (()).a: # match (().a):
match ((),).a # (match(())).a
match ((),).a: # match (((),).a):match (a).b # (match(a)).b
match (a).b: # match (a.b):
match (a.b) # match(a.b)
match (a.b): # match (a.b):
match (a,).b # (match(a)).b (not (match((a,))).b)
match (a,).b: # match ((a,).b): (not match (a.b):)
match ((a,)).b # (match((a,))).b
match ((a,)).b: # match ((a,).b):match [a].b # (match[a]).b
match [a].b: # match ([a].b):
match [a,].b # (match[(a,)]).b (not (match[a]).b)
match [a,].b: # match ([a].b): (not match ([(a,)].b):)
match [(a,)].b # (match[(a,)]).b
match [(a,)].b: # match ([(a,)].b):My rough plan (slightly amended after looking again) was going to be:
so that in either case there should be enough information to convert to the other form later if we find the initial assumption was wrong. This specific initial classification is important: there’s not enough information to translate in the other direction in either case. Of course, this is easier said than coded in LALRPOP, and I’m not entirely sure whether LALRPOP bugs are interfering with my attempt (I already found one). |
|
Thanks, this is extremely helpful. (I kind of assumed I was missing something important given how smoothly this went.) If you’re further along and want to keep pushing on it, I can close and defer to you. Or if you want to collaborate on a branch that works too. Or I can keep trying here based on some of the pointers above. Whatever you prefer. |
|
Some discussion from Parso that may or may not end up being relevant here: davidhalter/parso#138 (comment) |
|
To what degree would getting those LALRPOP changes merge help here? Do we need to consider publishing a fork for now? |
|
I also found this interesting on how Python 3.5 and earlier handled async and await as soft keywords via lexer tricks, but I doubt they’d help us here: https://benjam.info/blog/posts/2019-09-18-python-deep-dive-tokenizer/#async-and-await |
|
Although… could we have the lexer look ahead? Is that crazy? Isn’t it a match statement IFF the line starts with match and ends in a colon? (Haven’t thought this through, I assume that won’t work.) |
|
No I don’t think a lexer trick like that can work: match()[a:
b]
match()[a:
b]: |
|
Well you’d need to skip over bracketed content, no? I.e., look ahead until you hit a logical newline (not a physical newline)? At which point you’d either have a semicolon or not. |
|
Put differently, what I’m asking is whether we could backtrack or lookahead in the lexer (where we have more control) rather than complicating the parser. E.g. I think LALRPOP does some backtracking in its own lexer (https://github.com/lalrpop/lalrpop/blob/b777a6a884052d6283971f71b3ba453aa6d417ab/lalrpop/src/tok/mod.rs#L138), but I’d have to try this myself to have a real opinion on it. |
8d0f96e to
5b44678
Compare
9016f92 to
33bc7f2
Compare
|
This is able to parse all of |
55610d6 to
0893e73
Compare
|
From what I can tell, performance is the ~same or within 1% (for parsing CPython via Ruff). |
| kwd_patterns: vec![], | ||
| } | ||
| }, | ||
| } |
There was a problem hiding this comment.
I suspect some of this could be made more concise.
|
@andersk could you review this PR? |
Co-authored-by: Jim Fasarakis-Hilliard <d.f.hilliard@gmail.com>
963b9cd to
0201a5a
Compare
|
@youknowone I say we merge this later today, what do you think? |
|
Totally fine if andersk is busy. I forgot the specific branch, but I found @charliermarsh already tested it with ruff Thanks @flying-sheep |
|
unpinning #2759 |
|
Yeah I've run that branch over the following codebases and, in each case, verified that the lint violation counts are identical before and after that change:
On CPython, we see 18367 violations before and 18533 after; however, one fewer parse error in |
|
Merging so we don't unnecessarily hold up astral-sh/ruff#282 too, really big thanks for this @charliermarsh! |
Extends #95 Closes #82 Adds parsing of new `type` soft keyword for defining type aliases. Supports type alias statements as defined in PEP 695 e.g. ```python # A non-generic type alias type IntOrStr = int | str # A generic type alias type ListOrSet[T] = list[T] | set[T] # A type alias that includes a forward reference type AnimalOrVegetable = Animal | "Vegetable" # A generic self-referential type alias type RecursiveList[T] = T | list[RecursiveList[T]] ``` All type parameter kinds are supported as in #95. Builds on soft keyword abstractions introduced in RustPython/RustPython#4519
…hon#97) Extends RustPython#95 Closes RustPython#82 Adds parsing of new `type` soft keyword for defining type aliases. Supports type alias statements as defined in PEP 695 e.g. ```python type IntOrStr = int | str type ListOrSet[T] = list[T] | set[T] type AnimalOrVegetable = Animal | "Vegetable" type RecursiveList[T] = T | list[RecursiveList[T]] ``` All type parameter kinds are supported as in RustPython#95. Builds on soft keyword abstractions introduced in RustPython/RustPython#4519
…hon#97) Extends RustPython#95 Closes RustPython#82 Adds parsing of new `type` soft keyword for defining type aliases. Supports type alias statements as defined in PEP 695 e.g. ```python type IntOrStr = int | str type ListOrSet[T] = list[T] | set[T] type AnimalOrVegetable = Animal | "Vegetable" type RecursiveList[T] = T | list[RecursiveList[T]] ``` All type parameter kinds are supported as in RustPython#95. Builds on soft keyword abstractions introduced in RustPython/RustPython#4519
Summary
This is a work-in-progress, but it does work thus far for the implemented cases. I'm putting it up now to (1) signal that I'm working on it, and (2) get feedback from anyone else that has explored this and can see problems ahead.
closes #4323
closes #3427