Skip to content

Commit

Permalink
Refactor NodeKind to take advantage of a parse node only having one t…
Browse files Browse the repository at this point in the history
…oken kind. (carbon-language#3486)

This builds on the series of changes to NodeKinds, aiming to simplify
the NodeKind implementation a little, also making it clearer that
there's a single associated token for each parse node (or, for
placeholders/invalid parses, not validated).

Note that prior to the relevant changes, there were nodes with multiple
tokens. This change is also locking in the approach of one token per
parse node, by refactoring macros to stop supporting multiple.
  • Loading branch information
jonmeow committed Dec 13, 2023
1 parent 550559e commit add31eb
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 262 deletions.
4 changes: 2 additions & 2 deletions toolchain/parse/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ Context::Context(Tree& tree, Lex::TokenizedBuffer& tokens,

auto Context::AddLeafNode(NodeKind kind, Lex::TokenIndex token, bool has_error)
-> void {
CheckNodeMatchesLexerToken(kind, tokens_->GetKind(token), has_error);
kind.CheckMatchesTokenKind(tokens_->GetKind(token), has_error);
tree_->node_impls_.push_back(
Tree::NodeImpl(kind, has_error, token, /*subtree_size=*/1));
if (has_error) {
Expand All @@ -79,7 +79,7 @@ auto Context::AddLeafNode(NodeKind kind, Lex::TokenIndex token, bool has_error)

auto Context::AddNode(NodeKind kind, Lex::TokenIndex token, int subtree_start,
bool has_error) -> void {
CheckNodeMatchesLexerToken(kind, tokens_->GetKind(token), has_error);
kind.CheckMatchesTokenKind(tokens_->GetKind(token), has_error);
int subtree_size = tree_->size() - subtree_start + 1;
tree_->node_impls_.push_back(
Tree::NodeImpl(kind, has_error, token, subtree_size));
Expand Down
68 changes: 25 additions & 43 deletions toolchain/parse/node_kind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,51 +47,33 @@ auto NodeKind::child_count() const -> int32_t {
return child_count;
}

// NOLINTNEXTLINE(readability-function-size): It's hard to extract macros.
auto CheckNodeMatchesLexerToken(NodeKind node_kind, Lex::TokenKind token_kind,
bool has_error) -> void {
// As a special-case, a placeholder node may correspond to any lexer token.
if (node_kind == NodeKind::Placeholder) {
return;
}

switch (node_kind) {
// Use `CARBON_LOG CARBON_ANY_TOKEN` to discover which combinations happen
// in practice.
#define CARBON_LOG \
llvm::errs() << "ZZZ: Created parse node with NodeKind " << node_kind \
<< " and has_error " << has_error << " for lexical token " \
<< token_kind << "\n";

#define CARBON_TOKEN(Expected) \
if (token_kind == Lex::TokenKind::Expected) { \
return; \
}

#define CARBON_ANY_TOKEN_ON_ERROR \
if (has_error) { \
return; \
}

#define CARBON_CASE(Name, MatchActions) \
case NodeKind::Name: \
MatchActions; /* NOLINT(bugprone-macro-parentheses) */ \
break;

#define CARBON_PARSE_NODE_KIND_BRACKET(Name, BracketName, MatchActions) \
CARBON_CASE(Name, MatchActions)

#define CARBON_PARSE_NODE_KIND_CHILD_COUNT(Name, Size, MatchActions) \
CARBON_CASE(Name, MatchActions)

auto NodeKind::CheckMatchesTokenKind(Lex::TokenKind token_kind, bool has_error)
-> void {
static constexpr Lex::TokenKind TokenIfValid[] = {
#define CARBON_IF_VALID(LexTokenKind) LexTokenKind
#define CARBON_PARSE_NODE_KIND_BRACKET(Name, BracketName, LexTokenKind) \
Lex::TokenKind::LexTokenKind,
#define CARBON_PARSE_NODE_KIND_CHILD_COUNT(Name, Size, LexTokenKind) \
Lex::TokenKind::LexTokenKind,
#include "toolchain/parse/node_kind.def"
};
static constexpr Lex::TokenKind TokenIfError[] = {
#define CARBON_IF_VALID(LexTokenKind) Error
#define CARBON_PARSE_NODE_KIND_BRACKET(Name, BracketName, LexTokenKind) \
Lex::TokenKind::LexTokenKind,
#define CARBON_PARSE_NODE_KIND_CHILD_COUNT(Name, Size, LexTokenKind) \
Lex::TokenKind::LexTokenKind,
#include "toolchain/parse/node_kind.def"
};

#undef CARBON_LOG
#undef CARBON_CASE
}
CARBON_FATAL() << "Created parse node with NodeKind " << node_kind
<< " and has_error " << has_error
<< " for unexpected lexical token " << token_kind;
Lex::TokenKind expected_token_kind =
has_error ? TokenIfError[AsInt()] : TokenIfValid[AsInt()];
// Error indicates that the kind shouldn't be enforced.
CARBON_CHECK(Lex::TokenKind::Error == expected_token_kind ||
token_kind == expected_token_kind)
<< "Created parse node with NodeKind " << *this << " and has_error "
<< has_error << " for lexical token kind " << token_kind
<< ", but expected token kind " << expected_token_kind;
}

} // namespace Carbon::Parse
Loading

0 comments on commit add31eb

Please sign in to comment.