-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Expand file tree
/
Copy pathnode_ids.h
More file actions
213 lines (178 loc) · 8.07 KB
/
node_ids.h
File metadata and controls
213 lines (178 loc) · 8.07 KB
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
// 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_TOOLCHAIN_PARSE_NODE_IDS_H_
#define CARBON_TOOLCHAIN_PARSE_NODE_IDS_H_
#include "toolchain/base/index_base.h"
#include "toolchain/lex/token_index.h"
#include "toolchain/parse/node_category.h"
#include "toolchain/parse/node_kind.h"
namespace Carbon::Parse {
// Represents an invalid node id of any type
struct NoneNodeId {};
// A lightweight handle representing a node in the tree.
//
// Objects of this type are small and cheap to copy and store. They don't
// contain any of the information about the node, and serve as a handle that
// can be used with the underlying tree to query for detailed information.
struct NodeId : public IdBase<NodeId> {
static constexpr llvm::StringLiteral Label = "node";
// We give NodeId a bit in addition to TokenIndex in order to account for
// virtual nodes, where a token may produce two nodes.
static constexpr int32_t Bits = Lex::TokenIndex::Bits + 1;
// The maximum ID, non-inclusive.
static constexpr int Max = 1 << Bits;
// A node ID with no value.
static constexpr NoneNodeId None;
constexpr explicit NodeId(int32_t index) : IdBase(index) {
CARBON_DCHECK(index < Max, "Index out of range: {0}", index);
}
explicit(false) constexpr NodeId(NoneNodeId /*none*/) : IdBase(NoneIndex) {}
};
// For looking up the type associated with a given id type.
template <typename T>
struct NodeForId;
// `<KindName>Id` is a typed version of `NodeId` that references a node of kind
// `<KindName>`:
template <const NodeKind& K>
struct NodeIdForKind : public NodeId {
// NOLINTNEXTLINE(readability-identifier-naming)
static const NodeKind& Kind;
// Provide a factory function for construction from `NodeId`. This doesn't
// validate the type, so it's unsafe.
static constexpr auto UnsafeMake(NodeId node_id) -> NodeIdForKind {
return NodeIdForKind(node_id);
}
explicit(false) constexpr NodeIdForKind(NoneNodeId /*none*/)
: NodeId(NoneIndex) {}
private:
// Private to prevent accidental explicit construction from an untyped
// NodeId.
explicit constexpr NodeIdForKind(NodeId node_id) : NodeId(node_id) {}
};
template <const NodeKind& K>
const NodeKind& NodeIdForKind<K>::Kind = K;
#define CARBON_PARSE_NODE_KIND(KindName) \
using KindName##Id = NodeIdForKind<NodeKind::KindName>;
#include "toolchain/parse/node_kind.def"
// NodeId that matches any NodeKind whose `category()` overlaps with `Category`.
template <NodeCategory::RawEnumType Category>
struct NodeIdInCategory : public NodeId {
// Provide a factory function for construction from `NodeId`. This doesn't
// validate the type, so it's unsafe.
static constexpr auto UnsafeMake(NodeId node_id) -> NodeIdInCategory {
return NodeIdInCategory(node_id);
}
// Support conversion from `NodeIdForKind<Kind>` if Kind's category
// overlaps with `Category`.
template <const NodeKind& Kind>
explicit(false) NodeIdInCategory(NodeIdForKind<Kind> node_id)
: NodeId(node_id) {
CARBON_CHECK(Kind.category().HasAnyOf(Category));
}
explicit(false) constexpr NodeIdInCategory(NoneNodeId /*none*/)
: NodeId(NoneIndex) {}
private:
// Private to prevent accidental explicit construction from an untyped
// NodeId.
explicit constexpr NodeIdInCategory(NodeId node_id) : NodeId(node_id) {}
};
// Aliases for `NodeIdInCategory` to describe particular categories of nodes.
using AnyDeclId = NodeIdInCategory<NodeCategory::Decl>;
using AnyExprId = NodeIdInCategory<NodeCategory::Expr>;
using AnyImplAsId = NodeIdInCategory<NodeCategory::ImplAs>;
using AnyMemberAccessId =
NodeIdInCategory<NodeCategory::MemberName | NodeCategory::MemberExpr |
NodeCategory::IntConst>;
using AnyModifierId = NodeIdInCategory<NodeCategory::Modifier>;
using AnyPatternId =
NodeIdInCategory<NodeCategory::Pattern | NodeCategory::Expr>;
using AnyStatementId =
NodeIdInCategory<NodeCategory::Statement | NodeCategory::Decl>;
using AnyRequireImplsId = NodeIdInCategory<NodeCategory::RequireImpls>;
using AnyRequirementId = NodeIdInCategory<NodeCategory::Requirement>;
using AnyObserveOperatorId = NodeIdInCategory<NodeCategory::ObserveOperator>;
using AnyObserveOperandId =
NodeIdInCategory<NodeCategory::Expr | NodeCategory::ObserveOperator>;
using AnyNonExprNameId = NodeIdInCategory<NodeCategory::NonExprName>;
using AnyPackageNameId = NodeIdInCategory<NodeCategory::PackageName>;
using AnyReturnDeclId = NodeIdInCategory<NodeCategory::ReturnDecl>;
namespace Internal {
template <typename T>
concept IsNodeKind = std::same_as<std::remove_cvref_t<T>, NodeKind> ||
std::same_as<std::remove_cvref_t<T>, NodeKind::Definition>;
template <typename T>
concept IsTypedNode = requires {
{ T::Kind } -> IsNodeKind;
};
} // namespace Internal
// NodeId with kind that matches one of the `T::Kind`s.
template <typename... T>
requires(sizeof...(T) >= 2 && (Internal::IsTypedNode<T> && ...))
struct NodeIdOneOf : public NodeId {
private:
// True if `OtherT` is one of `T`.
template <typename OtherT>
static constexpr bool Contains = (std::is_same<OtherT, T>{} || ...);
// True if `NodeIdOneOf<SubsetT...>` is a subset of this `NodeIdOneOf`.
template <typename Unused>
static constexpr bool IsSubset = false;
template <typename... SubsetT>
static constexpr bool IsSubset<NodeIdOneOf<SubsetT...>> =
(Contains<SubsetT> && ...);
// Private to prevent accidental explicit construction from an untyped
// NodeId.
explicit constexpr NodeIdOneOf(NodeId node_id) : NodeId(node_id) {}
public:
// Provide a factory function for construction from `NodeId`. This doesn't
// validate the type, so it's unsafe.
static constexpr auto UnsafeMake(NodeId node_id) -> NodeIdOneOf {
return NodeIdOneOf(node_id);
}
template <const NodeKind& Kind>
requires(Contains<NodeIdForKind<Kind>>)
explicit(false) NodeIdOneOf(NodeIdForKind<Kind> node_id) : NodeId(node_id) {}
template <typename OtherNodeIdOneOf>
requires(IsSubset<OtherNodeIdOneOf>)
explicit(false) NodeIdOneOf(OtherNodeIdOneOf node_id) : NodeId(node_id) {}
explicit(false) constexpr NodeIdOneOf(NoneNodeId /*none*/)
: NodeId(NoneIndex) {}
};
using AnyClassDeclId =
NodeIdOneOf<ClassDeclId, ClassDefinitionStartId,
// TODO: This may be wrong? But we have choice types produce a
// class, so they are a form of class decls. This avoids
// duplicating all of SemIR::ClassDecl.
ChoiceDefinitionStartId>;
using AnyFunctionDeclId = NodeIdOneOf<FunctionDeclId, FunctionDefinitionStartId,
BuiltinFunctionDefinitionStartId>;
using AnyFunctionDefinitionId =
NodeIdOneOf<FunctionDefinitionId, FunctionTerseDefinitionId,
BuiltinFunctionDefinitionId>;
using AnyImplDeclId = NodeIdOneOf<ImplDeclId, ImplDefinitionStartId>;
using AnyInterfaceDeclId =
NodeIdOneOf<InterfaceDeclId, InterfaceDefinitionStartId>;
using AnyNamedConstraintDeclId =
NodeIdOneOf<NamedConstraintDeclId, NamedConstraintDefinitionStartId>;
using AnyNamespaceId =
NodeIdOneOf<NamespaceId, ImportDeclId, LibraryDeclId, PackageDeclId>;
using AnyPackagingDeclId =
NodeIdOneOf<ImportDeclId, LibraryDeclId, PackageDeclId>;
using AnyPointerDeferenceExprId =
NodeIdOneOf<PrefixOperatorStarId, PointerMemberAccessExprId>;
using AnyRuntimeBindingPatternName =
NodeIdOneOf<IdentifierNameNotBeforeSignatureId, SelfValueNameId,
UnderscoreNameId>;
using AnyPrimitiveFormIdId =
NodeIdOneOf<RefPrimitiveFormId, VarPrimitiveFormId, ValPrimitiveFormId>;
// NodeId with kind that is anything but T::Kind.
template <typename T>
struct NodeIdNot : public NodeId {
constexpr explicit NodeIdNot(NodeId node_id) : NodeId(node_id) {}
explicit(false) constexpr NodeIdNot(NoneNodeId /*none*/)
: NodeId(NoneIndex) {}
};
// Note that the support for extracting these types using the `Tree::Extract*`
// functions is defined in `extract.cpp`.
} // namespace Carbon::Parse
#endif // CARBON_TOOLCHAIN_PARSE_NODE_IDS_H_