cython

Форк
0
/
MatchCaseNodes.py 
259 строк · 7.6 Кб
1
# Nodes for structural pattern matching.
2
#
3
# In a separate file because they're unlikely to be useful for much else.
4

5
from .Nodes import Node, StatNode, ErrorNode
6
from .Errors import error
7

8

9
class MatchNode(StatNode):
10
    """
11
    subject  ExprNode    The expression to be matched
12
    cases    [MatchCaseNode]  list of cases
13
    """
14

15
    child_attrs = ["subject", "cases"]
16

17
    def validate_irrefutable(self):
18
        found_irrefutable_case = None
19
        for case in self.cases:
20
            if isinstance(case, ErrorNode):
21
                # This validation happens before error nodes have been
22
                # transformed into actual errors, so we need to ignore them
23
                continue
24
            if found_irrefutable_case:
25
                error(
26
                    found_irrefutable_case.pos,
27
                    f"{found_irrefutable_case.pattern.irrefutable_message()} makes remaining patterns unreachable"
28
                )
29
                break
30
            if case.is_irrefutable():
31
                found_irrefutable_case = case
32
            case.validate_irrefutable()
33

34
    def analyse_expressions(self, env):
35
        error(self.pos, "Structural pattern match is not yet implemented")
36
        return self
37

38

39
class MatchCaseNode(Node):
40
    """
41
    pattern    PatternNode
42
    body       StatListNode
43
    guard      ExprNode or None
44
    """
45

46
    child_attrs = ["pattern", "body", "guard"]
47

48
    def is_irrefutable(self):
49
        if isinstance(self.pattern, ErrorNode):
50
            return True  # value doesn't really matter
51
        return self.pattern.is_irrefutable() and not self.guard
52

53
    def validate_targets(self):
54
        if isinstance(self.pattern, ErrorNode):
55
            return
56
        self.pattern.get_targets()
57

58
    def validate_irrefutable(self):
59
        if isinstance(self.pattern, ErrorNode):
60
            return
61
        self.pattern.validate_irrefutable()
62

63

64
class PatternNode(Node):
65
    """
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
69
    times.
70

71
    as_targets   [NameNode]    any target assign by "as"
72
    """
73

74
    child_attrs = ["as_targets"]
75

76
    def __init__(self, pos, **kwds):
77
        if "as_targets" not in kwds:
78
            kwds["as_targets"] = []
79
        super(PatternNode, self).__init__(pos, **kwds)
80

81
    def is_irrefutable(self):
82
        return False
83

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)
88
        return targets
89

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)
94

95
    def add_target_to_targets(self, targets, target):
96
        if target in targets:
97
            error(self.pos, f"multiple assignments to name '{target}' in pattern")
98
        targets.add(target)
99

100
    def get_main_pattern_targets(self):
101
        # exclude "as" target
102
        raise NotImplementedError
103

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()
109

110

111
class MatchValuePatternNode(PatternNode):
112
    """
113
    value   ExprNode        # todo be more specific
114
    is_is_check   bool     Picks "is" or equality check
115
    """
116

117
    child_attrs = PatternNode.child_attrs + ["value"]
118
    is_is_check = False
119

120
    def get_main_pattern_targets(self):
121
        return set()
122

123

124
class MatchAndAssignPatternNode(PatternNode):
125
    """
126
    target   NameNode or None  the target to assign to (None = wildcard)
127
    is_star  bool
128
    """
129

130
    target = None
131
    is_star = False
132

133
    child_atts = PatternNode.child_attrs + ["target"]
134

135
    def is_irrefutable(self):
136
        return not self.is_star
137

138
    def irrefutable_message(self):
139
        if self.target:
140
            return "name capture '%s'" % self.target.name
141
        else:
142
            return "wildcard"
143

144
    def get_main_pattern_targets(self):
145
        if self.target:
146
            return {self.target.name}
147
        else:
148
            return set()
149

150

151
class OrPatternNode(PatternNode):
152
    """
153
    alternatives   list of PatternNodes
154
    """
155

156
    child_attrs = PatternNode.child_attrs + ["alternatives"]
157

158
    def get_first_irrefutable(self):
159
        for alternative in self.alternatives:
160
            if alternative.is_irrefutable():
161
                return alternative
162
        return None
163

164
    def is_irrefutable(self):
165
        return self.get_first_irrefutable() is not None
166

167
    def irrefutable_message(self):
168
        return self.get_first_irrefutable().irrefutable_message()
169

170
    def get_main_pattern_targets(self):
171
        child_targets = None
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
177
        return child_targets
178

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:
184
                error(
185
                    found_irrefutable_case.pos,
186
                    f"{found_irrefutable_case.irrefutable_message()} makes remaining patterns unreachable"
187
                )
188
                break
189
            if alternative.is_irrefutable():
190
                found_irrefutable_case = alternative
191
            alternative.validate_irrefutable()
192

193

194
class MatchSequencePatternNode(PatternNode):
195
    """
196
    patterns   list of PatternNodes
197
    """
198

199
    child_attrs = PatternNode.child_attrs + ["patterns"]
200

201
    def get_main_pattern_targets(self):
202
        targets = set()
203
        for pattern in self.patterns:
204
            self.update_targets_with_targets(targets, pattern.get_targets())
205
        return targets
206

207

208
class MatchMappingPatternNode(PatternNode):
209
    """
210
    keys   list of NameNodes
211
    value_patterns  list of PatternNodes of equal length to keys
212
    double_star_capture_target  NameNode or None
213
    """
214

215
    keys = []
216
    value_patterns = []
217
    double_star_capture_target = None
218

219
    child_attrs = PatternNode.child_attrs + [
220
        "keys",
221
        "value_patterns",
222
        "double_star_capture_target",
223
    ]
224

225
    def get_main_pattern_targets(self):
226
        targets = set()
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)
231
        return targets
232

233

234
class ClassPatternNode(PatternNode):
235
    """
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)
241
    """
242

243
    class_ = None
244
    positional_patterns = []
245
    keyword_pattern_names = []
246
    keyword_pattern_patterns = []
247

248
    child_attrs = PatternNode.child_attrs + [
249
        "class_",
250
        "positional_patterns",
251
        "keyword_pattern_names",
252
        "keyword_pattern_patterns",
253
    ]
254

255
    def get_main_pattern_targets(self):
256
        targets = set()
257
        for pattern in self.positional_patterns + self.keyword_pattern_patterns:
258
            self.update_targets_with_targets(targets, pattern.get_targets())
259
        return targets
260

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.