-
-
Notifications
You must be signed in to change notification settings - Fork 32.2k
bpo-43897: Implement AST validation for Pattern Matching #24771
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
bpo-43897: Implement AST validation for Pattern Matching #24771
Conversation
|
This PR is stale because it has been open for 30 days with no activity. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi @isidentical!
I think I missed this in the beta-freeze scramble. Any plans to update it for the new AST?
I might take a look at it in the upcoming weeks though I don't think I would have enough capacity to catch up with beta 2 (9 days from now). If you have time, I could give access to my fork if not I'll try to make it ready for beta 3. |
|
Beta 3 is fine! |
0356aea to
d758c6a
Compare
|
Hey @brandtbucher! I've updated the PR with the new AST form, sorry it took a bit long. I didn't have much free time after the AST layout change, and needed to catch up with the new nodes first. Just ported all the missing pieces, there are still some bugs that I can see (for example some of the old parts of the validator code just quit when error happens, but doesn't decrement the recursion limit. Since I didn't touch those and the patch was already big I just skipped them now, might fix later) but nothing too big. Please let me know any missing stuff that I should handle. |
|
🤖 New build scheduled with the buildbot fleet by @isidentical for commit d758c6a1e9f6c01800822c5bdf5e1778161fab3f 🤖 If you want to schedule another build, you need to add the ":hammer: test-with-buildbots" label again. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, this looks really good! I just have a few comments:
Lib/test/test_ast.py
Outdated
| cases = [ | ||
| ast.match_case( | ||
| pattern=pattern, | ||
| body = [ast.Expr(ast.Constant(...))] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Took me a sec to see what was happening here. Maybe clearer as ast.Pass()?
| body = [ast.Expr(ast.Constant(...))] | |
| body = [ast.Pass()] |
Lib/test/test_ast.py
Outdated
| ast.MatchMapping( | ||
| [constant_true, ast.Starred(ast.Name('lol', ast.Load()), ast.Load())], | ||
| [pattern_x, pattern_1], | ||
| rest='legit' | ||
| ), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks the exact same as the pattern above, right?
| ast.MatchMapping( | |
| [constant_true, ast.Starred(ast.Name('lol', ast.Load()), ast.Load())], | |
| [pattern_x, pattern_1], | |
| rest='legit' | |
| ), |
Python/ast.c
Outdated
| case Constant_kind: { | ||
| /* Ellipsis and immutable sequences are not allowed. | ||
| For True, False and None, MatchSingleton() should | ||
| be used */ | ||
| if (!validate_expr(state, exp, Load)) { | ||
| return 0; | ||
| } | ||
| PyObject *literal = exp->v.Constant.value; | ||
| if (PyLong_CheckExact(literal) || PyFloat_CheckExact(literal) || | ||
| PyBytes_CheckExact(literal) || PyComplex_CheckExact(literal) || | ||
| PyUnicode_CheckExact(literal)) { | ||
| return 1; | ||
| } | ||
| PyErr_SetString(PyExc_ValueError, | ||
| "unexpected constant inside of a literal pattern"); | ||
| return 0; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think these braces are needed, right?
| case Constant_kind: { | |
| /* Ellipsis and immutable sequences are not allowed. | |
| For True, False and None, MatchSingleton() should | |
| be used */ | |
| if (!validate_expr(state, exp, Load)) { | |
| return 0; | |
| } | |
| PyObject *literal = exp->v.Constant.value; | |
| if (PyLong_CheckExact(literal) || PyFloat_CheckExact(literal) || | |
| PyBytes_CheckExact(literal) || PyComplex_CheckExact(literal) || | |
| PyUnicode_CheckExact(literal)) { | |
| return 1; | |
| } | |
| PyErr_SetString(PyExc_ValueError, | |
| "unexpected constant inside of a literal pattern"); | |
| return 0; | |
| } | |
| case Constant_kind: | |
| /* Ellipsis and immutable sequences are not allowed. | |
| For True, False and None, MatchSingleton() should | |
| be used */ | |
| if (!validate_expr(state, exp, Load)) { | |
| return 0; | |
| } | |
| PyObject *literal = exp->v.Constant.value; | |
| if (PyLong_CheckExact(literal) || PyFloat_CheckExact(literal) || | |
| PyBytes_CheckExact(literal) || PyComplex_CheckExact(literal) || | |
| PyUnicode_CheckExact(literal)) { | |
| return 1; | |
| } | |
| PyErr_SetString(PyExc_ValueError, | |
| "unexpected constant inside of a literal pattern"); | |
| return 0; |
Python/ast.c
Outdated
| break; | ||
| case MatchMapping_kind: | ||
| // TODO: check "rest" target name is valid | ||
| case MatchMapping_kind: { | ||
| if (asdl_seq_LEN(p->v.MatchMapping.keys) != asdl_seq_LEN(p->v.MatchMapping.patterns)) { | ||
| PyErr_SetString(PyExc_ValueError, | ||
| "MatchMapping doesn't have the same number of keys as patterns"); | ||
| return 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| return 0; | |
| ret = 0; | |
| break; |
Python/ast.c
Outdated
| break; | ||
| case MatchMapping_kind: | ||
| // TODO: check "rest" target name is valid | ||
| case MatchMapping_kind: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These braces aren't needed either, right?
| case MatchMapping_kind: { | |
| case MatchMapping_kind: |
Python/ast.c
Outdated
| break; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above.
| } |
Python/ast.c
Outdated
| } else if (cls->kind == Attribute_kind) { | ||
| cls = cls->v.Attribute.value; | ||
| continue; | ||
| } else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| } else if (cls->kind == Attribute_kind) { | |
| cls = cls->v.Attribute.value; | |
| continue; | |
| } else { | |
| } | |
| else if (cls->kind == Attribute_kind) { | |
| cls = cls->v.Attribute.value; | |
| continue; | |
| } | |
| else { |
Python/ast.c
Outdated
| break; | ||
| } | ||
| case MatchClass_kind: | ||
| if (asdl_seq_LEN(p->v.MatchClass.kwd_attrs) != asdl_seq_LEN(p->v.MatchClass.kwd_patterns)) { | ||
| PyErr_SetString(PyExc_ValueError, | ||
| "MatchClass doesn't have the same number of keyword attributes as patterns"); | ||
| return 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| return 0; | |
| ret = 0; | |
| break; |
Python/ast.c
Outdated
| case MatchClass_kind: | ||
| if (asdl_seq_LEN(p->v.MatchClass.kwd_attrs) != asdl_seq_LEN(p->v.MatchClass.kwd_patterns)) { | ||
| PyErr_SetString(PyExc_ValueError, | ||
| "MatchClass doesn't have the same number of keyword attributes as patterns"); | ||
| return 0; | ||
| } | ||
| // TODO: Restrict cls lookup to being a name or attribute | ||
| if (!validate_expr(state, p->v.MatchClass.cls, Load)) { | ||
| return 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| return 0; | |
| ret = 0; | |
| break; |
|
When you're done making the requested changes, leave the comment: |
Sorry, didn't see this. Feel free to ignore those suggestions, then! I can find time to go back over those and fix the |
What do you mean by the |
d758c6a to
8dcb7d9
Compare
Patterns like Also, |
|
Thanks again! Sorry I kept dropping the ball on this, haha. |
https://bugs.python.org/issue43897