Skip to content

Commit fe4cb1f

Browse files
committed
Rip out self.next() entirely
1 parent fa9e742 commit fe4cb1f

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
@@ -4618,7 +4624,7 @@ def parse(self, block: Block) -> None:
46184624
fail(f'Tab characters are illegal in the Clinic DSL: {line!r}',
46194625
line_number=block_start)
46204626
try:
4621-
function = self.state(function, line)
4627+
function = self.handle_line(function, line)
46224628
except ClinicError as exc:
46234629
exc.lineno = line_number
46244630
raise
@@ -4631,11 +4637,43 @@ def parse(self, block: Block) -> None:
46314637
fail("'preserve' only works for blocks that don't produce any output!")
46324638
block.output = self.saved_output
46334639

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

46414679
def valid_line(self, line: str) -> bool:
@@ -4650,21 +4688,7 @@ def valid_line(self, line: str) -> bool:
46504688

46514689
return True
46524690

4653-
def next(
4654-
self,
4655-
state: StateKeeper,
4656-
*,
4657-
function: Function | None,
4658-
line: str | None = None,
4659-
) -> Function | None:
4660-
self.state = state
4661-
if line is not None:
4662-
function = self.state(function=function, line=line)
4663-
return function
4664-
4665-
def state_dsl_start(self, function: Function | None, line: str) -> Function | None:
4666-
assert function is None
4667-
4691+
def handle_dsl_start(self, line: str) -> Function | None:
46684692
if not self.valid_line(line):
46694693
return None
46704694

@@ -4679,11 +4703,10 @@ def state_dsl_start(self, function: Function | None, line: str) -> Function | No
46794703
fail(str(e))
46804704
return None
46814705

4682-
return self.next(self.state_modulename_name, function=None, line=line)
4706+
self.state = DSLParserState.MODULENAME_NAME
4707+
return self.handle_modulename_name(line)
46834708

