semantics_node_stack.h 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  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 "llvm/ADT/SmallVector.h"
  8. #include "toolchain/parser/parse_node_kind.h"
  9. #include "toolchain/parser/parse_tree.h"
  10. #include "toolchain/semantics/semantics_node.h"
  11. namespace Carbon {
  12. // Wraps the stack of nodes for SemanticsParseTreeHandler.
  13. //
  14. // All pushes and pops will be vlogged.
  15. //
  16. // Pop APIs will run basic verification:
  17. //
  18. // - If receiving a pop_parse_kind, verify that the parse_node being popped is
  19. // of pop_parse_kind.
  20. // - Validates presence of node_id based on whether it's a solo
  21. // parse_node.
  22. //
  23. // These should be assumed API constraints unless otherwise mentioned on a
  24. // method. The main exception is PopAndIgnore, which doesn't do verification.
  25. class SemanticsNodeStack {
  26. public:
  27. explicit SemanticsNodeStack(const ParseTree& parse_tree,
  28. llvm::raw_ostream* vlog_stream)
  29. : parse_tree_(&parse_tree), vlog_stream_(vlog_stream) {}
  30. // Pushes a solo parse tree node onto the stack. Used when there is no
  31. // IR generated by the node.
  32. auto Push(ParseTree::Node parse_node) -> void {
  33. PushEntry({.parse_node = parse_node, .node_id = SemanticsNodeId::Invalid},
  34. DebugLog::None);
  35. }
  36. // Pushes a parse tree node onto the stack with a semantics node.
  37. auto Push(ParseTree::Node parse_node, SemanticsNodeId node_id) -> void {
  38. PushEntry({.parse_node = parse_node, .node_id = node_id}, DebugLog::NodeId);
  39. }
  40. // Pushes a parse tree node onto the stack with a semantics node block.
  41. auto Push(ParseTree::Node parse_node, SemanticsNodeBlockId node_block_id)
  42. -> void {
  43. PushEntry({.parse_node = parse_node, .node_block_id = node_block_id},
  44. DebugLog::NodeBlockId);
  45. }
  46. // Pushes a parse tree node onto the stack with its name.
  47. auto Push(ParseTree::Node parse_node, SemanticsStringId name_id) -> void {
  48. PushEntry({.parse_node = parse_node, .name_id = name_id}, DebugLog::NameId);
  49. }
  50. // Pushes a parse tree node onto the stack with a semantics node block.
  51. auto Push(ParseTree::Node parse_node, SemanticsTypeId type_id) -> void {
  52. PushEntry({.parse_node = parse_node, .type_id = type_id}, DebugLog::TypeId);
  53. }
  54. // Pops the top of the stack without any verification.
  55. auto PopAndIgnore() -> void { PopEntry(); }
  56. // Pops the top of the stack.
  57. auto PopAndDiscardSoloParseNode(ParseNodeKind pop_parse_kind) -> void;
  58. // Pops the top of the stack, and discards the ID.
  59. auto PopAndDiscardId() -> void;
  60. // Pops the top of the stack, and discards the ID.
  61. auto PopAndDiscardId(ParseNodeKind pop_parse_kind) -> void;
  62. // Pops the top of the stack and returns the parse_node.
  63. auto PopForSoloParseNode() -> ParseTree::Node;
  64. // Pops the top of the stack and returns the parse_node.
  65. auto PopForSoloParseNode(ParseNodeKind pop_parse_kind) -> ParseTree::Node;
  66. // Pops the top of the stack and returns the node_id.
  67. auto PopForNodeId(ParseNodeKind pop_parse_kind) -> SemanticsNodeId;
  68. // Pops the top of the stack and returns the parse_node and node_id.
  69. auto PopForParseNodeAndNodeId()
  70. -> std::pair<ParseTree::Node, SemanticsNodeId>;
  71. // Pops the top of the stack and returns the parse_node and node_id.
  72. auto PopForParseNodeAndNodeId(ParseNodeKind pop_parse_kind)
  73. -> std::pair<ParseTree::Node, SemanticsNodeId>;
  74. // Pops the top of the stack and returns the node_id.
  75. auto PopForNodeId() -> SemanticsNodeId;
  76. // Pops the top of the stack and returns the node_block_id.
  77. auto PopForNodeBlockId(ParseNodeKind pop_parse_kind) -> SemanticsNodeBlockId;
  78. // Pops the top of the stack and returns the type_id.
  79. auto PopForTypeId(ParseNodeKind pop_parse_kind) -> SemanticsTypeId;
  80. // Pops the top of the stack and returns the parse_node and name_id.
  81. auto PopForParseNodeAndNameId(ParseNodeKind pop_parse_kind)
  82. -> std::pair<ParseTree::Node, SemanticsStringId>;
  83. // Peeks at the parse_node of the top of the stack.
  84. auto PeekParseNode() -> ParseTree::Node { return stack_.back().parse_node; }
  85. // Peeks at the name_id of the top of the stack.
  86. auto PeekForNameId(ParseNodeKind parse_kind) -> SemanticsStringId;
  87. // Prints the stack for a stack dump.
  88. auto PrintForStackDump(llvm::raw_ostream& output) const -> void;
  89. auto empty() const -> bool { return stack_.empty(); }
  90. auto size() const -> size_t { return stack_.size(); }
  91. private:
  92. // An entry in stack_.
  93. struct Entry {
  94. // The node associated with the stack entry.
  95. ParseTree::Node parse_node;
  96. // The entries will evaluate as invalid if and only if they're a solo
  97. // parse_node. Invalid is used instead of optional to save space.
  98. //
  99. // A discriminator isn't needed because the caller can determine which field
  100. // is used based on the ParseNodeKind.
  101. union {
  102. SemanticsNodeId node_id;
  103. SemanticsNodeBlockId node_block_id;
  104. SemanticsStringId name_id;
  105. SemanticsTypeId type_id;
  106. };
  107. };
  108. static_assert(sizeof(Entry) == 8, "Unexpected Entry size");
  109. // Which Entry union member to log.
  110. enum DebugLog {
  111. None,
  112. NodeId,
  113. NodeBlockId,
  114. NameId,
  115. TypeId,
  116. };
  117. // Pushes an entry onto the stack.
  118. auto PushEntry(Entry entry, DebugLog debug_log) -> void;
  119. // Pops an entry.
  120. auto PopEntry() -> Entry;
  121. // Pops an entry, requiring the specific kind.
  122. auto PopEntry(ParseNodeKind pop_parse_kind) -> Entry;
  123. // Require an entry to have the given ParseNodeKind.
  124. auto RequireParseKind(Entry entry, ParseNodeKind require_kind) -> void;
  125. // Requires an entry to have a invalid node_id.
  126. auto RequireSoloParseNode(Entry entry) -> void;
  127. // Requires an entry to have a valid id.
  128. auto RequireValidId(Entry entry) -> void;
  129. // The file's parse tree.
  130. const ParseTree* parse_tree_;
  131. // Whether to print verbose output.
  132. llvm::raw_ostream* vlog_stream_;
  133. // The actual stack.
  134. // PushEntry and PopEntry control modification in order to centralize
  135. // vlogging.
  136. llvm::SmallVector<Entry> stack_;
  137. };
  138. } // namespace Carbon
  139. #endif // CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_NODE_STACK_H_