Skip to content

Commit 0da42bf

Browse files
committed
Rip out self.next() entirely
1 parent 6afef47 commit 0da42bf

File tree

1 file changed

+76
-72
lines changed

1 file changed

+76
-72
lines changed

Tools/clinic/clinic.py

Lines changed: 76 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -4388,10 +4388,6 @@ def dedent(self, line: str) -> str:
43884388
return line[indent:]
43894389

43904390

4391-
class StateKeeper(Protocol):
4392-
def __call__(self, function: Function | None, line: str) -> Function | None: ...
4393-
4394-
43954391
ConverterArgs = dict[str, Any]
43964392

43974393
class ParamState(enum.IntEnum):
@@ -4425,8 +4421,18 @@ class ParamState(enum.IntEnum):
44254421
RIGHT_SQUARE_AFTER = 6
44264422

44274423

4424+
class DSLParserState(enum.Enum):
4425+
DSL_START = enum.auto()
4426+
MODULENAME_NAME = enum.auto()
4427+
PARAMETERS_START = enum.auto()
4428+
PARAMETER = enum.auto()
4429+
PARAMETER_DOCSTRING_START = enum.auto()
4430+
PARAMETER_DOCSTRING = enum.auto()
4431+
FUNCTION_DOCSTRING = enum.auto()
4432+
4433+
44284434
class DSLParser:
4429-
state: StateKeeper
4435+
state: DSLParserState
44304436
keyword_only: bool
44314437
positional_only: bool
44324438
group: int
@@ -4456,7 +4462,7 @@ def __init__(self, clinic: Clinic) -> None:
44564462
self.reset()
44574463

44584464
def reset(self) -> None:
4459-
self.state = self.state_dsl_start
4465+
self.state = DSLParserState.DSL_START
44604466
self.keyword_only = False
44614467
self.positional_only = False
44624468
self.group = 0
@@ -4611,7 +4617,7 @@ def parse(self, block: Block) -> None:
46114617
if '\t' in line:
46124618
fail('Tab characters are illegal in the Clinic DSL.\n\t' + repr(line), line_number=block_start)
46134619
try:
4614-
function = self.state(function, line)
4620+
function = self.handle_line(function, line)
46154621
except ClinicError as exc:
46164622
exc.lineno = line_number
46174623
raise
@@ -4624,11 +4630,43 @@ def parse(self, block: Block) -> None:
46244630
fail("'preserve' only works for blocks that don't produce any output!")
46254631
block.output = self.saved_output
46264632

4633+
def handle_line(self, function: Function | None, line: str) -> Function | None:
4634+
match function:
4635+
case None:
4636+
match self.state:
4637+
case DSLParserState.DSL_START:
4638+
return self.handle_dsl_start(line)
4639+
case DSLParserState.MODULENAME_NAME:
4640+
return self.handle_modulename_name(line)
4641+
case _ as state:
4642+
raise AssertionError(
4643+
f"self.state is {state!r} but function is still None!"
4644+
)
4645+
case Function():
4646+
match self.state:
4647+
case DSLParserState.PARAMETERS_START:
4648+
return self.handle_parameters_start(function, line)
4649+
case DSLParserState.PARAMETER:
4650+
return self.handle_parameter(function, line)
4651+
case DSLParserState.PARAMETER_DOCSTRING_START:
4652+
return self.handle_parameter_docstring_start(function, line)
4653+
case DSLParserState.PARAMETER_DOCSTRING:
4654+
return self.handle_parameter_docstring(function, line)
4655+
case DSLParserState.FUNCTION_DOCSTRING:
4656+
return self.handle_function_docstring(function, line)
4657+
case _ as state:
4658+
raise AssertionError(f"Unexpected state: {state!r}")
4659+
case _:
4660+
raise AssertionError(
4661+
f"Expected function to be a Function or None, "
4662+
f"got {type(function)!r}"
4663+
)
4664+
46274665
def in_docstring(self) -> bool:
46284666
"""Return true if we are processing a docstring."""
46294667
return self.state in {
4630-
self.state_parameter_docstring,
4631-
self.state_function_docstring,
4668+
DSLParserState.PARAMETER_DOCSTRING,
4669+
DSLParserState.FUNCTION_DOCSTRING,
46324670
}
46334671

