-
Notifications
You must be signed in to change notification settings - Fork 1.5k
/
pattern.h
484 lines (401 loc) · 17 KB
/
pattern.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef CARBON_EXPLORER_AST_PATTERN_H_
#define CARBON_EXPLORER_AST_PATTERN_H_
#include <optional>
#include <string>
#include <vector>
#include "common/check.h"
#include "common/ostream.h"
#include "explorer/ast/ast_node.h"
#include "explorer/ast/ast_rtti.h"
#include "explorer/ast/clone_context.h"
#include "explorer/ast/expression.h"
#include "explorer/ast/expression_category.h"
#include "explorer/ast/value_node.h"
#include "explorer/base/source_location.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/STLFunctionalExtras.h"
namespace Carbon {
class Value;
// Abstract base class of all AST nodes representing patterns.
//
// Pattern and its derived classes support LLVM-style RTTI, including
// llvm::isa, llvm::cast, and llvm::dyn_cast. To support this, every
// class derived from Pattern must provide a `classof` operation, and
// every concrete derived class must have a corresponding enumerator
// in `Kind`; see https://llvm.org/docs/HowToSetUpLLVMStyleRTTI.html for
// details.
class Pattern : public AstNode {
public:
explicit Pattern(CloneContext& context, const Pattern& other)
: AstNode(context, other),
static_type_(context.Clone(other.static_type_)),
value_(context.Clone(other.value_)) {}
Pattern(const Pattern&) = delete;
auto operator=(const Pattern&) -> Pattern& = delete;
~Pattern() override = 0;
void Print(llvm::raw_ostream& out) const override;
void PrintID(llvm::raw_ostream& out) const override;
static auto classof(const AstNode* node) -> bool {
return InheritsFromPattern(node->kind());
}
// Returns the enumerator corresponding to the most-derived type of this
// object.
auto kind() const -> PatternKind {
return static_cast<PatternKind>(root_kind());
}
// The static type of this pattern. Cannot be called before typechecking.
auto static_type() const -> const Value& {
CARBON_CHECK(static_type_.has_value());
return **static_type_;
}
auto has_static_type() const -> bool { return static_type_.has_value(); }
// Sets the static type of this expression. Can only be called once, during
// typechecking.
void set_static_type(Nonnull<const Value*> type) {
CARBON_CHECK(!static_type_.has_value());
static_type_ = type;
}
// The value of this pattern. Cannot be called before typechecking.
// TODO: Rename to avoid confusion with BindingPattern::constant_value
auto value() const -> const Value& { return **value_; }
// Sets the value of this pattern. Can only be called once, during
// typechecking.
void set_value(Nonnull<const Value*> value) {
CARBON_CHECK(!value_, "set_value called more than once");
value_ = value;
}
// Returns whether the value has been set. Should only be called
// during typechecking: before typechecking it's guaranteed to be false,
// and after typechecking it's guaranteed to be true.
auto has_value() const -> bool { return value_.has_value(); }
// Determines whether the pattern has already been type-checked. Should
// only be used by type-checking.
auto is_type_checked() const -> bool {
return static_type_.has_value() && value_.has_value();
}
protected:
// Constructs a Pattern representing syntax at the given line number.
// `kind` must be the enumerator corresponding to the most-derived type being
// constructed.
Pattern(AstNodeKind kind, SourceLocation source_loc)
: AstNode(kind, source_loc) {}
private:
std::optional<Nonnull<const Value*>> static_type_;
std::optional<Nonnull<const Value*>> value_;
};
// Call the given `visitor` on all patterns nested within the given pattern,
// including `pattern` itself, in a preorder traversal. Aborts and returns
// `false` if `visitor` returns `false`, otherwise returns `true`.
auto VisitNestedPatterns(const Pattern& pattern,
llvm::function_ref<bool(const Pattern&)> visitor)
-> bool;
inline auto VisitNestedPatterns(Pattern& pattern,
llvm::function_ref<bool(Pattern&)> visitor)
-> bool {
// The non-const version is implemented in terms of the const version. The
// const_cast is safe because every pattern reachable through a non-const
// pattern is also non-const.
const Pattern& const_pattern = pattern;
return VisitNestedPatterns(const_pattern, [&](const Pattern& inner) {
return visitor(const_cast<Pattern&>(inner));
});
}
// A pattern consisting of the `auto` keyword.
class AutoPattern : public Pattern {
public:
explicit AutoPattern(SourceLocation source_loc)
: Pattern(AstNodeKind::AutoPattern, source_loc) {}
explicit AutoPattern(CloneContext& context, const AutoPattern& other)
: Pattern(context, other) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromAutoPattern(node->kind());
}
};
class VarPattern : public Pattern {
public:
explicit VarPattern(SourceLocation source_loc, Nonnull<Pattern*> pattern)
: Pattern(AstNodeKind::VarPattern, source_loc), pattern_(pattern) {}
explicit VarPattern(CloneContext& context, const VarPattern& other)
: Pattern(context, other), pattern_(context.Clone(other.pattern_)) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromVarPattern(node->kind());
}
auto pattern() const -> const Pattern& { return *pattern_; }
auto pattern() -> Pattern& { return *pattern_; }
auto expression_category() const -> ExpressionCategory {
return ExpressionCategory::Reference;
}
private:
Nonnull<Pattern*> pattern_;
};
// A pattern that matches a value of a specified type, and optionally binds
// a name to it.
class BindingPattern : public Pattern {
public:
using ImplementsCarbonValueNode = void;
BindingPattern(SourceLocation source_loc, std::string name,
Nonnull<Pattern*> type,
std::optional<ExpressionCategory> expression_category)
: Pattern(AstNodeKind::BindingPattern, source_loc),
name_(std::move(name)),
type_(type),
expression_category_(expression_category) {}
explicit BindingPattern(CloneContext& context, const BindingPattern& other)
: Pattern(context, other),
name_(other.name_),
type_(context.Clone(other.type_)),
expression_category_(other.expression_category_) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromBindingPattern(node->kind());
}
// The name this pattern binds, if any. If equal to AnonymousName, indicates
// that this BindingPattern does not bind a name, which in turn means it
// should not be used as a ValueNode.
auto name() const -> const std::string& { return name_; }
// The pattern specifying the type of values that this pattern matches.
auto type() const -> const Pattern& { return *type_; }
auto type() -> Pattern& { return *type_; }
// Returns the value category of this pattern. Can only be called after
// typechecking.
auto expression_category() const -> ExpressionCategory {
return expression_category_.value();
}
// Returns whether the value category has been set. Should only be called
// during typechecking.
auto has_expression_category() const -> bool {
return expression_category_.has_value();
}
// Sets the value category of the variable being bound. Can only be called
// once during typechecking
void set_expression_category(ExpressionCategory vc) {
CARBON_CHECK(!expression_category_.has_value());
expression_category_ = vc;
}
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
return std::nullopt;
}
auto symbolic_identity() const -> std::optional<Nonnull<const Value*>> {
return std::nullopt;
}
private:
std::string name_;
Nonnull<Pattern*> type_;
std::optional<ExpressionCategory> expression_category_;
};
class AddrPattern : public Pattern {
public:
explicit AddrPattern(SourceLocation source_loc,
Nonnull<BindingPattern*> binding)
: Pattern(AstNodeKind::AddrPattern, source_loc), binding_(binding) {}
explicit AddrPattern(CloneContext& context, const AddrPattern& other)
: Pattern(context, other), binding_(context.Clone(other.binding_)) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromAddrPattern(node->kind());
}
auto binding() const -> const BindingPattern& { return *binding_; }
auto binding() -> BindingPattern& { return *binding_; }
private:
Nonnull<BindingPattern*> binding_;
};
// A pattern that matches a tuple value field-wise.
class TuplePattern : public Pattern {
public:
TuplePattern(SourceLocation source_loc, std::vector<Nonnull<Pattern*>> fields)
: Pattern(AstNodeKind::TuplePattern, source_loc),
fields_(std::move(fields)) {}
explicit TuplePattern(CloneContext& context, const TuplePattern& other)
: Pattern(context, other), fields_(context.Clone(other.fields_)) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromTuplePattern(node->kind());
}
auto fields() const -> llvm::ArrayRef<Nonnull<const Pattern*>> {
return fields_;
}
auto fields() -> llvm::ArrayRef<Nonnull<Pattern*>> { return fields_; }
private:
std::vector<Nonnull<Pattern*>> fields_;
};
class GenericBinding : public Pattern {
public:
using ImplementsCarbonValueNode = void;
enum class BindingKind {
// A checked generic binding, `T:! type`.
Checked,
// A template generic binding, `template T:! type`.
Template,
};
explicit GenericBinding(SourceLocation source_loc, std::string name,
Nonnull<Expression*> type, BindingKind binding_kind)
: Pattern(AstNodeKind::GenericBinding, source_loc),
name_(std::move(name)),
type_(type),
binding_kind_(binding_kind) {}
explicit GenericBinding(CloneContext& context, const GenericBinding& other);
static auto classof(const AstNode* node) -> bool {
return InheritsFromGenericBinding(node->kind());
}
auto name() const -> const std::string& { return name_; }
auto type() const -> const Expression& { return *type_; }
auto type() -> Expression& { return *type_; }
auto binding_kind() const -> BindingKind { return binding_kind_; }
// The index of this binding, which is the number of bindings that are in
// scope at the point where this binding is declared.
auto index() const -> int {
CARBON_CHECK(index_);
return *index_;
}
// Set the index of this binding. Should be called only during type-checking.
void set_index(int index) {
CARBON_CHECK(!index_, "should only set depth and index once");
index_ = index;
}
auto expression_category() const -> ExpressionCategory {
return ExpressionCategory::Value;
}
auto constant_value() const -> std::optional<Nonnull<const Value*>> {
return template_value_;
}
auto symbolic_identity() const -> std::optional<Nonnull<const Value*>> {
return symbolic_identity_;
}
void set_symbolic_identity(Nonnull<const Value*> value) {
CARBON_CHECK(!symbolic_identity_.has_value());
symbolic_identity_ = value;
}
void set_template_value(Nonnull<const Value*> template_value) {
CARBON_CHECK(binding_kind_ == BindingKind::Template);
template_value_ = template_value;
}
auto has_template_value() const -> bool {
CARBON_CHECK(binding_kind_ == BindingKind::Template);
return template_value_.has_value();
}
// The impl binding associated with this type variable.
auto impl_binding() const -> std::optional<Nonnull<const ImplBinding*>> {
return impl_binding_;
}
// Set the impl binding.
void set_impl_binding(Nonnull<const ImplBinding*> binding) {
CARBON_CHECK(!impl_binding_.has_value());
impl_binding_ = binding;
}
// Return the original generic binding.
auto original() const -> Nonnull<const GenericBinding*> {
if (original_.has_value()) {
return *original_;
} else {
return this;
}
}
// Set the original generic binding.
void set_original(Nonnull<const GenericBinding*> orig) { original_ = orig; }
// Returns whether this binding has been named as a type within its own type
// expression via `.Self`. Set by type-checking.
auto named_as_type_via_dot_self() const -> bool {
return named_as_type_via_dot_self_;
}
// Set that this binding was named as a type within its own type expression
// via `.Self`. May only be called during type-checking.
void set_named_as_type_via_dot_self() { named_as_type_via_dot_self_ = true; }
private:
std::string name_;
Nonnull<Expression*> type_;
BindingKind binding_kind_;
std::optional<int> index_;
std::optional<Nonnull<const Value*>> template_value_;
std::optional<Nonnull<const Value*>> symbolic_identity_;
std::optional<Nonnull<const ImplBinding*>> impl_binding_;
std::optional<Nonnull<const GenericBinding*>> original_;
bool named_as_type_via_dot_self_ = false;
};
// Converts paren_contents to a Pattern, interpreting the parentheses as
// grouping if their contents permit that interpretation, or as forming a
// tuple otherwise.
auto PatternFromParenContents(Nonnull<Arena*> arena, SourceLocation source_loc,
const ParenContents<Pattern>& paren_contents)
-> Nonnull<Pattern*>;
// Converts paren_contents to a TuplePattern, interpreting the parentheses as
// forming a tuple.
auto TuplePatternFromParenContents(Nonnull<Arena*> arena,
SourceLocation source_loc,
const ParenContents<Pattern>& paren_contents)
-> Nonnull<TuplePattern*>;
// Converts `contents` to ParenContents<Pattern> by replacing each Expression
// with an ExpressionPattern.
auto ParenExpressionToParenPattern(Nonnull<Arena*> arena,
const ParenContents<Expression>& contents)
-> ParenContents<Pattern>;
// A pattern that matches an alternative of a choice type.
class AlternativePattern : public Pattern {
public:
// Constructs an AlternativePattern that matches the alternative specified
// by `alternative`, if its arguments match `arguments`.
static auto Create(Nonnull<Arena*> arena, SourceLocation source_loc,
Nonnull<Expression*> alternative,
Nonnull<TuplePattern*> arguments)
-> ErrorOr<Nonnull<AlternativePattern*>> {
CARBON_ASSIGN_OR_RETURN(
Nonnull<SimpleMemberAccessExpression*> member_access,
RequireSimpleMemberAccess(alternative));
return arena->New<AlternativePattern>(source_loc, &member_access->object(),
member_access->member_name(),
arguments);
}
// Constructs an AlternativePattern that matches a value of the type
// specified by choice_type if it represents an alternative named
// alternative_name, and its arguments match `arguments`.
AlternativePattern(SourceLocation source_loc,
Nonnull<Expression*> choice_type,
std::string alternative_name,
Nonnull<TuplePattern*> arguments)
: Pattern(AstNodeKind::AlternativePattern, source_loc),
choice_type_(choice_type),
alternative_name_(std::move(alternative_name)),
arguments_(arguments) {}
explicit AlternativePattern(CloneContext& context,
const AlternativePattern& other)
: Pattern(context, other),
choice_type_(context.Clone(other.choice_type_)),
alternative_name_(other.alternative_name_),
arguments_(context.Clone(other.arguments_)) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromAlternativePattern(node->kind());
}
auto choice_type() const -> const Expression& { return *choice_type_; }
auto choice_type() -> Expression& { return *choice_type_; }
auto alternative_name() const -> const std::string& {
return alternative_name_;
}
auto arguments() const -> const TuplePattern& { return *arguments_; }
auto arguments() -> TuplePattern& { return *arguments_; }
private:
static auto RequireSimpleMemberAccess(Nonnull<Expression*> alternative)
-> ErrorOr<Nonnull<SimpleMemberAccessExpression*>>;
Nonnull<Expression*> choice_type_;
std::string alternative_name_;
Nonnull<TuplePattern*> arguments_;
};
// A pattern that matches a value if it is equal to the value of a given
// expression.
class ExpressionPattern : public Pattern {
public:
explicit ExpressionPattern(Nonnull<Expression*> expression)
: Pattern(AstNodeKind::ExpressionPattern, expression->source_loc()),
expression_(expression) {}
explicit ExpressionPattern(CloneContext& context,
const ExpressionPattern& other)
: Pattern(context, other),
expression_(context.Clone(other.expression_)) {}
static auto classof(const AstNode* node) -> bool {
return InheritsFromExpressionPattern(node->kind());
}
auto expression() const -> const Expression& { return *expression_; }
auto expression() -> Expression& { return *expression_; }
private:
Nonnull<Expression*> expression_;
};
} // namespace Carbon
#endif // CARBON_EXPLORER_AST_PATTERN_H_