@@ -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
@@ -4795,17 +4812,18 @@ def state_parameter(self, line: str | None) -> None:
4795
4812
self .parse_special_symbol (line )
4796
4813
return
4797
4814
4798
- if self .parameter_state in (self .ps_start , self .ps_required ):
4799
- self .to_required ()
4800
- elif self .parameter_state == self .ps_left_square_before :
4801
- self .parameter_state = self .ps_group_before
4802
- elif self .parameter_state == self .ps_group_before :
4803
- if not self .group :
4815
+ match self .parameter_state :
4816
+ case ParamState .START |
9E88
ParamState .REQUIRED :
4804
4817
self .to_required ()
4805
- elif self .parameter_state in (self .ps_group_after , self .ps_optional ):
4806
- pass
4807
- else :
4808
- fail ("Function " + self .function .name + " has an unsupported group configuration. (Unexpected state " + str (self .parameter_state ) + ".a)" )
4818
+ case ParamState .LEFT_SQUARE_BEFORE :
4819
+ self .parameter_state = ParamState .GROUP_BEFORE
4820
+ case ParamState .GROUP_BEFORE :
4821
+ if not self .group :
4822
+ self .to_required ()
4823
+ case ParamState .GROUP_AFTER | ParamState .OPTIONAL :
4824
+ pass
4825
+ case st :
4826
+ fail (f"Function { self .function .name } has an unsupported group configuration. (Unexpected state { st } .a)" )
4809
4827
4810
4828
# handle "as" for parameters too
4811
4829
c_name = None
@@ -4866,8 +4884,9 @@ def state_parameter(self, line: str | None) -> None:
4866
4884
name , legacy , kwargs = self .parse_converter (parameter .annotation )
4867
4885
4868
4886
if not default :
4869
- if self .parameter_state == self .ps_optional :
4870
- fail ("Can't have a parameter without a default (" + repr (parameter_name ) + ")\n after a parameter with a default!" )
4887
+ if self .parameter_state is ParamState .OPTIONAL :
4888
+ fail (f"Can't have a parameter without a default ({ parameter_name !r} )\n "
4889
+ "after a parameter with a default!" )
4871
4890
value : Sentinels | Null
4872
4891
if is_vararg :
4873
4892
value = NULL
@@ -4880,8 +4899,8 @@ def state_parameter(self, line: str | None) -> None:
4880
4899
if is_vararg :
4881
4900
fail ("Vararg can't take a default value!" )
4882
4901
4883
- if self .parameter_state == self . ps_required :
4884
- self .parameter_state = self . ps_optional
4902
+ if self .parameter_state is ParamState . REQUIRED :
4903
+ self .parameter_state = ParamState . OPTIONAL
4885
4904
default = default .strip ()
4886
4905
bad = False
4887
4906
ast_input = f"x = { default } "
@@ -5007,22 +5026,22 @@ def bad_node(self, node):
5007
5026
5008
5027
if isinstance (converter , self_converter ):
5009
5028
if len (self .function .parameters ) == 1 :
5010
- if ( self .parameter_state != self . ps_required ) :
5029
+ if self .parameter_state is not ParamState . REQUIRED :
5011
5030
fail ("A 'self' parameter cannot be marked optional." )
5012
5031
if value is not unspecified :
5013
5032
fail ("A 'self' parameter cannot have a default value." )
5014
5033
if self .group :
5015
5034
fail ("A 'self' parameter cannot be in an optional group." )
5016
5035
kind = inspect .Parameter .POSITIONAL_ONLY
5017
- self .parameter_state = self . ps_start
5036
+ self .parameter_state = ParamState . START
5018
5037
self .function .parameters .clear ()
5019
5038
else :
5020
5039
fail ("A 'self' parameter, if specified, must be the very first thing in the parameter block." )
5021
5040
5022
5041
if isinstance (converter , defining_class_converter ):
5023
5042
_lp = len (self .function .parameters )
5024
5043
if _lp == 1 :
5025
- if ( self .parameter_state != self . ps_required ) :
5044
+ if self .parameter_state is not ParamState . REQUIRED :
5026
5045
fail ("A 'defining_class' parameter cannot be marked optional." )
5027
5046
if value is not unspecified :
5028
5047
fail ("A 'defining_class' parameter cannot have a default value." )
@@ -5071,12 +5090,13 @@ def parse_special_symbol(self, symbol):
5071
5090
fail ("Function " + self .function .name + " uses '*' more than once." )
5072
5091
self .keyword_only = True
5073
5092
elif symbol == '[' :
5074
- if self .parameter_state in (self .ps_start , self .ps_left_square_before ):
5075
- self .parameter_state = self .ps_left_square_before
5076
- elif self .parameter_state in (self .ps_required , self .ps_group_after ):
5077
- self .parameter_state = self .ps_group_after
5078
- else :
5079
- fail ("Function " + self .function .name + " has an unsupported group configuration. (Unexpected state " + str (self .parameter_state ) + ".b)" )
5093
+ match self .parameter_state :
5094
+ case ParamState .START | ParamState .LEFT_SQUARE_BEFORE :
5095
+ self .parameter_state = ParamState .LEFT_SQUARE_BEFORE
5096
+ case ParamState .REQUIRED | ParamState .GROUP_AFTER :
5097
+ self .parameter_state = ParamState .GROUP_AFTER
5098
+ case st :
5099
+ fail (f"Function { self .function .name } has an unsupported group configuration. (Unexpected state { st } .b)" )
5080
5100
self .group += 1
5081
5101
self .function .docstring_only = True
5082
5102
elif symbol == ']' :
@@ -5085,20 +5105,27 @@ def parse_special_symbol(self, symbol):
5085
5105
if not any (p .group == self .group for p in self .function .parameters .values ()):
5086
5106
fail ("Function " + self .function .name + " has an empty group.\n All groups must contain at least one parameter." )
5087
5107
self .group -= 1
5088
- if self .parameter_state in (self .ps_left_square_before , self .ps_group_before ):
5089
- self .parameter_state = self .ps_group_before
5090
- elif self .parameter_state in (self .ps_group_after , self .ps_right_square_after ):
5091
- self .parameter_state = self .ps_right_square_after
5092
- else :
5093
- fail ("Function " + self .function .name + " has an unsupported group configuration. (Unexpected state " + str (self .parameter_state ) + ".c)" )
5108
+ match self .parameter_state :
5109
+ case ParamState .LEFT_SQUARE_BEFORE | ParamState .GROUP_BEFORE :
5110
+ self .parameter_state = ParamState .GROUP_BEFORE
5111
+ case ParamState .GROUP_AFTER | ParamState .RIGHT_SQUARE_AFTER :
5112
+ self .parameter_state = ParamState .RIGHT_SQUARE_AFTER
5113
+ case st :
5114
+ fail (f"Function { self .function .name } has an unsupported group configuration. (Unexpected state { st } .c)" )
5094
5115
elif symbol == '/' :
5095
5116
if self .positional_only :
5096
5117
fail ("Function " + self .function .name + " uses '/' more than once." )
5097
5118
self .positional_only = True
5098
- # ps_required and ps_optional are allowed here, that allows positional-only without option groups
5119
+ # REQUIRED and OPTIONAL are allowed here, that allows positional-only without option groups
5099
5120
# to work (and have default values!)
5100
- if (self .parameter_state not in (self .ps_required , self .ps_optional , self .ps_right_square_after , self .ps_group_before )) or self .group :
5101
- fail ("Function " + self .function .name + " has an unsupported group configuration. (Unexpected state " + str (self .parameter_state ) + ".d)" )
5121
+ allowed = {
5122
+ ParamState .REQUIRED ,
5123
+ ParamState .OPTIONAL ,
5124
+ ParamState .RIGHT_SQUARE_AFTER ,
5125
+ ParamState .GROUP_BEFORE ,
5126
+ }
5127
+ if (self .parameter_state not in allowed ) or self .group :
5128
+ fail (f"Function { self .function .name } has an unsupported group configuration. (Unexpected state { self .parameter_state } .d)" )
5102
5129
if self .keyword_only :
5103
5130
fail ("Function " + self .function .name + " mixes keyword-only and positional-only parameters, which is unsupported." )
5104
5131
# fixup preceding parameters
0 commit comments