|
|
@@ -7,6 +7,7 @@
|
|
|
|
|
|
#include <type_traits>
|
|
|
|
|
|
+#include "common/vlog.h"
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
#include "toolchain/parser/parse_node_kind.h"
|
|
|
#include "toolchain/parser/parse_tree.h"
|
|
|
@@ -36,79 +37,93 @@ class SemanticsNodeStack {
|
|
|
// Pushes a solo parse tree node onto the stack. Used when there is no
|
|
|
// IR generated by the node.
|
|
|
auto Push(ParseTree::Node parse_node) -> void {
|
|
|
- PushEntry({.parse_node = parse_node, .node_id = SemanticsNodeId::Invalid},
|
|
|
- DebugLog::None);
|
|
|
+ CARBON_VLOG() << "Node Push " << stack_.size() << ": "
|
|
|
+ << parse_tree_->node_kind(parse_node) << " -> <none>\n";
|
|
|
+ CARBON_CHECK(stack_.size() < (1 << 20))
|
|
|
+ << "Excessive stack size: likely infinite loop";
|
|
|
+ stack_.push_back(Entry(parse_node, SemanticsNodeId::Invalid));
|
|
|
}
|
|
|
|
|
|
- // Pushes a parse tree node onto the stack with a semantics node.
|
|
|
- auto Push(ParseTree::Node parse_node, SemanticsNodeId node_id) -> void {
|
|
|
- PushEntry({.parse_node = parse_node, .node_id = node_id}, DebugLog::NodeId);
|
|
|
- }
|
|
|
-
|
|
|
- // Pushes a parse tree node onto the stack with a semantics node block.
|
|
|
- auto Push(ParseTree::Node parse_node, SemanticsNodeBlockId node_block_id)
|
|
|
- -> void {
|
|
|
- PushEntry({.parse_node = parse_node, .node_block_id = node_block_id},
|
|
|
- DebugLog::NodeBlockId);
|
|
|
- }
|
|
|
-
|
|
|
- // Pushes a parse tree node onto the stack with its name.
|
|
|
- auto Push(ParseTree::Node parse_node, SemanticsStringId name_id) -> void {
|
|
|
- PushEntry({.parse_node = parse_node, .name_id = name_id}, DebugLog::NameId);
|
|
|
- }
|
|
|
-
|
|
|
- // Pushes a parse tree node onto the stack with a semantics node block.
|
|
|
- auto Push(ParseTree::Node parse_node, SemanticsTypeId type_id) -> void {
|
|
|
- PushEntry({.parse_node = parse_node, .type_id = type_id}, DebugLog::TypeId);
|
|
|
+ // Pushes a parse tree node onto the stack with an ID.
|
|
|
+ template <typename IdT>
|
|
|
+ auto Push(ParseTree::Node parse_node, IdT id) -> void {
|
|
|
+ CARBON_VLOG() << "Node Push " << stack_.size() << ": "
|
|
|
+ << parse_tree_->node_kind(parse_node) << " -> " << id << "\n";
|
|
|
+ CARBON_CHECK(stack_.size() < (1 << 20))
|
|
|
+ << "Excessive stack size: likely infinite loop";
|
|
|
+ stack_.push_back(Entry(parse_node, id));
|
|
|
}
|
|
|
|
|
|
// Pops the top of the stack without any verification.
|
|
|
- auto PopAndIgnore() -> void { PopEntry(); }
|
|
|
-
|
|
|
- // Pops the top of the stack.
|
|
|
- auto PopAndDiscardSoloParseNode(ParseNodeKind pop_parse_kind) -> void;
|
|
|
-
|
|
|
- // Pops the top of the stack, and discards the ID.
|
|
|
- auto PopAndDiscardId() -> void;
|
|
|
-
|
|
|
- // Pops the top of the stack, and discards the ID.
|
|
|
- auto PopAndDiscardId(ParseNodeKind pop_parse_kind) -> void;
|
|
|
+ auto PopAndIgnore() -> void { PopEntry<SemanticsNodeId>(); }
|
|
|
|
|
|
// Pops the top of the stack and returns the parse_node.
|
|
|
- auto PopForSoloParseNode() -> ParseTree::Node;
|
|
|
+ auto PopForSoloParseNode() -> ParseTree::Node {
|
|
|
+ Entry back = PopEntry<SemanticsNodeId>();
|
|
|
+ RequireSoloParseNode(back);
|
|
|
+ return back.parse_node;
|
|
|
+ }
|
|
|
|
|
|
// Pops the top of the stack and returns the parse_node.
|
|
|
- auto PopForSoloParseNode(ParseNodeKind pop_parse_kind) -> ParseTree::Node;
|
|
|
+ auto PopForSoloParseNode(ParseNodeKind pop_parse_kind) -> ParseTree::Node {
|
|
|
+ auto parse_node = PopForSoloParseNode();
|
|
|
+ RequireParseKind(parse_node, pop_parse_kind);
|
|
|
+ return parse_node;
|
|
|
+ }
|
|
|
|
|
|
- // Pops the top of the stack and returns the node_id.
|
|
|
- auto PopForNodeId(ParseNodeKind pop_parse_kind) -> SemanticsNodeId;
|
|
|
+ // Pops the top of the stack.
|
|
|
+ auto PopAndDiscardSoloParseNode(ParseNodeKind pop_parse_kind) -> void {
|
|
|
+ PopForSoloParseNode(pop_parse_kind);
|
|
|
+ }
|
|
|
|
|
|
- // Pops the top of the stack and returns the parse_node and node_id.
|
|
|
- auto PopForParseNodeAndNodeId()
|
|
|
- -> std::pair<ParseTree::Node, SemanticsNodeId>;
|
|
|
+ // Pops the top of the stack and returns the parse_node and the ID.
|
|
|
+ template <typename IdT>
|
|
|
+ auto PopWithParseNode() -> std::pair<ParseTree::Node, IdT> {
|
|
|
+ Entry back = PopEntry<IdT>();
|
|
|
+ RequireValidId(back);
|
|
|
+ return {back.parse_node, back.id<IdT>()};
|
|
|
+ }
|
|
|
|
|
|
- // Pops the top of the stack and returns the parse_node and node_id.
|
|
|
- auto PopForParseNodeAndNodeId(ParseNodeKind pop_parse_kind)
|
|
|
- -> std::pair<ParseTree::Node, SemanticsNodeId>;
|
|
|
+ // Pops the top of the stack and returns the parse_node and the ID.
|
|
|
+ template <typename IdT>
|
|
|
+ auto PopWithParseNode(ParseNodeKind pop_parse_kind)
|
|
|
+ -> std::pair<ParseTree::Node, IdT> {
|
|
|
+ auto back = PopWithParseNode<IdT>();
|
|
|
+ RequireParseKind(back.first, pop_parse_kind);
|
|
|
+ return back;
|
|
|
+ }
|
|
|
|
|
|
- // Pops the top of the stack and returns the node_id.
|
|
|
- auto PopForNodeId() -> SemanticsNodeId;
|
|
|
+ // Pops the top of the stack and returns the ID.
|
|
|
+ template <typename IdT>
|
|
|
+ auto Pop() -> IdT {
|
|
|
+ return PopWithParseNode<IdT>().second;
|
|
|
+ }
|
|
|
|
|
|
- // Pops the top of the stack and returns the node_block_id.
|
|
|
- auto PopForNodeBlockId(ParseNodeKind pop_parse_kind) -> SemanticsNodeBlockId;
|
|
|
+ // Pops the top of the stack and returns the ID.
|
|
|
+ template <typename IdT>
|
|
|
+ auto Pop(ParseNodeKind pop_parse_kind) -> IdT {
|
|
|
+ return PopWithParseNode<IdT>(pop_parse_kind).second;
|
|
|
+ }
|
|
|
|
|
|
- // Pops the top of the stack and returns the type_id.
|
|
|
- auto PopForTypeId(ParseNodeKind pop_parse_kind) -> SemanticsTypeId;
|
|
|
+ // Pops the top of the stack, and discards the ID.
|
|
|
+ auto PopAndDiscardId() -> void { PopWithParseNode<SemanticsNodeId>(); }
|
|
|
|
|
|
- // Pops the top of the stack and returns the parse_node and name_id.
|
|
|
- auto PopForParseNodeAndNameId(ParseNodeKind pop_parse_kind)
|
|
|
- -> std::pair<ParseTree::Node, SemanticsStringId>;
|
|
|
+ // Pops the top of the stack, and discards the ID.
|
|
|
+ auto PopAndDiscardId(ParseNodeKind pop_parse_kind) -> void {
|
|
|
+ PopWithParseNode<SemanticsNodeId>(pop_parse_kind);
|
|
|
+ }
|
|
|
|
|
|
// Peeks at the parse_node of the top of the stack.
|
|
|
auto PeekParseNode() -> ParseTree::Node { return stack_.back().parse_node; }
|
|
|
|
|
|
- // Peeks at the name_id of the top of the stack.
|
|
|
- auto PeekForNameId(ParseNodeKind parse_kind) -> SemanticsStringId;
|
|
|
+ // Peeks at the ID of the top of the stack.
|
|
|
+ template <typename IdT>
|
|
|
+ auto Peek(ParseNodeKind parse_kind) -> IdT {
|
|
|
+ Entry back = stack_.back();
|
|
|
+ RequireParseKind(back.parse_node, parse_kind);
|
|
|
+ RequireValidId(back);
|
|
|
+ return back.id<IdT>();
|
|
|
+ }
|
|
|
|
|
|
// Prints the stack for a stack dump.
|
|
|
auto PrintForStackDump(llvm::raw_ostream& output) const -> void;
|
|
|
@@ -119,6 +134,33 @@ class SemanticsNodeStack {
|
|
|
private:
|
|
|
// An entry in stack_.
|
|
|
struct Entry {
|
|
|
+ explicit Entry(ParseTree::Node parse_node, SemanticsNodeId node_id)
|
|
|
+ : parse_node(parse_node), node_id(node_id) {}
|
|
|
+ explicit Entry(ParseTree::Node parse_node,
|
|
|
+ SemanticsNodeBlockId node_block_id)
|
|
|
+ : parse_node(parse_node), node_block_id(node_block_id) {}
|
|
|
+ explicit Entry(ParseTree::Node parse_node, SemanticsStringId name_id)
|
|
|
+ : parse_node(parse_node), name_id(name_id) {}
|
|
|
+ explicit Entry(ParseTree::Node parse_node, SemanticsTypeId type_id)
|
|
|
+ : parse_node(parse_node), type_id(type_id) {}
|
|
|
+
|
|
|
+ // Returns the appropriate ID basaed on type.
|
|
|
+ template <typename T>
|
|
|
+ auto id() -> T& {
|
|
|
+ if constexpr (std::is_same<T, SemanticsNodeId>()) {
|
|
|
+ return node_id;
|
|
|
+ }
|
|
|
+ if constexpr (std::is_same<T, SemanticsNodeBlockId>()) {
|
|
|
+ return node_block_id;
|
|
|
+ }
|
|
|
+ if constexpr (std::is_same<T, SemanticsStringId>()) {
|
|
|
+ return name_id;
|
|
|
+ }
|
|
|
+ if constexpr (std::is_same<T, SemanticsTypeId>()) {
|
|
|
+ return type_id;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
// The node associated with the stack entry.
|
|
|
ParseTree::Node parse_node;
|
|
|
|
|
|
@@ -133,35 +175,54 @@ class SemanticsNodeStack {
|
|
|
SemanticsStringId name_id;
|
|
|
SemanticsTypeId type_id;
|
|
|
};
|
|
|
- };
|
|
|
- static_assert(sizeof(Entry) == 8, "Unexpected Entry size");
|
|
|
|
|
|
- // Which Entry union member to log.
|
|
|
- enum DebugLog {
|
|
|
- None,
|
|
|
- NodeId,
|
|
|
- NodeBlockId,
|
|
|
- NameId,
|
|
|
- TypeId,
|
|
|
+ // APIs rely on type punning. They read node_id.is_valid, even though that
|
|
|
+ // may not be the active union member. These asserts enforce standard layout
|
|
|
+ // in order to help ensure that works.
|
|
|
+ // TODO: Use is_layout_compatible in C++20.
|
|
|
+ static_assert(std::is_standard_layout_v<SemanticsNodeId>,
|
|
|
+ "Need standard layout for type punning");
|
|
|
+ static_assert(std::is_standard_layout_v<SemanticsNodeBlockId>,
|
|
|
+ "Need standard layout for type punning");
|
|
|
+ static_assert(std::is_standard_layout_v<SemanticsStringId>,
|
|
|
+ "Need standard layout for type punning");
|
|
|
+ static_assert(std::is_standard_layout_v<SemanticsTypeId>,
|
|
|
+ "Need standard layout for type punning");
|
|
|
};
|
|
|
-
|
|
|
- // Pushes an entry onto the stack.
|
|
|
- auto PushEntry(Entry entry, DebugLog debug_log) -> void;
|
|
|
+ static_assert(sizeof(Entry) == 8, "Unexpected Entry size");
|
|
|
|
|
|
// Pops an entry.
|
|
|
- auto PopEntry() -> Entry;
|
|
|
-
|
|
|
- // Pops an entry, requiring the specific kind.
|
|
|
- auto PopEntry(ParseNodeKind pop_parse_kind) -> Entry;
|
|
|
+ template <typename IdT>
|
|
|
+ auto PopEntry() -> Entry {
|
|
|
+ Entry back = stack_.pop_back_val();
|
|
|
+ CARBON_VLOG() << "Node Pop " << stack_.size() << ": "
|
|
|
+ << parse_tree_->node_kind(back.parse_node) << " -> "
|
|
|
+ << back.id<IdT>() << "\n";
|
|
|
+ return back;
|
|
|
+ }
|
|
|
|
|
|
// Require an entry to have the given ParseNodeKind.
|
|
|
- auto RequireParseKind(Entry entry, ParseNodeKind require_kind) -> void;
|
|
|
+ auto RequireParseKind(ParseTree::Node parse_node, ParseNodeKind require_kind)
|
|
|
+ -> void {
|
|
|
+ auto actual_kind = parse_tree_->node_kind(parse_node);
|
|
|
+ CARBON_CHECK(require_kind == actual_kind)
|
|
|
+ << "Expected " << require_kind << ", found " << actual_kind;
|
|
|
+ }
|
|
|
|
|
|
// Requires an entry to have a invalid node_id.
|
|
|
- auto RequireSoloParseNode(Entry entry) -> void;
|
|
|
+ auto RequireSoloParseNode(Entry entry) -> void {
|
|
|
+ // See above comment on type punning.
|
|
|
+ CARBON_CHECK(!entry.node_id.is_valid())
|
|
|
+ << "Expected invalid id on " << parse_tree_->node_kind(entry.parse_node)
|
|
|
+ << ", was " << entry.node_id << " (may not be node)";
|
|
|
+ }
|
|
|
|
|
|
// Requires an entry to have a valid id.
|
|
|
- auto RequireValidId(Entry entry) -> void;
|
|
|
+ auto RequireValidId(Entry entry) -> void {
|
|
|
+ // See above comment on type punning.
|
|
|
+ CARBON_CHECK(entry.node_id.is_valid())
|
|
|
+ << "Expected valid id on " << parse_tree_->node_kind(entry.parse_node);
|
|
|
+ }
|
|
|
|
|
|
// The file's parse tree.
|
|
|
const ParseTree* parse_tree_;
|