@@ -4388,10 +4388,6 @@ def dedent(self, line: str) -> str:
4388
4388
return line [indent :]
4389
4389
4390
4390
4391
- class StateKeeper (Protocol ):
4392
- def __call__ (self , function : Function | None , line : str ) -> Function | None : ...
4393
-
4394
-
4395
4391
ConverterArgs = dict [str , Any ]
4396
4392
4397
4393
class ParamState (enum .IntEnum ):
@@ -4425,8 +4421,18 @@ class ParamState(enum.IntEnum):
4425
4421
RIGHT_SQUARE_AFTER = 6
4426
4422
4427
4423
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
+
4428
4434
class DSLParser :
4429
- state : StateKeeper
4435
+ state : DSLParserState
4430
4436
keyword_only : bool
4431
4437
positional_only : bool
4432
4438
group : int
@@ -4456,7 +4462,7 @@ def __init__(self, clinic: Clinic) -> None:
4456
4462
self .reset ()
4457
4463
4458
4464
def reset (self ) -> None :
4459
- self .state = self . state_dsl_start
4465
+ self .state = DSLParserState . DSL_START
4460
4466
self .keyword_only = False
4461
4467
self .positional_only = False
4462
4468
self .group = 0
@@ -4618,7 +4624,7 @@ def parse(self, block: Block) -> None:
4618
4624
fail (f'Tab characters are illegal in the Clinic DSL: { line !r} ' ,
4619
4625
line_number = block_start )
4620
4626
try :
4621
- function = self .state (function , line )
4627
+ function = self .handle_line (function , line )
4622
4628
except ClinicError as exc :
4623
4629
exc .lineno = line_number
4624
4630
raise
@@ -4631,11 +4637,43 @@ def parse(self, block: Block) -> None:
4631
4637
fail ("'preserve' only works for blocks that don't produce any output!" )
4632
4638
block .output = self .saved_output
4633
4639
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
+
4634
4672
def in_docstring (self ) -> bool :
4635
4673
"""Return true if we are processing a docstring."""
4636
4674
return self .state in {
4637
- self . state_parameter_docstring ,
4638
- self . state_function_docstring ,
4675
+ DSLParserState . PARAMETER_DOCSTRING ,
4676
+ DSLParserState . FUNCTION_DOCSTRING ,
4639
4677
}
4640
4678
4641
4679
def valid_line (self , line : str ) -> bool :
@@ -4650,21 +4688,7 @@ def valid_line(self, line: str) -> bool:
4650
4688
4651
4689
return True
4652
4690
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 :
4668
4692
if not self .valid_line (line ):
4669
4693
return None
4670
4694
@@ -4679,11 +4703,10 @@ def state_dsl_start(self, function: Function | None, line: str) -> Function | No
4679
4703
fail (str (e ))
4680
4704
return None
4681
4705
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 )
4683
4708
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 :
4687
4710
# looking for declaration, which establishes the leftmost column
4688
4711
# line should be
4689
4712
# modulename.fnname [as c_basename] [-> return annotation]
@@ -4700,8 +4723,6 @@ def state_modulename_name(
4700
4723
# this line is permitted to start with whitespace.
4701
4724
# we'll call this number of spaces F (for "function").
4702
4725
4703
- assert function is None
4704
-
4705
4726
if not self .valid_line (line ):
4706
4727
return None
4707
4728
@@ -4744,7 +4765,8 @@ def state_modulename_name(
4744
4765
)
4745
4766
self .block .signatures .append (function )
4746
4767
(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
4748
4770
4749
4771
line , _ , returns = line .partition ('->' )
4750
4772
returns = returns .strip ()
@@ -4825,7 +4847,8 @@ def state_modulename_name(
4825
4847
function .parameters [name ] = p_self
4826
4848
4827
4849
(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
4829
4852
4830
4853
# Now entering the parameters section. The rules, formally stated:
4831
4854
#
@@ -4882,18 +4905,16 @@ def state_modulename_name(
4882
4905
# separate boolean state variables.) The states are defined in the
4883
4906
# ParamState class.
4884
4907
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 :
4888
4909
if self .valid_line (line ):
4889
4910
# if this line is not indented, we have no parameters
4890
4911
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 )
4894
4914
else :
4895
4915
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 )
4897
4918
4898
4919
return function
4899
4920
@@ -4906,11 +4927,7 @@ def to_required(self, function: Function) -> None:
4906
4927
for p in function .parameters .values ():
4907
4928
p .group = - p .group
4908
4929
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 :
4914
4931
if not self .valid_line (line ):
4915
4932
return function
4916
4933
@@ -4922,17 +4939,13 @@ def state_parameter(
4922
4939
indent = self .indent .infer (line )
4923
4940
if indent == - 1 :
4924
4941
# 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 )
4929
4944
4930
4945
if indent == 1 :
4931
4946
# 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 )
4936
4949
4937
4950
line = line .rstrip ()
4938
4951
if line .endswith ('\\ ' ):
@@ -5323,15 +5336,14 @@ def parse_slash(self, function: Function) -> None:
5323
5336
"positional-only parameters, which is unsupported." )
5324
5337
p .kind = inspect .Parameter .POSITIONAL_ONLY
5325
5338
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
5328
5341
) -> Function :
5329
- assert function is not None
5330
5342
assert self .indent .margin is not None , "self.margin.infer() has not yet been called to set the margin"
5331
5343
self .parameter_docstring_indent = len (self .indent .margin )
5332
5344
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 )
5335
5347
5336
5348
def docstring_append (self , obj : Function | Parameter , line : str ) -> None :
5337
5349
"""Add a rstripped line to the current docstring."""
@@ -5350,11 +5362,9 @@ def docstring_append(self, obj: Function | Parameter, line: str) -> None:
5350
5362
# every line of the docstring must start with at least F spaces,
5351
5363
# where F > P.
5352
5364
# 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
5355
5367
) -> Function :
5356
- assert function is not None
5357
-
5358
5368
if not self .valid_line (line ):
5359
5369
return function
5360
5370
@@ -5364,25 +5374,19 @@ def state_parameter_docstring(
5364
5374
assert self .indent .depth < 3
5365
5375
if self .indent .depth == 2 :
5366
5376
# 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 )
5369
5379
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 )
5374
5382
5375
5383
assert function .parameters
5376
5384
last_param = next (reversed (function .parameters .values ()))
5377
5385
self .docstring_append (last_param , line )
5378
5386
return function
5379
5387
5380
5388
# 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 :
5386
5390
if self .group :
5387
5391
fail (f"Function { function .name !r} has a ']' without a matching '['." )
5388
5392
0 commit comments