8000 Merge branch 'main' into clinic/annotate-state-parameter · python/cpython@2bd134f · GitHub
[go: up one dir, main page]

Skip to content

Commit 2bd134f

Browse files
authored
Merge branch 'main' into clinic/annotate-state-parameter
2 parents fa43e47 + 71b4044 commit 2bd134f

File tree

1 file changed

+78
-51
lines changed

1 file changed

+78
-51
lines changed

Tools/clinic/clinic.py

Lines changed: 78 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -4294,6 +4294,37 @@ def dedent(self, line):
42944294
StateKeeper = Callable[[str | None], None]
42954295
ConverterArgs = dict[str, Any]
42964296

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+
42974328
class DSLParser:
42984329
function: Function | None
42994330
state: StateKeeper
@@ -4331,7 +4362,7 @@ def reset(self) -> None:
43314362
self.keyword_only = False
43324363
self.positional_only = False
43334364
self.group = 0
4334-
self.parameter_state = self.ps_start
4365+
self.parameter_state: ParamState = ParamState.START
43354366
self.seen_positional_with_default = False
43364367
self.indent = IndentStack()
43374368
self.kind = CALLABLE
@@ -4726,22 +4757,8 @@ def state_modulename_name(self, line: str | None) -> None:
47264757
#
47274758
# These rules are enforced with a single state variable:
47284759
# "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.
47454762

47464763
def state_parameters_start(self, line: str | None) -> None:
47474764
if not self.valid_line(line):
@@ -4759,8 +4776,8 @@ def to_required(self):
47594776
"""
47604777
Transition to the "required" parameter state.
47614778
"""
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
47644781
for p in self.function.parameters.values():
47654782
p.group = -p.group
47664783

@@ -4795,17 +4812,18 @@ def state_parameter(self, line: str | None) -> None:
47954812
self.parse_special_symbol(line)
47964813
return
47974814

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:
48044817
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)")
48094827

48104828
# handle "as" for parameters too
48114829
c_name = None
@@ -4866,8 +4884,9 @@ def state_parameter(self, line: str | None) -> None:
48664884
name, legacy, kwargs = self.parse_converter(parameter.annotation)
48674885

48684886
if not default:
4869-
if self.parameter_state == self.ps_optional:
4870-
fail("Can't have a parameter without a default (" + repr(parameter_name) + ")\nafter 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!")
48714890
value: Sentinels | Null
48724891
if is_vararg:
48734892
value = NULL
@@ -4880,8 +4899,8 @@ def state_parameter(self, line: str | None) -> None:
48804899
if is_vararg:
48814900
fail("Vararg can't take a default value!")
48824901

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
48854904
default = default.strip()
48864905
bad = False
48874906
ast_input = f"x = {default}"
@@ -5007,22 +5026,22 @@ def bad_node(self, node):
50075026

50085027
if isinstance(converter, self_converter):
50095028
if len(self.function.parameters) == 1:
5010-
if (self.parameter_state != self.ps_required):
5029+
if self.parameter_state is not ParamState.REQUIRED:
50115030
fail("A 'self' parameter cannot be marked optional.")
50125031
if value is not unspecified:
50135032
fail("A 'self' parameter cannot have a default value.")
50145033
if self.group:
50155034
fail("A 'self' parameter cannot be in an optional group.")
50165035
kind = inspect.Parameter.POSITIONAL_ONLY
5017-
self.parameter_state = self.ps_start
5036+
self.parameter_state = ParamState.START
50185037
self.function.parameters.clear()
50195038
else:
50205039
fail("A 'self' parameter, if specified, must be the very first thing in the parameter block.")
50215040

50225041
if isinstance(converter, defining_class_converter):
50235042
_lp = len(self.function.parameters)
50245043
if _lp == 1:
5025-
if (self.parameter_state != self.ps_required):
5044+
if self.parameter_state is not ParamState.REQUIRED:
50265045
fail("A 'defining_class' parameter cannot be marked optional.")
50275046
if value is not unspecified:
50285047
fail("A 'defining_class' parameter cannot have a default value.")
@@ -5071,12 +5090,13 @@ def parse_special_symbol(self, symbol):
50715090
fail("Function " + self.function.name + " uses '*' more than once.")
50725091
self.keyword_only = True
50735092
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)")
50805100
self.group += 1
50815101
self.function.docstring_only = True
50825102
elif symbol == ']':
@@ -5085,20 +5105,27 @@ def parse_special_symbol(self, symbol):
50855105
if not any(p.group == self.group for p in self.function.parameters.values()):
50865106
fail("Function " + self.function.name + " has an empty group.\nAll groups must contain at least one parameter.")
50875107
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)")
50945115
elif symbol == '/':
50955116
if self.positional_only:
50965117
fail("Function " + self.function.name + " uses '/' more than once.")
50975118
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
50995120
# 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)")
51025129
if self.keyword_only:
51035130
fail("Function " + self.function.name + " mixes keyword-only and positional-only parameters, which is unsupported.")
51045131
# fixup preceding parameters

0 commit comments

Comments
 (0)
0