4684-
def state_modulename_name(
4685-
self, function: Function | None, line: str
4686-
) -> Function | None:
4709+
def handle_modulename_name(self, line: str) -> Function | None:
46874710
# looking for declaration, which establishes the leftmost column
46884711
# line should be
46894712
# modulename.fnname [as c_basename] [-> return annotation]
@@ -4700,8 +4723,6 @@ def state_modulename_name(
47004723
# this line is permitted to start with whitespace.
47014724
# we'll call this number of spaces F (for "function").
47024725

4703-
assert function is None
4704-
47054726
if not self.valid_line(line):
47064727
return None
47074728

@@ -4744,7 +4765,8 @@ def state_modulename_name(
47444765
)
47454766
self.block.signatures.append(function)
47464767
(cls or module).functions.append(function)
4747-
return self.next(self.state_function_docstring, function=function)
4768+
self.state = DSLParserState.FUNCTION_DOCSTRING
4769+
return function
47484770

47494771
line, _, returns = line.partition('->')
47504772
returns = returns.strip()
@@ -4825,7 +4847,8 @@ def state_modulename_name(
48254847
function.parameters[name] = p_self
48264848

48274849
(cls or module).functions.append(function)
4828-
return self.next(self.state_parameters_start, function=function)
4850+
self.state = DSLParserState.PARAMETERS_START
4851+
return function
48294852

48304853
# Now entering the parameters section. The rules, formally stated:
48314854
#
@@ -4882,18 +4905,16 @@ def state_modulename_name(
48824905
# separate boolean state variables.) The states are defined in the
48834906
# ParamState class.
48844907

4885-
def state_parameters_start(self, function: Function | None, line: str) -> Function:
4886-
assert function is not None
4887-
4908+
def handle_parameters_start(self, function: Function, line: str) -> Function:
48884909
if self.valid_line(line):
48894910
# if this line is not indented, we have no parameters
48904911
if not self.indent.infer(line):
4891-
self.next(
4892-
self.state_function_docstring, function=function, line=line
4893-
)
4912+
self.state = DSLParserState.FUNCTION_DOCSTRING
4913+
self.handle_function_docstring(function=function, line=line)
48944914
else:
48954915
self.parameter_continuation = ''
4896-
self.next(self.state_parameter, function=function, line=line)
4916+
self.state = DSLParserState.PARAMETER
4917+
self.handle_parameter(function=function, line=line)
48974918

48984919
return function
48994920

@@ -4906,11 +4927,7 @@ def to_required(self, function: Function) -> None:
49064927
for p in function.parameters.values():
49074928
p.group = -p.group
49084929

4909-
def state_parameter(
4910-
self, function: Function | None, line: str
4911-
) -> Function:
4912-
assert function is not None
4913-
4930+
def handle_parameter(self, function: Function, line: str) -> Function:
49144931
if not self.valid_line(line):
49154932
return function
49164933

@@ -4922,17 +4939,13 @@ def state_parameter(
49224939
indent = self.indent.infer(line)
49234940
if indent == -1:
49244941
# we outdented, must be to definition column
4925-
self.next(
4926-
self.state_function_docstring, function=function, line=line
4927-
)
4928-
return function
4942+
self.state = DSLParserState.FUNCTION_DOCSTRING
4943+
return self.handle_function_docstring(function=function, line=line)
49294944

49304945
if indent == 1:
49314946
# we indented, must be to new parameter docstring column
4932-
self.next(
4933-
self.state_parameter_docstring_start, function=function, line=line
4934-
)
4935-
return function
4947+
self.state = DSLParserState.PARAMETER_DOCSTRING_START
4948+
return self.handle_parameter_docstring_start(function=function, line=line)
49364949

49374950
line = line.rstrip()
49384951
if line.endswith('\\'):
@@ -5323,15 +5336,14 @@ def parse_slash(self, function: Function) -> None:
53235336
"positional-only parameters, which is unsupported.")
53245337
p.kind = inspect.Parameter.POSITIONAL_ONLY
53255338

5326-
def state_parameter_docstring_start(
5327-
self, function: Function | None, line: str
5339+
def handle_parameter_docstring_start(
5340+
self, function: Function, line: str
53285341
) -> Function:
5329-
assert function is not None
53305342
assert self.indent.margin is not None, "self.margin.infer() has not yet been called to set the margin"
53315343
self.parameter_docstring_indent = len(self.indent.margin)
53325344
assert self.indent.depth == 3
5333-
self.next(self.state_parameter_docstring, function=function, line=line)
5334-
return function
5345+
self.state = DSLParserState.PARAMETER_DOCSTRING
5346+
return self.handle_parameter_docstring(function=function, line=line)
53355347

53365348
def docstring_append(self, obj: Function | Parameter, line: str) -> None:
53375349
"""Add a rstripped line to the current docstring."""
@@ -5350,11 +5362,9 @@ def docstring_append(self, obj: Function | Parameter, line: str) -> None:
53505362
# every line of the docstring must start with at least F spaces,
53515363
# where F > P.
53525364
# these F spaces will be stripped.
5353-
def state_parameter_docstring(
5354-
self, function: Function | None, line: str
5365+
def handle_parameter_docstring(
5366+
self, function: Function, line: str
53555367
) -> Function:
5356-
assert function is not None
5357-
53585368
if not self.valid_line(line):
53595369
return function
53605370

@@ -5364,25 +5374,19 @@ def state_parameter_docstring(
53645374
assert self.indent.depth < 3
53655375
if self.indent.depth == 2:
53665376
# back to a parameter
5367-
self.next(self.state_parameter, function=function, line=line)
5368-
return function
5377+
self.state = DSLParserState.PARAMETER
5378+
return self.handle_parameter(function=function, line=line)
53695379
assert self.indent.depth == 1
5370-
self.next(
5371-
self.state_function_docstring, function=function, line=line
5372-
)
5373-
return function
5380+
self.state = DSLParserState.FUNCTION_DOCSTRING
5381+
return self.handle_function_docstring(function=function, line=line)
53745382

53755383
assert function.parameters
53765384
last_param = next(reversed(function.parameters.values()))
53775385
self.docstring_append(last_param, line)
53785386
return function
53795387

53805388
# the final stanza of the DSL is the docstring.
5381-
def state_function_docstring(
5382-
self, function: Function | None, line: str
5383-
) -> Function:
5384-
assert function is not None
5385-
5389+
def handle_function_docstring(self, function: Function, line: str) -> Function:
53865390
if self.group:
53875391
fail(f"Function {function.name!r} has a ']' without a matching '['.")
53885392

0 commit comments

Comments
 (0)