@@ -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
@@ -4611,7 +4617,7 @@ def parse(self, block: Block) -> None:
4611
4617
if '\t ' in line :
4612
4618
fail ('Tab characters are illegal in the Clinic DSL.\n \t ' + repr (line ), line_number = block_start )
4613
4619
try :
4614
- function = self .state (function , line )
4620
+ function = self .handle_line (function , line )
4615
4621
except ClinicError as exc :
4616
4622
exc .lineno = line_number
4617
4623
raise
@@ -4624,11 +4630,43 @@ def parse(self, block: Block) -> None:
4624
4630
fail ("'preserve' only works for blocks that don't produce any output!" )
4625
4631
block .output = self .saved_output
4626
4632
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
+
4627
4665
def in_docstring (self ) -> bool :
4628
4666
"""Return true if we are processing a docstring."""
4629
4667
return self .state in {
4630
- self . state_parameter_docstring ,
4631
- self . state_function_docstring ,
4668
+ DSLParserState . PARAMETER_DOCSTRING ,
4669
+ DSLParserState . FUNCTION_DOCSTRING ,
4632
4670
}
4633
4671
4634
4672
def valid_line (self , line : str ) -> bool :
@@ -4647,21 +4685,7 @@ def valid_line(self, line: str) -> bool:
4647
4685
def calculate_indent (line : str ) -> int :
4648
4686
return len (line ) - len (line .strip ())
4649
4687
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 :
4665
4689
if not self .valid_line (line ):
4666
4690
return None
4667
4691
@@ -4676,11 +4700,10 @@ def state_dsl_start(self, function: Function | None, line: str) -> Function | No
4676
4700
fail (str (e ))
4677
4701
return None
4678
4702
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 )
4680
4705
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 :
4684
4707
# looking for declaration, which establishes the leftmost column
4685
4708
# line should be
4686
4709
# modulename.fnname [as c_basename] [-> return annotation]
@@ -4697,8 +4720,6 @@ def state_modulename_name(
4697
4720
# this line is permitted to start with whitespace.
4698
4721
# we'll call this number of spaces F (for "function").
4699
4722
4700
- assert function is None
4701
-
4702
4723
if not self .valid_line (line ):
4703
4724
return None
4704
4725
@@ -4740,7 +4761,8 @@ def state_modulename_name(
4740
4761
)
4741
4762
self .block .signatures .append (function )
4742
4763
(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
4744
4766
4745
4767
line , _ , returns = line .partition ('->' )
4746
4768
returns = returns .strip ()
@@ -4821,7 +4843,8 @@ def state_modulename_name(
4821
4843
function .parameters [name ] = p_self
4822
4844
4823
4845
(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
4825
4848
4826
4849
# Now entering the parameters section. The rules, formally stated:
4827
4850
#
@@ -4878,18 +4901,16 @@ def state_modulename_name(
4878
4901
# separate boolean state variables.) The states are defined in the
4879
4902
# ParamState class.
4880
4903
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 :
4884
4905
if self .valid_line (line ):
4885
4906
# if this line is not indented, we have no parameters
4886
4907
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 )
4890
4910
else :
4891
4911
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 )
4893
4914
4894
4915
return function
4895
4916
@@ -4902,11 +4923,7 @@ def to_required(self, function: Function) -> None:
4902
4923
for p in function .parameters .values ():
4903
4924
p .group = - p .group
4904
4925
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 :
4910
4927
if not self .valid_line (line ):
4911
4928
return function
4912
4929
@@ -4918,17 +4935,13 @@ def state_parameter(
4918
4935
indent = self .indent .infer (line )
4919
4936
if indent == - 1 :
4920
4937
# 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 )
4925
4940
4926
4941
if indent == 1 :
4927
4942
# 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 )
4932
4945
4933
4946
line = line .rstrip ()
4934
4947
if line .endswith ('\\ ' ):
@@ -5318,15 +5331,14 @@ def parse_slash(self, function: Function) -> None:
5318
5331
"positional-only parameters, which is unsupported." )
5319
5332
p .kind = inspect .Parameter .POSITIONAL_ONLY
5320
5333
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
5323
5336
) -> Function :
5324
- assert function is not None
5325
5337
assert self .indent .margin is not None , "self.margin.infer() has not yet been called to set the margin"
5326
5338
self .parameter_docstring_indent = len (self .indent .margin )
5327
5339
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 )
5330
5342
5331
5343
def docstring_append (self , obj : Function | Parameter , line : str ) -> None :
5332
5344
"""Add a rstripped line to the current docstring."""
@@ -5345,11 +5357,9 @@ def docstring_append(self, obj: Function | Parameter, line: str) -> None:
5345
5357
# every line of the docstring must start with at least F spaces,
5346
5358
# where F > P.
5347
5359
# 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
5350
5362
) -> Function :
5351
- assert function is not None
5352
-
5353
5363
if not self .valid_line (line ):
5354
5364
return function
5355
5365
@@ -5359,25 +5369,19 @@ def state_parameter_docstring(
5359
5369
assert self .indent .depth < 3
5360
5370
if self .indent .depth == 2 :
5361
5371
# 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 )
5364
5374
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 )
5369
5377
5370
5378
assert function .parameters
5371
5379
last_param = next (reversed (function .parameters .values ()))
5372
5380
self .docstring_append (last_param , line )
5373
5381
return function
5374
5382
5375
5383
# 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 :
5381
5385
if self .group :
5382
5386
fail (f"Function { function .name } has a ] without a matching [." )
5383
5387
0 commit comments