semantics_node_stack.h 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  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. #ifndef CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_NODE_STACK_H_
  5. #define CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_NODE_STACK_H_
  6. #include <type_traits>
  7. #include "common/vlog.h"
  8. #include "llvm/ADT/SmallVector.h"
  9. #include "toolchain/parser/parse_node_kind.h"
  10. #include "toolchain/parser/parse_tree.h"
  11. #include "toolchain/semantics/semantics_node.h"
  12. namespace Carbon {
  13. // Wraps the stack of nodes for SemanticsParseTreeHandler.
  14. //
  15. // All pushes and pops will be vlogged.
  16. //
  17. // Pop APIs will run basic verification:
  18. //
  19. // - If receiving a pop_parse_kind, verify that the parse_node being popped is
  20. // of pop_parse_kind.
  21. // - Validates presence of node_id based on whether it's a solo
  22. // parse_node.
  23. //
  24. // These should be assumed API constraints unless otherwise mentioned on a
  25. // method. The main exception is PopAndIgnore, which doesn't do verification.
  26. class SemanticsNodeStack {
  27. public:
  28. explicit SemanticsNodeStack(const ParseTree& parse_tree,
  29. llvm::raw_ostream* vlog_stream)
  30. : parse_tree_(&parse_tree), vlog_stream_(vlog_stream) {}
  31. // Pushes a solo parse tree node onto the stack. Used when there is no
  32. // IR generated by the node.
  33. auto Push(ParseTree::Node parse_node) -> void {
  34. CARBON_VLOG() << "Node Push " << stack_.size() << ": "
  35. << parse_tree_->node_kind(parse_node) << " -> <none>\n";
  36. CARBON_CHECK(stack_.size() < (1 << 20))
  37. << "Excessive stack size: likely infinite loop";
  38. stack_.push_back(Entry(parse_node, SemanticsNodeId::Invalid));
  39. }
  40. // Pushes a parse tree node onto the stack with an ID.
  41. template <typename IdT>
  42. auto Push(ParseTree::Node parse_node, IdT id) -> void {
  43. CARBON_VLOG() << "Node Push " << stack_.size() << ": "
  44. << parse_tree_->node_kind(parse_node) << " -> " << id << "\n";
  45. CARBON_CHECK(stack_.size() < (1 << 20))
  46. << "Excessive stack size: likely infinite loop";
  47. stack_.push_back(Entry(parse_node, id));
  48. }
  49. // Pops the top of the stack without any verification.
  50. auto PopAndIgnore() -> void { PopEntry<SemanticsNodeId>(); }
  51. // Pops the top of the stack and returns the parse_node.
  52. auto PopForSoloParseNode() -> ParseTree::Node {
  53. Entry back = PopEntry<SemanticsNodeId>();
  54. RequireSoloParseNode(back);
  55. return back.parse_node;
  56. }
  57. // Pops the top of the stack and returns the parse_node.
  58. auto PopForSoloParseNode(ParseNodeKind pop_parse_kind) -> ParseTree::Node {
  59. auto parse_node = PopForSoloParseNode();
  60. RequireParseKind(parse_node, pop_parse_kind);
  61. return parse_node;
  62. }
  63. // Pops the top of the stack.
  64. auto PopAndDiscardSoloParseNode(ParseNodeKind pop_parse_kind) -> void {
  65. PopForSoloParseNode(pop_parse_kind);
  66. }
  67. // Pops the top of the stack and returns the parse_node and the ID.
  68. template <typename IdT>
  69. auto PopWithParseNode() -> std::pair<ParseTree::Node, IdT> {
  70. Entry back = PopEntry<IdT>();
  71. RequireValidId(back);
  72. return {back.parse_node, back.id<IdT>()};
  73. }
  74. // Pops the top of the stack and returns the parse_node and the ID.
  75. template <typename IdT>
  76. auto PopWithParseNode(ParseNodeKind pop_parse_kind)
  77. -> std::pair<ParseTree::Node, IdT> {
  78. auto back = PopWithParseNode<IdT>();
  79. RequireParseKind(back.first, pop_parse_kind);
  80. return back;
  81. }
  82. // Pops the top of the stack and returns the ID.
  83. template <typename IdT>
  84. auto Pop() -> IdT {
  85. return PopWithParseNode<IdT>().second;
  86. }
  87. // Pops the top of the stack and returns the ID.
  88. template <typename IdT>
  89. auto Pop(ParseNodeKind pop_parse_kind) -> IdT {
  90. return PopWithParseNode<IdT>(pop_parse_kind).second;
  91. }
  92. // Pops the top of the stack, and discards the ID.
  93. auto PopAndDiscardId() -> void { PopWithParseNode<SemanticsNodeId>(); }
  94. // Pops the top of the stack, and discards the ID.
  95. auto PopAndDiscardId(ParseNodeKind pop_parse_kind) -> void {
  96. PopWithParseNode<SemanticsNodeId>(pop_parse_kind);
  97. }
  98. // Peeks at the parse_node of the top of the stack.
  99. auto PeekParseNode() -> ParseTree::Node { return stack_.back().parse_node; }
  100. // Peeks at the ID of the top of the stack.
  101. template <typename IdT>
  102. auto Peek(ParseNodeKind parse_kind) -> IdT {
  103. Entry back = stack_.back();
  104. RequireParseKind(back.parse_node, parse_kind);
  105. RequireValidId(back);
  106. return back.id<IdT>();
  107. }
  108. // Prints the stack for a stack dump.
  109. auto PrintForStackDump(llvm::raw_ostream& output) const -> void;
  110. auto empty() const -> bool { return stack_.empty(); }
  111. auto size() const -> size_t { return stack_.size(); }
  112. private:
  113. // An entry in stack_.
  114. struct Entry {
  115. explicit Entry(ParseTree::Node parse_node, SemanticsNodeId node_id)
  116. : parse_node(parse_node), node_id(node_id) {}
  117. explicit Entry(ParseTree::Node parse_node,
  118. SemanticsNodeBlockId node_block_id)
  119. : parse_node(parse_node), node_block_id(node_block_id) {}
  120. explicit Entry(ParseTree::Node parse_node, SemanticsFunctionId function_id)
  121. : parse_node(parse_node), function_id(function_id) {}
  122. explicit Entry(ParseTree::Node parse_node, SemanticsStringId name_id)
  123. : parse_node(parse_node), name_id(name_id) {}
  124. explicit Entry(ParseTree::Node parse_node, SemanticsTypeId type_id)
  125. : parse_node(parse_node), type_id(type_id) {}
  126. // Returns the appropriate ID basaed on type.
  127. template <typename T>
  128. auto id() -> T& {
  129. if constexpr (std::is_same<T, SemanticsNodeId>()) {
  130. return node_id;
  131. }
  132. if constexpr (std::is_same<T, SemanticsNodeBlockId>()) {
  133. return node_block_id;
  134. }
  135. if constexpr (std::is_same<T, SemanticsFunctionId>()) {
  136. return function_id;
  137. }
  138. if constexpr (std::is_same<T, SemanticsStringId>()) {
  139. return name_id;
  140. }
  141. if constexpr (std::is_same<T, SemanticsTypeId>()) {
  142. return type_id;
  143. }
  144. }
  145. // The node associated with the stack entry.
  146. ParseTree::Node parse_node;
  147. // The entries will evaluate as invalid if and only if they're a solo
  148. // parse_node. Invalid is used instead of optional to save space.
  149. //
  150. // A discriminator isn't needed because the caller can determine which field
  151. // is used based on the ParseNodeKind.
  152. union {
  153. SemanticsNodeId node_id;
  154. SemanticsNodeBlockId node_block_id;
  155. SemanticsFunctionId function_id;
  156. SemanticsStringId name_id;
  157. SemanticsTypeId type_id;
  158. };
  159. // APIs rely on type punning. They read node_id.is_valid, even though that
  160. // may not be the active union member. These asserts enforce standard layout
  161. // in order to help ensure that works.
  162. // TODO: Use is_layout_compatible in C++20.
  163. static_assert(std::is_standard_layout_v<SemanticsNodeId>,
  164. "Need standard layout for type punning");
  165. static_assert(std::is_standard_layout_v<SemanticsNodeBlockId>,
  166. "Need standard layout for type punning");
  167. static_assert(std::is_standard_layout_v<SemanticsFunctionId>,
  168. "Need standard layout for type punning");
  169. static_assert(std::is_standard_layout_v<SemanticsStringId>,
  170. "Need standard layout for type punning");
  171. static_assert(std::is_standard_layout_v<SemanticsTypeId>,
  172. "Need standard layout for type punning");
  173. };
  174. static_assert(sizeof(Entry) == 8, "Unexpected Entry size");
  175. // Pops an entry.
  176. template <typename IdT>
  177. auto PopEntry() -> Entry {
  178. Entry back = stack_.pop_back_val();
  179. CARBON_VLOG() << "Node Pop " << stack_.size() << ": "
  180. << parse_tree_->node_kind(back.parse_node) << " -> "
  181. << back.id<IdT>() << "\n";
  182. return back;
  183. }
  184. // Require an entry to have the given ParseNodeKind.
  185. auto RequireParseKind(ParseTree::Node parse_node, ParseNodeKind require_kind)
  186. -> void {
  187. auto actual_kind = parse_tree_->node_kind(parse_node);
  188. CARBON_CHECK(require_kind == actual_kind)
  189. << "Expected " << require_kind << ", found " << actual_kind;
  190. }
  191. // Requires an entry to have a invalid node_id.
  192. auto RequireSoloParseNode(Entry entry) -> void {
  193. // See above comment on type punning.
  194. CARBON_CHECK(!entry.node_id.is_valid())
  195. << "Expected invalid id on " << parse_tree_->node_kind(entry.parse_node)
  196. << ", was " << entry.node_id << " (may not be node)";
  197. }
  198. // Requires an entry to have a valid id.
  199. auto RequireValidId(Entry entry) -> void {
  200. // See above comment on type punning.
  201. CARBON_CHECK(entry.node_id.is_valid())
  202. << "Expected valid id on " << parse_tree_->node_kind(entry.parse_node);
  203. }
  204. // The file's parse tree.
  205. const ParseTree* parse_tree_;
  206. // Whether to print verbose output.
  207. llvm::raw_ostream* vlog_stream_;
  208. // The actual stack.
  209. // PushEntry and PopEntry control modification in order to centralize
  210. // vlogging.
  211. llvm::SmallVector<Entry> stack_;
  212. };
  213. } // namespace Carbon
  214. #endif // CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_NODE_STACK_H_