46344672
def valid_line(self, line: str) -> bool:
@@ -4647,21 +4685,7 @@ def valid_line(self, line: str) -> bool:
46474685
def calculate_indent(line: str) -> int:
46484686
return len(line) - len(line.strip())
46494687

4650-
def next(
4651-
self,
4652-
state: StateKeeper,
4653-
*,
4654-
function: Function | None,
4655-
line: str | None = None,
4656-
) -> Function | None:
4657-
self.state = state
4658-
if line is not None:
4659-
function = self.state(function=function, line=line)
4660-
return function
4661-
4662-
def state_dsl_start(self, function: Function | None, line: str) -> Function | None:
4663-
assert function is None
4664-
4688+
def handle_dsl_start(self, line: str) -> Function | None:
46654689
if not self.valid_line(line):
46664690
return None
46674691

@@ -4676,11 +4700,10 @@ def state_dsl_start(self, function: Function | None, line: str) -> Function | No
46764700
fail(str(e))
46774701
return None
46784702

4679-
return self.next(self.state_modulename_name, function=None, line=line)
4703+
self.state = DSLParserState.MODULENAME_NAME
4704+
return self.handle_modulename_name(line)
46804705

4681-
def state_modulename_name(
4682-
self, function: Function | None, line: str
4683-
) -> Function | None:
4706+
def handle_modulename_name(self, line: str) -> Function | None:
46844707
# looking for declaration, which establishes the leftmost column
46854708
# line should be
46864709
# modulename.fnname [as c_basename] [-> return annotation]
@@ -4697,8 +4720,6 @@ def state_modulename_name(
46974720
# this line is permitted to start with whitespace.
46984721
# we'll call this number of spaces F (for "function").
46994722

4700-
assert function is None
4701-
47024723
if not self.valid_line(line):
47034724
return None
47044725

@@ -4740,7 +4761,8 @@ def state_modulename_name(
47404761
)
47414762
self.block.signatures.append(function)
47424763
(cls or module).functions.append(function)
4743-
return self.next(self.state_function_docstring, function=function)
4764+
self.state = DSLParserState.FUNCTION_DOCSTRING
4765+
return function
47444766

47454767
line, _, returns = line.partition('->')
47464768
returns = returns.strip()
@@ -4821,7 +4843,8 @@ def state_modulename_name(
48214843
function.parameters[name] = p_self
48224844

48234845
(cls or module).functions.append(function)
4824-
return self.next(self.state_parameters_start, function=function)
4846+
self.state = DSLParserState.PARAMETERS_START
4847+
return function
48254848

48264849
# Now entering the parameters section. The rules, formally stated:
48274850
#
@@ -4878,18 +4901,16 @@ def state_modulename_name(
48784901
# separate boolean state variables.) The states are defined in the
48794902
# ParamState class.
48804903

4881-
def state_parameters_start(self, function: Function | None, line: str) -> Function:
4882-
assert function is not None
4883-
4904+
def handle_parameters_start(self, function: Function, line: str) -> Function:
48844905
if self.valid_line(line):
48854906
# if this line is not indented, we have no parameters
48864907
if not self.indent.infer(line):
4887-
self.next(
4888-
self.state_function_docstring, function=function, line=line
4889-
)
4908+
self.state = DSLParserState.FUNCTION_DOCSTRING
4909+
self.handle_function_docstring(function=function, line=line)
48904910
else:
48914911
self.parameter_continuation = ''
4892-
self.next(self.state_parameter, function=function, line=line)
4912+
self.state = DSLParserState.PARAMETER
4913+
self.handle_parameter(function=function, line=line)
48934914

48944915
return function
48954916

@@ -4902,11 +4923,7 @@ def to_required(self, function: Function) -> None:
49024923
for p in function.parameters.values():
49034924
p.group = -p.group
49044925

4905-
def state_parameter(
4906-
self, function: Function | None, line: str
4907-
) -> Function:
4908-
assert function is not None
4909-
4926+
def handle_parameter(self, function: Function, line: str) -> Function:
49104927
if not self.valid_line(line):
49114928
return function
49124929

@@ -4918,17 +4935,13 @@ def state_parameter(
49184935
indent = self.indent.infer(line)
49194936
if indent == -1:
49204937
# we outdented, must be to definition column
4921-
self.next(
4922-
self.state_function_docstring, function=function, line=line
4923-
)
4924-
return function
4938+
self.state = DSLParserState.FUNCTION_DOCSTRING
4939+
return self.handle_function_docstring(function=function, line=line)
49254940

49264941
if indent == 1:
49274942
# we indented, must be to new parameter docstring column
4928-
self.next(
4929-
self.state_parameter_docstring_start, function=function, line=line
4930-
)
4931-
return function
4943+
self.state = DSLParserState.PARAMETER_DOCSTRING_START
4944+
return self.handle_parameter_docstring_start(function=function, line=line)
49324945

49334946
line = line.rstrip()
49344947
if line.endswith('\\'):
@@ -5318,15 +5331,14 @@ def parse_slash(self, function: Function) -> None:
53185331
"positional-only parameters, which is unsupported.")
53195332
p.kind = inspect.Parameter.POSITIONAL_ONLY
53205333

5321-
def state_parameter_docstring_start(
5322-
self, function: Function | None, line: str
5334+
def handle_parameter_docstring_start(
5335+
self, function: Function, line: str
53235336
) -> Function:
5324-
assert function is not None
53255337
assert self.indent.margin is not None, "self.margin.infer() has not yet been called to set the margin"
53265338
self.parameter_docstring_indent = len(self.indent.margin)
53275339
assert self.indent.depth == 3
5328-
self.next(self.state_parameter_docstring, function=function, line=line)
5329-
return function
5340+
self.state = DSLParserState.PARAMETER_DOCSTRING
5341+
return self.handle_parameter_docstring(function=function, line=line)
53305342

53315343
def docstring_append(self, obj: Function | Parameter, line: str) -> None:
53325344
"""Add a rstripped line to the current docstring."""
@@ -5345,11 +5357,9 @@ def docstring_append(self, obj: Function | Parameter, line: str) -> None:
53455357
# every line of the docstring must start with at least F spaces,
53465358
# where F > P.
53475359
# these F spaces will be stripped.
5348-
def state_parameter_docstring(
5349-
self, function: Function | None, line: str
5360+
def handle_parameter_docstring(
5361+
self, function: Function, line: str
53505362
) -> Function:
5351-
assert function is not None
5352-
53535363
if not self.valid_line(line):
53545364
return function
53555365

@@ -5359,25 +5369,19 @@ def state_parameter_docstring(
53595369
assert self.indent.depth < 3
53605370
if self.indent.depth == 2:
53615371
# back to a parameter
5362-
self.next(self.state_parameter, function=function, line=line)
5363-
return function
5372+
self.state = DSLParserState.PARAMETER
5373+
return self.handle_parameter(function=function, line=line)
53645374
assert self.indent.depth == 1
5365-
self.next(
5366-
self.state_function_docstring, function=function, line=line
5367-
)
5368-
return function
5375+
self.state = DSLParserState.FUNCTION_DOCSTRING
5376+
return self.handle_function_docstring(function=function, line=line)
53695377

53705378
assert function.parameters
53715379
last_param = next(reversed(function.parameters.values()))
53725380
self.docstring_append(last_param, line)
53735381
return function
53745382

53755383
# the final stanza of the DSL is the docstring.
5376-
def state_function_docstring(
5377-
self, function: Function | None, line: str
5378-
) -> Function:
5379-
assert function is not None
5380-
5384+
def handle_function_docstring(self, function: Function, line: str) -> Function:
53815385
if self.group:
53825386
fail(f"Function {function.name} has a ] without a matching [.")
53835387

0 commit comments

Comments
 (0)