-
-
Notifications
You must be signed in to change notification settings - Fork 31.1k
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
gh-104683: Argument clinic: remove some unnecessary uses of self.next()
in the DSLParser
#107635
Conversation
|
||
def state_modulename_name(self, line: str) -> None: | ||
def parse_modulename_name(self, line: str) -> None: |
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 renamed this function to distinguish it from the state_foo
functions, all of which must only ever be called indirectly via self.next()
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.
What do you think of parse_function_declaration
?
def parse_modulename_name(self, line: str) -> None: | |
def parse_function_declaration(self, line: str) -> None: |
I'm not sure (yet) this is a step in the right direction. By consolidating stages in the state machine, debugging it becomes harder. For example, if I add this debug print: diff --git a/Tools/clinic/clinic.py b/Tools/clinic/clinic.py
index 6c5a2c7c85..b9d47d2e0e 100755
--- a/Tools/clinic/clinic.py
+++ b/Tools/clinic/clinic.py
@@ -4652,6 +4652,7 @@ def next(
line: str | None = None
) -> None:
self.state = state
+ print(f"--> {state.__name__:25} {line=!r}")
if line is not None:
self.state(line)
I get this: $ cat test.c
/*[clinic input]
module m
m.func
a: int
[clinic start generated code]*/
static PyObject *
m_func_impl(PyObject *module, int a)
/*[clinic end generated code: output=188ac0e0fa832273 input=e686625fcf7cad0e]*/
$ python3.12 Tools/clinic/clinic.py test.c
--> state_modulename_name line='m.func'
--> state_parameters_start line=None
--> state_parameter line=' a: int' However, with this PR, I now get: $ python3.12 Tools/clinic/clinic.py test.c
--> state_parameters_start line=None
--> state_parameter line=' a: int' |
Right, that's a very good point, and I think exposes that my mental model of the state machine here was subtly wrong. I think there may be another solution to the "But wait, these branches are unreachable!" problem I came up against in Argument-Clinic#14; I'll have a play around. |
Many
state_foo
methods on theDSLParser
class inclinic.py
are called only indirectly via thenext()
method:cpython/Tools/clinic/clinic.py
Lines 4645 to 4652 in 407d7fd
The reason for this is that the
DSLParser
parses argument-clinic input a line at a time; butstate
often persists across lines. (Example: a docstring can span multiple lines; by saving the "state" at the end of one line, the DSLParser is able to resume parsing with the same state when it begins parsing the next line, and therefore knows that it's in the middle of a docstring.)However, there are two
state_foo
methods on theDSLParser
class that are arguably badly named, and shouldn't be called viaself.next()
, even though they both currently are:state_modulename_name
state_parameter_docstring_start
Both of these are examples of states that are impossible to span multiple lines. A modulename declaration cannot span multiple lines; nor can the start of a parameter docstring. As such, calling these methods via
self.next()
is needless indirection, and can be removed.It is provable that both of these states cannot span multiple lines, due to the fact that neither
state_modulename_name
norstate_parameter_docstring_start
ever exit early before settingself.state
to something new (by callingself.next
).Tools/clinic/
#104683