extract.cpp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. // Part of the Carbon Language project, under the Apache License v2.0 with LLVM
  2. // Exceptions. See /LICENSE for license information.
  3. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. #include <tuple>
  5. #include <typeinfo>
  6. #include <utility>
  7. #include "common/error.h"
  8. #include "common/struct_reflection.h"
  9. #include "toolchain/parse/tree.h"
  10. #include "toolchain/parse/typed_nodes.h"
  11. namespace Carbon::Parse {
  12. namespace {
  13. // Implementation of the process of extracting a typed node structure from the
  14. // parse tree. The extraction process uses the class `Extractable<T>`, defined
  15. // below, to extract individual fields of type `T`.
  16. class NodeExtractor {
  17. public:
  18. struct CheckpointState {
  19. Tree::SiblingIterator it;
  20. };
  21. NodeExtractor(const Tree* tree, Lex::TokenizedBuffer* tokens,
  22. ErrorBuilder* trace, NodeId node_id,
  23. llvm::iterator_range<Tree::SiblingIterator> children)
  24. : tree_(tree),
  25. tokens_(tokens),
  26. trace_(trace),
  27. node_id_(node_id),
  28. it_(children.begin()),
  29. end_(children.end()) {}
  30. auto at_end() const -> bool { return it_ == end_; }
  31. auto kind() const -> NodeKind { return tree_->node_kind(*it_); }
  32. auto has_token() const -> bool { return node_id_.is_valid(); }
  33. auto token() const -> Lex::TokenIndex { return tree_->node_token(node_id_); }
  34. auto token_kind() const -> Lex::TokenKind {
  35. return tokens_->GetKind(token());
  36. }
  37. auto trace() const -> ErrorBuilder* { return trace_; }
  38. // Saves a checkpoint of our current position so we can return later if
  39. // extraction of a child node fails.
  40. auto Checkpoint() const -> CheckpointState { return {.it = it_}; }
  41. auto RestoreCheckpoint(CheckpointState checkpoint) { it_ = checkpoint.it; }
  42. // Determines whether the current position matches the specified node kind. If
  43. // not, produces a suitable trace message.
  44. auto MatchesNodeIdForKind(NodeKind kind) const -> bool;
  45. // Determines whether the current position matches the specified node
  46. // category. If not, produces a suitable trace message.
  47. auto MatchesNodeIdInCategory(NodeCategory category) const -> bool;
  48. // Determines whether the current position matches any of the specified node
  49. // kinds. If not, produces a suitable trace message.
  50. auto MatchesNodeIdOneOf(std::initializer_list<NodeKind> kinds) const -> bool;
  51. // Determines whether the token corresponding to the enclosing node is of the
  52. // specified kind. If not, produces a suitable trace message.
  53. auto MatchesTokenKind(Lex::TokenKind expected_kind) const -> bool;
  54. // Extracts the next node from the tree.
  55. auto ExtractNode() -> NodeId { return *it_++; }
  56. // Extracts a tuple-like type `T` by extracting its components and then
  57. // assembling a `T` value.
  58. template <typename T, typename... U, std::size_t... Index>
  59. auto ExtractTupleLikeType(std::index_sequence<Index...> /*indices*/,
  60. std::tuple<U...>* /*type*/) -> std::optional<T>;
  61. private:
  62. const Tree* tree_;
  63. Lex::TokenizedBuffer* tokens_;
  64. ErrorBuilder* trace_;
  65. NodeId node_id_;
  66. Tree::SiblingIterator it_;
  67. Tree::SiblingIterator end_;
  68. };
  69. } // namespace
  70. namespace {
  71. // A trait type that should be specialized by types that can be extracted
  72. // from a parse tree. A specialization should provide the following API:
  73. //
  74. // ```cpp
  75. // template<>
  76. // struct Extractable<T> {
  77. // // Extract a value of this type from the sequence of nodes starting at
  78. // // `it`, and increment `it` past this type. Returns `std::nullopt` if
  79. // // the tree is malformed. If `trace != nullptr`, writes what actions
  80. // // were taken to `*trace`.
  81. // static auto Extract(NodeExtractor* extractor) -> std::optional<T>;
  82. // };
  83. // ```
  84. //
  85. // Note that `Tree::SiblingIterator`s iterate in reverse order through the
  86. // children of a node.
  87. //
  88. // This class is only in this file.
  89. template <typename T>
  90. struct Extractable;
  91. } // namespace
  92. // Extract a `NodeId` as a single child.
  93. template <>
  94. struct Extractable<NodeId> {
  95. static auto Extract(NodeExtractor& extractor) -> std::optional<NodeId> {
  96. if (extractor.at_end()) {
  97. if (auto* trace = extractor.trace()) {
  98. *trace << "NodeId error: no more children\n";
  99. }
  100. return std::nullopt;
  101. }
  102. if (auto* trace = extractor.trace()) {
  103. *trace << "NodeId: " << extractor.kind() << " consumed\n";
  104. }
  105. return extractor.ExtractNode();
  106. }
  107. };
  108. auto NodeExtractor::MatchesNodeIdForKind(NodeKind expected_kind) const -> bool {
  109. if (at_end() || kind() != expected_kind) {
  110. if (trace_) {
  111. if (at_end()) {
  112. *trace_ << "NodeIdForKind error: no more children, expected "
  113. << expected_kind << "\n";
  114. } else {
  115. *trace_ << "NodeIdForKind error: wrong kind " << kind() << ", expected "
  116. << expected_kind << "\n";
  117. }
  118. }
  119. return false;
  120. }
  121. if (trace_) {
  122. *trace_ << "NodeIdForKind: " << expected_kind << " consumed\n";
  123. }
  124. return true;
  125. }
  126. // Extract a `FooId`, which is the same as `NodeIdForKind<NodeKind::Foo>`,
  127. // as a single required child.
  128. template <const NodeKind& Kind>
  129. struct Extractable<NodeIdForKind<Kind>> {
  130. static auto Extract(NodeExtractor& extractor)
  131. -> std::optional<NodeIdForKind<Kind>> {
  132. if (extractor.MatchesNodeIdForKind(Kind)) {
  133. return NodeIdForKind<Kind>(extractor.ExtractNode());
  134. } else {
  135. return std::nullopt;
  136. }
  137. }
  138. };
  139. auto NodeExtractor::MatchesNodeIdInCategory(NodeCategory category) const
  140. -> bool {
  141. if (at_end() || !kind().category().HasAnyOf(category)) {
  142. if (trace_) {
  143. *trace_ << "NodeIdInCategory " << category << " error: ";
  144. if (at_end()) {
  145. *trace_ << "no more children\n";
  146. } else {
  147. *trace_ << "kind " << kind() << " doesn't match\n";
  148. }
  149. }
  150. return false;
  151. }
  152. if (trace_) {
  153. *trace_ << "NodeIdInCategory " << category << ": kind " << kind()
  154. << " consumed\n";
  155. }
  156. return true;
  157. }
  158. // Extract a `NodeIdInCategory<Category>` as a single child.
  159. template <NodeCategory::RawEnumType Category>
  160. struct Extractable<NodeIdInCategory<Category>> {
  161. static auto Extract(NodeExtractor& extractor)
  162. -> std::optional<NodeIdInCategory<Category>> {
  163. if (extractor.MatchesNodeIdInCategory(Category)) {
  164. return NodeIdInCategory<Category>(extractor.ExtractNode());
  165. } else {
  166. return std::nullopt;
  167. }
  168. }
  169. };
  170. auto NodeExtractor::MatchesNodeIdOneOf(
  171. std::initializer_list<NodeKind> kinds) const -> bool {
  172. auto trace_kinds = [&] {
  173. llvm::ListSeparator sep(" or ");
  174. for (auto kind : kinds) {
  175. *trace_ << sep << kind;
  176. }
  177. };
  178. auto node_kind = kind();
  179. if (at_end() ||
  180. std::find(kinds.begin(), kinds.end(), node_kind) == kinds.end()) {
  181. if (trace_) {
  182. if (at_end()) {
  183. *trace_ << "NodeIdOneOf error: no more children, expected ";
  184. trace_kinds();
  185. *trace_ << "\n";
  186. } else {
  187. *trace_ << "NodeIdOneOf error: wrong kind " << node_kind
  188. << ", expected ";
  189. trace_kinds();
  190. *trace_ << "\n";
  191. }
  192. }
  193. return false;
  194. }
  195. if (trace_) {
  196. *trace_ << "NodeIdOneOf ";
  197. trace_kinds();
  198. *trace_ << ": " << node_kind << " consumed\n";
  199. }
  200. return true;
  201. }
  202. // Extract a `NodeIdOneOf<T...>` as a single required child.
  203. template <typename... T>
  204. struct Extractable<NodeIdOneOf<T...>> {
  205. static auto Extract(NodeExtractor& extractor)
  206. -> std::optional<NodeIdOneOf<T...>> {
  207. if (extractor.MatchesNodeIdOneOf({T::Kind...})) {
  208. return NodeIdOneOf<T...>(extractor.ExtractNode());
  209. } else {
  210. return std::nullopt;
  211. }
  212. }
  213. };
  214. // Extract a `NodeIdNot<T>` as a single required child.
  215. // Note: this is only instantiated once, so no need to create a helper function.
  216. template <typename T>
  217. struct Extractable<NodeIdNot<T>> {
  218. static auto Extract(NodeExtractor& extractor) -> std::optional<NodeIdNot<T>> {
  219. if (extractor.at_end() || extractor.kind() == T::Kind) {
  220. if (auto* trace = extractor.trace()) {
  221. if (extractor.at_end()) {
  222. *trace << "NodeIdNot " << T::Kind << " error: no more children\n";
  223. } else {
  224. *trace << "NodeIdNot error: unexpected " << T::Kind << "\n";
  225. }
  226. }
  227. return std::nullopt;
  228. }
  229. if (auto* trace = extractor.trace()) {
  230. *trace << "NodeIdNot " << T::Kind << ": " << extractor.kind()
  231. << " consumed\n";
  232. }
  233. return NodeIdNot<T>(extractor.ExtractNode());
  234. }
  235. };
  236. // Extract an `llvm::SmallVector<T>` by extracting `T`s until we can't.
  237. template <typename T>
  238. struct Extractable<llvm::SmallVector<T>> {
  239. static auto Extract(NodeExtractor& extractor)
  240. -> std::optional<llvm::SmallVector<T>> {
  241. if (auto* trace = extractor.trace()) {
  242. *trace << "Vector: begin\n";
  243. }
  244. llvm::SmallVector<T> result;
  245. while (!extractor.at_end()) {
  246. auto checkpoint = extractor.Checkpoint();
  247. auto item = Extractable<T>::Extract(extractor);
  248. if (!item.has_value()) {
  249. extractor.RestoreCheckpoint(checkpoint);
  250. break;
  251. }
  252. result.push_back(*item);
  253. }
  254. std::reverse(result.begin(), result.end());
  255. if (auto* trace = extractor.trace()) {
  256. *trace << "Vector: end\n";
  257. }
  258. return result;
  259. }
  260. };
  261. // Extract an `optional<T>` from a list of child nodes by attempting to extract
  262. // a `T`, and extracting nothing if that fails.
  263. template <typename T>
  264. struct Extractable<std::optional<T>> {
  265. static auto Extract(NodeExtractor& extractor)
  266. -> std::optional<std::optional<T>> {
  267. if (auto* trace = extractor.trace()) {
  268. *trace << "Optional " << typeid(T).name() << ": begin\n";
  269. }
  270. auto checkpoint = extractor.Checkpoint();
  271. std::optional<T> value = Extractable<T>::Extract(extractor);
  272. if (value) {
  273. if (auto* trace = extractor.trace()) {
  274. *trace << "Optional " << typeid(T).name() << ": found\n";
  275. }
  276. return value;
  277. }
  278. if (auto* trace = extractor.trace()) {
  279. *trace << "Optional " << typeid(T).name() << ": missing\n";
  280. }
  281. extractor.RestoreCheckpoint(checkpoint);
  282. return value;
  283. }
  284. };
  285. auto NodeExtractor::MatchesTokenKind(Lex::TokenKind expected_kind) const
  286. -> bool {
  287. if (!node_id_.is_valid()) {
  288. if (trace_) {
  289. *trace_ << "Token " << expected_kind
  290. << " expected but processing root node\n";
  291. }
  292. return false;
  293. }
  294. if (token_kind() != expected_kind) {
  295. if (trace_) {
  296. *trace_ << "Token " << expected_kind << " expected for "
  297. << tree_->node_kind(node_id_) << ", found " << token_kind()
  298. << "\n";
  299. }
  300. return false;
  301. }
  302. return true;
  303. }
  304. // Extract the token corresponding to a node.
  305. template <const Lex::TokenKind& Kind>
  306. struct Extractable<Lex::TokenIndexForKind<Kind>> {
  307. static auto Extract(NodeExtractor& extractor)
  308. -> std::optional<Lex::TokenIndexForKind<Kind>> {
  309. if (extractor.MatchesTokenKind(Kind)) {
  310. return static_cast<Lex::TokenIndexForKind<Kind>>(extractor.token());
  311. } else {
  312. return std::nullopt;
  313. }
  314. }
  315. };
  316. // Extract the token corresponding to a node.
  317. template <>
  318. struct Extractable<Lex::TokenIndex> {
  319. static auto Extract(NodeExtractor& extractor)
  320. -> std::optional<Lex::TokenIndex> {
  321. if (!extractor.has_token()) {
  322. if (auto* trace = extractor.trace()) {
  323. *trace << "Token expected but processing root node\n";
  324. }
  325. return std::nullopt;
  326. }
  327. return extractor.token();
  328. }
  329. };
  330. template <typename T, typename... U, std::size_t... Index>
  331. auto NodeExtractor::ExtractTupleLikeType(
  332. std::index_sequence<Index...> /*indices*/, std::tuple<U...>* /*type*/)
  333. -> std::optional<T> {
  334. std::tuple<std::optional<U>...> fields;
  335. if (trace_) {
  336. *trace_ << "Aggregate " << typeid(T).name() << ": begin\n";
  337. }
  338. // Use a fold over the `=` operator to parse fields from right to left.
  339. [[maybe_unused]] int unused;
  340. bool ok = true;
  341. static_cast<void>(
  342. ((ok && (ok = (std::get<Index>(fields) = Extractable<U>::Extract(*this))
  343. .has_value()),
  344. unused) = ... = 0));
  345. if (!ok) {
  346. if (trace_) {
  347. *trace_ << "Aggregate " << typeid(T).name() << ": error\n";
  348. }
  349. return std::nullopt;
  350. }
  351. if (trace_) {
  352. *trace_ << "Aggregate " << typeid(T).name() << ": success\n";
  353. }
  354. return T{std::move(std::get<Index>(fields).value())...};
  355. }
  356. namespace {
  357. // Extract the fields of a simple aggregate type.
  358. template <typename T>
  359. struct Extractable {
  360. static_assert(std::is_aggregate_v<T>, "Unsupported child type");
  361. static auto ExtractImpl(NodeExtractor& extractor) -> std::optional<T> {
  362. // Compute the corresponding tuple type.
  363. using TupleType = decltype(StructReflection::AsTuple(std::declval<T>()));
  364. return extractor.ExtractTupleLikeType<T>(
  365. std::make_index_sequence<std::tuple_size_v<TupleType>>(),
  366. static_cast<TupleType*>(nullptr));
  367. }
  368. static auto Extract(NodeExtractor& extractor) -> std::optional<T> {
  369. static_assert(!HasKindMember<T>, "Missing Id suffix");
  370. return ExtractImpl(extractor);
  371. }
  372. };
  373. } // namespace
  374. template <typename T>
  375. auto Tree::TryExtractNodeFromChildren(
  376. NodeId node_id, llvm::iterator_range<Tree::SiblingIterator> children,
  377. ErrorBuilder* trace) const -> std::optional<T> {
  378. NodeExtractor extractor(this, tokens_, trace, node_id, children);
  379. auto result = Extractable<T>::ExtractImpl(extractor);
  380. if (!extractor.at_end()) {
  381. if (trace) {
  382. *trace << "Error: " << node_kind(extractor.ExtractNode())
  383. << " node left unconsumed.";
  384. }
  385. return std::nullopt;
  386. }
  387. return result;
  388. }
  389. // Manually instantiate Tree::TryExtractNodeFromChildren
  390. #define CARBON_PARSE_NODE_KIND(KindName) \
  391. template auto Tree::TryExtractNodeFromChildren<KindName>( \
  392. NodeId node_id, llvm::iterator_range<Tree::SiblingIterator> children, \
  393. ErrorBuilder * trace) const -> std::optional<KindName>;
  394. // Also instantiate for `File`, even though it isn't a parse node.
  395. CARBON_PARSE_NODE_KIND(File)
  396. #include "toolchain/parse/node_kind.def"
  397. auto Tree::ExtractFile() const -> File {
  398. return ExtractNodeFromChildren<File>(NodeId::Invalid, roots());
  399. }
  400. } // namespace Carbon::Parse