forked from carbon-language/carbon-lang
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathelement.h
192 lines (151 loc) · 5.45 KB
/
element.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
// 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_ELEMENT_H_
#define CARBON_EXPLORER_AST_ELEMENT_H_
#include <optional>
#include <string>
#include <string_view>
#include "common/ostream.h"
#include "explorer/ast/ast_rtti.h"
#include "explorer/base/decompose.h"
#include "explorer/base/nonnull.h"
#include "llvm/ADT/PointerUnion.h"
namespace Carbon {
class Declaration;
class Value;
// A NamedValue represents a value with a name, such as a single struct field.
struct NamedValue : HashFromDecompose<NamedValue> {
NamedValue(std::string name, Nonnull<const Value*> value)
: name(std::move(name)), value(value) {}
template <typename F>
auto Decompose(F f) const {
return f(name, value);
}
// The field name.
std::string name;
// The field's value.
Nonnull<const Value*> value;
};
// A generic member of a type. This is can be a named, positional or other type
// of member.
//
// Arena's canonicalization support is enabled for Element and all derived
// types. As a result, all Elements must be immutable, and all their constructor
// arguments must be copyable, equality-comparable, and hashable. See
// Arena's documentation for details.
class Element : public Printable<Element> {
protected:
explicit Element(ElementKind kind) : kind_(kind) {}
public:
using EnableCanonicalizedAllocation = void;
virtual ~Element() = default;
// Call `f` on this value, cast to its most-derived type. `R` specifies the
// expected return type of `f`.
template <typename R, typename F>
auto Visit(F f) const -> R;
// Prints the Member
virtual void Print(llvm::raw_ostream& out) const = 0;
// Return whether the member's name matches `name`.
virtual auto IsNamed(std::string_view name) const -> bool = 0;
// Returns the enumerator corresponding to the most-derived type of this
// object.
auto kind() const -> ElementKind { return kind_; }
// The declared type of the member, which might include type variables.
virtual auto type() const -> const Value& = 0;
private:
const ElementKind kind_;
};
// A named element of a type.
//
// This is either a declared member of a class, interface, or similar, or a
// member of a struct with no declaration.
class NamedElement : public Element {
public:
explicit NamedElement(Nonnull<const Declaration*> declaration);
explicit NamedElement(Nonnull<const NamedValue*> struct_member);
template <typename F>
auto Decompose(F f) const {
if (auto decl = declaration()) {
return f(*decl);
} else {
return f(*struct_member());
}
}
// Prints the element's name
void Print(llvm::raw_ostream& out) const override;
auto IsNamed(std::string_view name) const -> bool override;
static auto classof(const Element* member) -> bool {
return InheritsFromNamedElement(member->kind());
}
auto type() const -> const Value& override;
// The name of the member.
auto name() const -> std::string_view;
// A declaration of the member, if any exists.
auto declaration() const -> std::optional<Nonnull<const Declaration*>>;
// A name and type pair, if this is a struct member.
auto struct_member() const -> std::optional<Nonnull<const NamedValue*>>;
private:
const llvm::PointerUnion<Nonnull<const Declaration*>,
Nonnull<const NamedValue*>>
element_;
};
// A positional element of a type.
//
// This is a positional tuple element, or other index-based value.
class PositionalElement : public Element {
public:
explicit PositionalElement(int index, Nonnull<const Value*> type)
: Element(ElementKind::PositionalElement), index_(index), type_(type) {}
template <typename F>
auto Decompose(F f) const {
return f(index_, type_);
}
// Prints the element
void Print(llvm::raw_ostream& out) const override;
// Return whether the member's name matches `name`.
auto IsNamed(std::string_view name) const -> bool override;
static auto classof(const Element* member) -> bool {
return InheritsFromPositionalElement(member->kind());
}
auto index() const -> int { return index_; }
auto type() const -> const Value& override { return *type_; }
private:
const int index_;
const Nonnull<const Value*> type_;
};
// A base class object.
//
// This is the base class object of a class value.
class BaseElement : public Element {
public:
explicit BaseElement(Nonnull<const Value*> type)
: Element(ElementKind::BaseElement), type_(type) {}
template <typename F>
auto Decompose(F f) const {
return f(type_);
}
// Prints the Member
void Print(llvm::raw_ostream& out) const override;
// Return whether the member's name matches `name`.
auto IsNamed(std::string_view name) const -> bool override;
static auto classof(const Element* member) -> bool {
return InheritsFromBaseElement(member->kind());
}
auto type() const -> const Value& override { return *type_; }
private:
const Nonnull<const Value*> type_;
};
template <typename R, typename F>
auto Element::Visit(F f) const -> R {
switch (kind()) {
case ElementKind::NamedElement:
return f(static_cast<const NamedElement*>(this));
case ElementKind::PositionalElement:
return f(static_cast<const PositionalElement*>(this));
case ElementKind::BaseElement:
return f(static_cast<const BaseElement*>(this));
}
}
} // namespace Carbon
#endif // CARBON_EXPLORER_AST_ELEMENT_H_