@@ -4294,6 +4294,37 @@ def dedent(self, line):
4294
4294
StateKeeper = Callable [[str | None ], None ]
4295
4295
ConverterArgs = dict [str , Any ]
4296
4296
4297
+ class ParamState (enum .IntEnum ):
4298
+ """Parameter parsing state.
4299
+
4300
+ [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] <- line
4301
+ 01 2 3 4 5 6 <- state transitions
4302
+ """
4303
+ # Before we've seen anything.
4304
+ # Legal transitions: to LEFT_SQUARE_BEFORE or REQUIRED
4305
+ START = 0
4306
+
4307
+ # Left square backets before required params.
4308
+ LEFT_SQUARE_BEFORE = 1
4309
+
4310
+ # In a group, before required params.
4311
+ GROUP_BEFORE = 2
4312
+
4313
+ # Required params, positional-or-keyword or positional-only (we
4314
+ # don't know yet). Renumber left groups!
4315
+ REQUIRED = 3
4316
+
4317
+ # Positional-or-keyword or positional-only params that now must have
4318
+ # default values.
4319
+ OPTIONAL = 4
4320
+
4321
+ # In a group, after required params.
4322
+ GROUP_AFTER = 5
4323
+
4324
+ # Right square brackets after required params.
4325
+ RIGHT_SQUARE_AFTER = 6
4326
+
4327
+
4297
4328
class DSLParser :
4298
4329
function : Function | None
4299
4330
state : StateKeeper
@@ -4331,7 +4362,7 @@ def reset(self) -> None:
4331
4362
self .keyword_only = False
4332
4363
self .positional_only = False
4333
4364
self .group = 0
4334
- self .parameter_state = self . ps_start
4365
+ self .parameter_state : ParamState = ParamState . START
4335
4366
self .seen_positional_with_default = False
4336
4367
self .indent = IndentStack ()
4337
4368
self .kind = CALLABLE
@@ -4726,22 +4757,8 @@ def state_modulename_name(self, line: str | None) -> None:
4726
4757
#
4727
4758
# These rules are enforced with a single state variable:
4728
4759
# "parameter_state". (Previously the code was a miasma of ifs and
4729
- # separate boolean state variables.) The states are:
4730
- #
4731
- # [ [ a, b, ] c, ] d, e, f=3, [ g, h, [ i ] ] <- line
4732
- # 01 2 3 4 5 6 <- state transitions
4733
- #
4734
- # 0: ps_start. before we've seen anything. legal transitions are to 1 or 3.
4735
- # 1: ps_left_square_before. left square brackets before required parameters.
4736
- # 2: ps_group_before. in a group, before required parameters.
4737
- # 3: ps_required. required parameters, positional-or-keyword or positional-only
4738
- # (we don't know yet). (renumber left groups!)
4739
- # 4: ps_optional. positional-or-keyword or positional-only parameters that
4740
- # now must have default values.
4741
- # 5: ps_group_after. in a group, after required parameters.
4742
- # 6: ps_right_square_after. right square brackets after required parameters.
4743
- ps_start , ps_left_square_before , ps_group_before , ps_required , \
4744
- ps_optional , ps_group_after , ps_right_square_after = range (7 )
4760
+ # separate boolean state variables.) The states are defined in the
4761
+ # ParamState class.
4745
4762
4746
4763
def state_parameters_start (self , line : str | None ) -> None :
4747
4764
if not self .valid_line (line ):
@@ -4759,8 +4776,8 @@ def to_required(self):
4759
4776
"""
4760
4777
Transition to the "required" parameter state.
4761
4778
"""
4762
- if self .parameter_state != self . ps_required :
4763
- self .parameter_state = self . ps_required
4779
+ if self .parameter_state is not ParamState . REQUIRED :
4780
+ self .parameter_state = ParamState . REQUIRED
4764
4781
for p in self .function .parameters .values ():
4765
4782
p .group = - p .group
4766
4783
@@ -4793,17 +4810,18 @@ def state_parameter(self, line):
4793
4810
self .parse_special_symbol (line )
4794
4811
return
4795
4812
4796
- if self .parameter_state in (self .ps_start , self .ps_required ):
4797
- self .to_required ()
4798
- elif self .parameter_state == self .ps_left_square_before :
4799
- self .parameter_state = self .ps_group_before
4800
- elif self .parameter_state == self .ps_group_before :
4801
- if not self .group :
4813
+ match self .parameter_state :
4814
+ case ParamState .START | ParamState .REQUIRED :
4802
4815
self .to_required ()
4803
- elif self .parameter_state in (self .ps_group_after , self .ps_optional ):
4804
- pass
4805
- else :
4806
- fail ("Function " + self .function .name + " has an unsupported group configuration. (Unexpected state " + str (self .parameter_state ) + ".a)" )
4816
+ case ParamState .LEFT_SQUARE_BEFORE :
4817
+ self .parameter_state = ParamState .GROUP_BEFORE
4818
+ case ParamState .GROUP_BEFORE :
4819
+ if not self .group :
4820
+ self .to_required ()
4821
+ case ParamState .GROUP_AFTER | ParamState .OPTIONAL :
4822
+ pass
4823
+ case st :
4824
+ fail (f"Function { self .function .name } has an unsupported group configuration. (Unexpected state { st } .a)" )
4807
4825
4808
4826
# handle "as" for parameters too
4809
4827
c_name = None
@@ -4863,8 +4881,9 @@ def state_parameter(self, line):
4863
4881
name , legacy , kwargs = self .parse_converter (parameter .annotation )
4864
4882
4865
4883
if not default :
4866
- if self .parameter_state == self .ps_optional :
4867
- fail ("Can't have a parameter without a default (" + repr (parameter_name ) + ")\n after a parameter with a default!" )
4884
+ if self .parameter_state is ParamState .OPTIONAL :
4885
+ fail (f"Can't have a parameter without a default ({ parameter_name !r} )\n "
4886
+ "after a parameter with a default!" )
4868
4887
if is_vararg :
4869
4888
value = NULL
4870
4889
kwargs .setdefault ('c_default' , "NULL" )
@@ -4876,8 +4895,8 @@ def state_parameter(self, line):
4876
4895
if is_vararg :
4877
4896
fail ("Vararg can't take a default value!" )
4878
4897
4879
- if self .parameter_state == self . ps_required :
4880
- self .parameter_state = self . ps_optional
4898
+ if self .parameter_state is ParamState . REQUIRED :
4899
+ self .parameter_state = ParamState . OPTIONAL
4881
4900
default = default .strip ()
4882
4901
bad = False
4883
4902
ast_input = f"x = { default } "
@@ -5001,22 +5020,22 @@ def bad_node(self, node):
5001
5020
5002
5021
if isinstance (converter , self_converter ):
5003
5022
if len (self .function .parameters ) == 1 :
5004
- if ( self .parameter_state != self . ps_required ) :
5023
+ if self .parameter_state is not ParamState . REQUIRED :
5005
5024
fail ("A 'self' parameter cannot be marked optional." )
5006
5025
if value is not unspecified :
5007
5026
fail ("A 'self' parameter cannot have a default value." )
5008
5027
if self .group :
5009
5028
fail ("A 'self' parameter cannot be in an optional group." )
5010
5029
kind = inspect .Parameter .POSITIONAL_ONLY
5011
- self .parameter_state = self . ps_start
5030
+ self .parameter_state = ParamState . START
5012
5031
self .function .parameters .clear ()
5013
5032
else :
5014
5033
fail ("A 'self' parameter, if specified, must be the very first thing in the parameter block." )
5015
5034
5016
5035
if isinstance (converter , defining_class_converter ):
5017
5036
_lp = len (self .function .parameters )
5018
5037
if _lp == 1 :
5019
- if ( self .parameter_state != self . ps_required ) :
5038
+ if self .parameter_state is not ParamState . REQUIRED :
5020
5039
fail ("A 'defining_class' parameter cannot be marked optional." )
5021
5040
if value is not unspecified :
5022
5041
fail ("A 'defining_class' parameter cannot have a default value." )
@@ -5065,12 +5084,13 @@ def parse_special_symbol(self, symbol):
5065
5084
fail ("Function " + self .function .name + " uses '*' more than once." )
5066
5085
self .keyword_only = True
5067
5086
elif symbol == '[' :
5068
- if self .parameter_state in (self .ps_start , self .ps_left_square_before ):
5069
- self .parameter_state = self .ps_left_square_before
5070
- elif self .parameter_state in (self .ps_required , self .ps_group_after ):
5071
- self .parameter_state = self .ps_group_after
5072
- else :
5073
- fail ("Function " + self .function .name + " has an unsupported group configuration. (Unexpected state " + str (self .parameter_state ) + ".b)" )
5087
+ match self .parameter_state :
5088
+ case ParamState .START | ParamState .LEFT_SQUARE_BEFORE :
5089
+ self .parameter_state = ParamState .LEFT_SQUARE_BEFORE
5090
+ case ParamState .REQUIRED | ParamState .GROUP_AFTER :
5091
+ self .parameter_state = ParamState .GROUP_AFTER
5092
+ case st :
5093
+ fail (f"Function { self .function .name } has an unsupported group configuration. (Unexpected state { st } .b)" )
5074
5094
self .group += 1
5075
5095
self .function .docstring_only = True
5076
5096
elif symbol == ']' :
@@ -5079,20 +5099,27 @@ def parse_special_symbol(self, symbol):
5079
5099
if not any (p .group == self .group for p in self .function .parameters .values ()):
5080
5100
fail ("Function " + self .function .name + " has an empty group.\n All groups must contain at least one parameter." )
5081
5101
self .group -= 1
5082
- if self .parameter_state in (self .ps_left_square_before , self .ps_group_before ):
5083
- self .parameter_state = self .ps_group_before
5084
- elif self .parameter_state in (self .ps_group_after , self .ps_right_square_after ):
5085
- self .parameter_state = self .ps_right_square_after
5086
- else :
5087
- fail ("Function " + self .function .name + " has an unsupported group configuration. (Unexpected state " + str (self .parameter_state ) + ".c)" )
5102
+ match self .parameter_state :
5103
+ case ParamState .LEFT_SQUARE_BEFORE | ParamState .GROUP_BEFORE :
5104
+ self .parameter_state = ParamState .GROUP_BEFORE
5105
+ case ParamState .GROUP_AFTER | ParamState .RIGHT_SQUARE_AFTER :
5106
+ self .parameter_state = ParamState .RIGHT_SQUARE_AFTER
5107
+ case st :
5108
+ fail (f"Function { self .function .name } has an unsupported group configuration. (Unexpected state { st } .c)" )
5088
5109
elif symbol == '/' :
5089
5110
if self .positional_only :
5090
5111
fail ("Function " + self .function .name + " uses '/' more than once." )
5091
5112
self .positional_only = True
5092
- # ps_required and ps_optional are allowed here, that allows positional-only without option groups
5113
+ # REQUIRED and OPTIONAL are allowed here, that allows positional-only without option groups
5093
5114
# to work (and have default values!)
5094
- if (self .parameter_state not in (self .ps_required , self .ps_optional , self .ps_right_square_after , self .ps_group_before )) or self .group :
5095
- fail ("Function " + self .function .name + " has an unsupported group configuration. (Unexpected state " + str (self .parameter_state ) + ".d)" )
5115
+ allowed = {
5116
+ ParamState .REQUIRED ,
5117
+ ParamState .OPTIONAL ,
5118
+ ParamState .RIGHT_SQUARE_AFTER ,
5119
+ ParamState .GROUP_BEFORE ,
5120
+ }
5121
+ if (self .parameter_state not in allowed ) or self .group :
5122
+ fail (f"Function { self .function .name } has an unsupported group configuration. (Unexpected state { self .parameter_state } .d)" )
5096
5123
if self .keyword_only :
5097
5124
fail ("Function " + self .function .name + " mixes keyword-only and positional-only parameters, which is unsupported." )
5098
5125
# fixup preceding parameters
0 commit comments