semantics_node_stack.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  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.
  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 PatternBinding parse tree node onto the stack with its name.
  41. auto Push(ParseTree::Node parse_node, SemanticsStringId name_id) -> void {
  42. CARBON_CHECK(parse_tree_->node_kind(parse_node) ==
  43. ParseNodeKind::PatternBinding);
  44. PushEntry({.parse_node = parse_node, .name_id = name_id}, DebugLog::NameId);
  45. }
  46. // Pops the top of the stack without any verification.
  47. auto PopAndIgnore() -> void { PopEntry(); }
  48. // Pops the top of the stack.
  49. auto PopAndDiscardSoloParseNode(ParseNodeKind pop_parse_kind) -> void;
  50. // Pops the top of the stack, and discards the ID.
  51. auto PopAndDiscardId() -> void;
  52. // Pops the top of the stack, and discards the ID.
  53. auto PopAndDiscardId(ParseNodeKind pop_parse_kind) -> void;
  54. // Pops the top of the stack and returns the parse_node.
  55. auto PopForSoloParseNode() -> ParseTree::Node;
  56. // Pops the top of the stack and returns the parse_node.
  57. auto PopForSoloParseNode(ParseNodeKind pop_parse_kind) -> ParseTree::Node;
  58. // Pops the top of the stack and returns the node_id.
  59. auto PopForNodeId(ParseNodeKind pop_parse_kind) -> SemanticsNodeId;
  60. // Pops the top of the stack and returns the parse_node and node_id.
  61. auto PopForParseNodeAndNodeId()
  62. -> std::pair<ParseTree::Node, SemanticsNodeId>;
  63. // Pops the top of the stack and returns the parse_node and node_id.
  64. auto PopForParseNodeAndNodeId(ParseNodeKind pop_parse_kind)
  65. -> std::pair<ParseTree::Node, SemanticsNodeId>;
  66. // Pops the top of the stack and returns the node_id.
  67. auto PopForNodeId() -> SemanticsNodeId;
  68. // Pops the top of the stack and returns the parse_node and name_id.
  69. // Verifies that the parse_node is a PatternBinding.
  70. auto PopForParseNodeAndNameId()
  71. -> std::pair<ParseTree::Node, SemanticsStringId>;
  72. // Peeks at the parse_node of the top of the stack.
  73. auto PeekParseNode() -> ParseTree::Node { return stack_.back().parse_node; }
  74. // Peeks at the name_id of the top of the stack.
  75. // Verifies that the parse_node is a PatternBinding.
  76. auto PeekForNameId() -> SemanticsStringId;
  77. // Prints the stack for a stack dump.
  78. auto PrintForStackDump(llvm::raw_ostream& output) const -> void;
  79. auto empty() const -> bool { return stack_.empty(); }
  80. auto size() const -> size_t { return stack_.size(); }
  81. private:
  82. // An entry in stack_.
  83. struct Entry {
  84. // The node associated with the stack entry.
  85. ParseTree::Node parse_node;
  86. // The entries will evaluate as invalid if and only if they're a solo
  87. // parse_node. Invalid is used instead of optional to save space.
  88. //
  89. // A discriminator isn't needed because the caller can determine which field
  90. // is used based on the ParseNodeKind.
  91. union {
  92. SemanticsNodeId node_id;
  93. // Right now name_id is exclusively for PatternBinding, which is enforced.
  94. SemanticsStringId name_id;
  95. };
  96. };
  97. static_assert(sizeof(Entry) == 8, "Unexpected Entry size");
  98. // Which Entry union member to log.
  99. enum DebugLog {
  100. None,
  101. NodeId,
  102. NameId,
  103. };
  104. // Pushes an entry onto the stack.
  105. auto PushEntry(Entry entry, DebugLog debug_log) -> void;
  106. // Pops an entry.
  107. auto PopEntry() -> Entry;
  108. // Pops an entry, requiring the specific kind.
  109. auto PopEntry(ParseNodeKind pop_parse_kind) -> Entry;
  110. // Require an entry to have the given ParseNodeKind.
  111. auto RequireParseKind(Entry entry, ParseNodeKind require_kind) -> void;
  112. // Requires an entry to have a invalid node_id.
  113. auto RequireSoloParseNode(Entry entry) -> void;
  114. // Requires an entry to have a valid id.
  115. auto RequireValidId(Entry entry) -> void;
  116. // The file's parse tree.
  117. const ParseTree* parse_tree_;
  118. // Whether to print verbose output.
  119. llvm::raw_ostream* vlog_stream_;
  120. // The actual stack.
  121. // PushEntry and PopEntry control modification in order to centralize
  122. // vlogging.
  123. llvm::SmallVector<Entry> stack_;
  124. };
  125. } // namespace Carbon
  126. #endif // CARBON_TOOLCHAIN_SEMANTICS_SEMANTICS_NODE_STACK_H_