5
from .Nodes import Node, StatNode, ErrorNode
6
from .Errors import error
9
class MatchNode(StatNode):
11
subject ExprNode The expression to be matched
12
cases [MatchCaseNode] list of cases
15
child_attrs = ["subject", "cases"]
17
def validate_irrefutable(self):
18
found_irrefutable_case = None
19
for case in self.cases:
20
if isinstance(case, ErrorNode):
24
if found_irrefutable_case:
26
found_irrefutable_case.pos,
27
f"{found_irrefutable_case.pattern.irrefutable_message()} makes remaining patterns unreachable"
30
if case.is_irrefutable():
31
found_irrefutable_case = case
32
case.validate_irrefutable()
34
def analyse_expressions(self, env):
35
error(self.pos, "Structural pattern match is not yet implemented")
39
class MatchCaseNode(Node):
43
guard ExprNode or None
46
child_attrs = ["pattern", "body", "guard"]
48
def is_irrefutable(self):
49
if isinstance(self.pattern, ErrorNode):
51
return self.pattern.is_irrefutable() and not self.guard
53
def validate_targets(self):
54
if isinstance(self.pattern, ErrorNode):
56
self.pattern.get_targets()
58
def validate_irrefutable(self):
59
if isinstance(self.pattern, ErrorNode):
61
self.pattern.validate_irrefutable()
64
class PatternNode(Node):
66
PatternNode is not an expression because
67
it does several things (evaluating a boolean expression,
68
assignment of targets), and they need to be done at different
71
as_targets [NameNode] any target assign by "as"
74
child_attrs = ["as_targets"]
76
def __init__(self, pos, **kwds):
77
if "as_targets" not in kwds:
78
kwds["as_targets"] = []
79
super(PatternNode, self).__init__(pos, **kwds)
81
def is_irrefutable(self):
84
def get_targets(self):
85
targets = self.get_main_pattern_targets()
86
for target in self.as_targets:
87
self.add_target_to_targets(targets, target.name)
90
def update_targets_with_targets(self, targets, other_targets):
91
for name in targets.intersection(other_targets):
92
error(self.pos, f"multiple assignments to name '{name}' in pattern")
93
targets.update(other_targets)
95
def add_target_to_targets(self, targets, target):
97
error(self.pos, f"multiple assignments to name '{target}' in pattern")
100
def get_main_pattern_targets(self):
102
raise NotImplementedError
104
def validate_irrefutable(self):
105
for attr in self.child_attrs:
106
child = getattr(self, attr)
107
if child is not None and isinstance(child, PatternNode):
108
child.validate_irrefutable()
111
class MatchValuePatternNode(PatternNode):
113
value ExprNode # todo be more specific
114
is_is_check bool Picks "is" or equality check
117
child_attrs = PatternNode.child_attrs + ["value"]
120
def get_main_pattern_targets(self):
124
class MatchAndAssignPatternNode(PatternNode):
126
target NameNode or None the target to assign to (None = wildcard)
133
child_atts = PatternNode.child_attrs + ["target"]
135
def is_irrefutable(self):
136
return not self.is_star
138
def irrefutable_message(self):
140
return "name capture '%s'" % self.target.name
144
def get_main_pattern_targets(self):
146
return {self.target.name}
151
class OrPatternNode(PatternNode):
153
alternatives list of PatternNodes
156
child_attrs = PatternNode.child_attrs + ["alternatives"]
158
def get_first_irrefutable(self):
159
for alternative in self.alternatives:
160
if alternative.is_irrefutable():
164
def is_irrefutable(self):
165
return self.get_first_irrefutable() is not None
167
def irrefutable_message(self):
168
return self.get_first_irrefutable().irrefutable_message()
170
def get_main_pattern_targets(self):
172
for alternative in self.alternatives:
173
alternative_targets = alternative.get_targets()
174
if child_targets is not None and child_targets != alternative_targets:
175
error(self.pos, "alternative patterns bind different names")
176
child_targets = alternative_targets
179
def validate_irrefutable(self):
180
super(OrPatternNode, self).validate_irrefutable()
181
found_irrefutable_case = None
182
for alternative in self.alternatives:
183
if found_irrefutable_case:
185
found_irrefutable_case.pos,
186
f"{found_irrefutable_case.irrefutable_message()} makes remaining patterns unreachable"
189
if alternative.is_irrefutable():
190
found_irrefutable_case = alternative
191
alternative.validate_irrefutable()
194
class MatchSequencePatternNode(PatternNode):
196
patterns list of PatternNodes
199
child_attrs = PatternNode.child_attrs + ["patterns"]
201
def get_main_pattern_targets(self):
203
for pattern in self.patterns:
204
self.update_targets_with_targets(targets, pattern.get_targets())
208
class MatchMappingPatternNode(PatternNode):
210
keys list of NameNodes
211
value_patterns list of PatternNodes of equal length to keys
212
double_star_capture_target NameNode or None
217
double_star_capture_target = None
219
child_attrs = PatternNode.child_attrs + [
222
"double_star_capture_target",
225
def get_main_pattern_targets(self):
227
for pattern in self.value_patterns:
228
self.update_targets_with_targets(targets, pattern.get_targets())
229
if self.double_star_capture_target:
230
self.add_target_to_targets(targets, self.double_star_capture_target.name)
234
class ClassPatternNode(PatternNode):
236
class_ NameNode or AttributeNode
237
positional_patterns list of PatternNodes
238
keyword_pattern_names list of NameNodes
239
keyword_pattern_patterns list of PatternNodes
240
(same length as keyword_pattern_names)
244
positional_patterns = []
245
keyword_pattern_names = []
246
keyword_pattern_patterns = []
248
child_attrs = PatternNode.child_attrs + [
250
"positional_patterns",
251
"keyword_pattern_names",
252
"keyword_pattern_patterns",
255
def get_main_pattern_targets(self):
257
for pattern in self.positional_patterns + self.keyword_pattern_patterns:
258
self.update_targets_with_targets(targets, pattern.get_targets())