Przeglądaj źródła

Refactor NodeKind to take advantage of a parse node only having one token kind. (#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.
Jon Ross-Perkins 2 lat temu
rodzic
commit
add31eb4e3

+ 2 - 2
toolchain/parse/context.cpp

@@ -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) {
@@ -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));

+ 25 - 43
toolchain/parse/node_kind.cpp

@@ -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

+ 158 - 212
toolchain/parse/node_kind.def

@@ -9,30 +9,30 @@
 //
 // Supported x-macros are:
 // - CARBON_PARSE_NODE_KIND(Name)
-//   Used as a fallback if other macros are missing. No kinds should use this
-//   directly.
-//   - CARBON_PARSE_NODE_KIND_BRACKET(Name, BracketName, LexTokenKinds)
+//   Used as a fallback if other macros are missing.
+//   - CARBON_PARSE_NODE_KIND_BRACKET(Name, BracketName, LexTokenKind)
 //     Defines a bracketed node kind. BracketName should refer to the node
 //     kind that is the _start_ of the bracketed range.
-//   - CARBON_PARSE_NODE_KIND_CHILD_COUNT(Name, ChildCount, LexTokenKinds)
+//   - CARBON_PARSE_NODE_KIND_CHILD_COUNT(Name, ChildCount, LexTokenKind)
 //     Defines a parse node with a set number of children, often 0. This count
 //     must be correct even when the node contains errors.
-//   - CARBON_PARSE_NODE_KIND_INFIX_OPERATOR(Name)
-//     Defines a parse node for an infix operator, with the Name as token.
-//   - CARBON_PARSE_NODE_KIND_PREFIX_OPERATOR(Name)
-//     Defines a parse node for a prefix operator, with the Name as token.
-//   - CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(Name, LexTokenKinds)
-//     Defines a parse node that corresponds to a token that is a single-token
-//     literal. The token is wrapped for LexTokenKinds.
-//   - CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Name)
-//     A token-based modifier. The Name is the TokenKind, and will be appended
-//     with "Modifier" for the parse kind.
+//     - CARBON_PARSE_NODE_KIND_INFIX_OPERATOR(Name)
+//       Defines a parse node for an infix operator, with the Name as token.
+//     - CARBON_PARSE_NODE_KIND_PREFIX_OPERATOR(Name)
+//       Defines a parse node for a prefix operator, with the Name as token.
+//     - CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(Name, LexTokenKind)
+//       Defines a parse node that corresponds to a token that is a single-token
+//       literal. The token is wrapped for LexTokenKinds.
+//     - CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Name)
+//       A token-based modifier. The Name is the TokenKind, and will be appended
+//       with "Modifier" for the parse kind.
 //
-//   In both cases, LexTokenKinds says which Lex::TokenKind values that this
-//   parse node can correspond to, and is a sequence of:
-//   - CARBON_TOKEN(kind): This node can correspond to this kind of token.
-//   - CARBON_ANY_TOKEN_ON_ERROR: When the `has_error` flag is set, this node
-//     can correspond to any token.
+// LexTokenKind indicates the token kind required on a valid node.
+// It will be either `kind_name` to indicate it's required even if the node is
+// an error, or `CARBON_IF_VALID(kind_name)` to indicate that the kind is
+// not enforced on error. A token kind of `Error` may be used if the kind should
+// never be enforced; this should only be used when the node is either not in
+// trees (`Placeholder`) or is always invalid (such as `InvalidParse`).
 //
 // This tree represents the subset relationship between these macros, where if a
 // specific x-macro isn't defined, it'll fall back to the parent macro.
@@ -63,7 +63,7 @@
 //   #define CARBON_PARSE_NODE_KIND_INFIX_OPERATOR(Name, ...) <code>
 #ifndef CARBON_PARSE_NODE_KIND_INFIX_OPERATOR
 #define CARBON_PARSE_NODE_KIND_INFIX_OPERATOR(Name) \
-  CARBON_PARSE_NODE_KIND_CHILD_COUNT(InfixOperator##Name, 2, CARBON_TOKEN(Name))
+  CARBON_PARSE_NODE_KIND_CHILD_COUNT(InfixOperator##Name, 2, Name)
 #endif
 
 // This is expected to be used with something like:
@@ -72,9 +72,8 @@
 //   #define CARBON_PARSE_NODE_KIND(...)
 //   #define CARBON_PARSE_NODE_KIND_PREFIX_OPERATOR(Name, ...) <code>
 #ifndef CARBON_PARSE_NODE_KIND_PREFIX_OPERATOR
-#define CARBON_PARSE_NODE_KIND_PREFIX_OPERATOR(Name)          \
-  CARBON_PARSE_NODE_KIND_CHILD_COUNT(PrefixOperator##Name, 1, \
-                                     CARBON_TOKEN(Name))
+#define CARBON_PARSE_NODE_KIND_PREFIX_OPERATOR(Name) \
+  CARBON_PARSE_NODE_KIND_CHILD_COUNT(PrefixOperator##Name, 1, Name)
 #endif
 
 // This is expected to be used with something like:
@@ -94,57 +93,49 @@
 //   #define CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Name, ...) <code>
 #ifndef CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER
 #define CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Name) \
-  CARBON_PARSE_NODE_KIND_CHILD_COUNT(Name##Modifier, 0, CARBON_TOKEN(Name))
+  CARBON_PARSE_NODE_KIND_CHILD_COUNT(Name##Modifier, 0, Name)
 #endif
 
 // The start of the file.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(FileStart, 0, CARBON_TOKEN(FileStart))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(FileStart, 0, FileStart)
 
 // The end of the file.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(FileEnd, 0, CARBON_TOKEN(FileEnd))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(FileEnd, 0, FileEnd)
 
 // An invalid parse. Used to balance the parse tree. Always has an error.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(InvalidParse, 0, CARBON_ANY_TOKEN_ON_ERROR)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(InvalidParse, 0, Error)
 
 // An invalid subtree. Always has an error.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(InvalidParseStart, 0,
-                                   CARBON_ANY_TOKEN_ON_ERROR)
-CARBON_PARSE_NODE_KIND_BRACKET(InvalidParseSubtree, InvalidParseStart,
-                               CARBON_ANY_TOKEN_ON_ERROR)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(InvalidParseStart, 0, Error)
+CARBON_PARSE_NODE_KIND_BRACKET(InvalidParseSubtree, InvalidParseStart, Error)
 
-// A placeholder node to be replaced. Its token kind is not enforced even when
-// valid, as a special-case in node_kind.cpp.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(Placeholder, 0, CARBON_ANY_TOKEN_ON_ERROR)
+// A placeholder node to be replaced; it will never exist in a valid parse tree.
+// Its token kind is not enforced even when valid.
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(Placeholder, 0, Error)
 
 // An empty declaration, such as `;`.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(EmptyDecl, 0,
-                                   CARBON_TOKEN(Semi) CARBON_ANY_TOKEN_ON_ERROR)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(EmptyDecl, 0, CARBON_IF_VALID(Semi))
 
 // An identifier name in a non-expression context, such as a declaration.
 CARBON_PARSE_NODE_KIND_CHILD_COUNT(IdentifierName, 0,
-                                   CARBON_TOKEN(Identifier)
-                                       CARBON_ANY_TOKEN_ON_ERROR)
+                                   CARBON_IF_VALID(Identifier))
 
 // An identifier name in an expression context.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(IdentifierNameExpr, 0,
-                                   CARBON_TOKEN(Identifier))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(IdentifierNameExpr, 0, Identifier)
 
 // The `self` value and `Self` type identifier keywords. Typically of the form
 // `self: Self`.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(SelfValueName, 0,
-                                   CARBON_TOKEN(SelfValueIdentifier))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(SelfValueNameExpr, 0,
-                                   CARBON_TOKEN(SelfValueIdentifier))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(SelfTypeNameExpr, 0,
-                                   CARBON_TOKEN(SelfTypeIdentifier))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(SelfValueName, 0, SelfValueIdentifier)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(SelfValueNameExpr, 0, SelfValueIdentifier)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(SelfTypeNameExpr, 0, SelfTypeIdentifier)
 
 // The `base` value keyword, introduced by `base: B`. Typically referenced in
 // an expression, as in `x.base` or `{.base = ...}`, but can also be used as a
 // declared name, as in `{.base: partial B}`.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(BaseName, 0, CARBON_TOKEN(Base))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(BaseName, 0, Base)
 
 // The `package` keyword in an expression.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(PackageExpr, 0, CARBON_TOKEN(Package))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(PackageExpr, 0, Package)
 
 // ----------------------------------------------------------------------------
 
@@ -174,8 +165,8 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(PackageExpr, 0, CARBON_TOKEN(Package))
 // ----------------------------------------------------------------------------
 
 // The name of a package or library for `package`, `import`, and `library`.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(PackageName, 0, CARBON_TOKEN(Identifier))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(LibraryName, 0, CARBON_TOKEN(StringLiteral))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(PackageName, 0, Identifier)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(LibraryName, 0, StringLiteral)
 
 // `package`:
 //   PackageIntroducer
@@ -183,53 +174,50 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(LibraryName, 0, CARBON_TOKEN(StringLiteral))
 //   _optional_ _external_: LibrarySpecifier
 //   PackageApi or PackageImpl
 // PackageDirective
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(PackageIntroducer, 0, CARBON_TOKEN(Package))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(PackageApi, 0, CARBON_TOKEN(Api))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(PackageImpl, 0, CARBON_TOKEN(Impl))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(PackageIntroducer, 0, Package)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(PackageApi, 0, Api)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(PackageImpl, 0, Impl)
 CARBON_PARSE_NODE_KIND_BRACKET(PackageDirective, PackageIntroducer,
-                               CARBON_TOKEN(Semi) CARBON_ANY_TOKEN_ON_ERROR)
+                               CARBON_IF_VALID(Semi))
 
 // `import`:
 //   ImportIntroducer
 //   _optional_ _external_: PackageName
 //   _optional_ _external_: LibrarySpecifier
 // ImportDirective
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImportIntroducer, 0, CARBON_TOKEN(Import))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImportIntroducer, 0, Import)
 CARBON_PARSE_NODE_KIND_BRACKET(ImportDirective, ImportIntroducer,
-                               CARBON_TOKEN(Semi) CARBON_ANY_TOKEN_ON_ERROR)
+                               CARBON_IF_VALID(Semi))
 // `library` as directive:
 //   LibraryIntroducer
 //   DefaultLibrary or _external_: LibraryName
 // LibraryDirective
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(DefaultLibrary, 0, CARBON_TOKEN(Default))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(LibraryIntroducer, 0, CARBON_TOKEN(Library))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(DefaultLibrary, 0, Default)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(LibraryIntroducer, 0, Library)
 CARBON_PARSE_NODE_KIND_BRACKET(LibraryDirective, LibraryIntroducer,
-                               CARBON_TOKEN(Semi) CARBON_ANY_TOKEN_ON_ERROR)
+                               CARBON_IF_VALID(Semi))
 
 // `library` in `package` or `import`:
 //   _external_: LibraryName
 // LibrarySpecifier
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(LibrarySpecifier, 1, CARBON_TOKEN(Library))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(LibrarySpecifier, 1, Library)
 
 // `namespace`:
 //   NamespaceStart
 //   _repeated_ _external_: modifier
 //   _external_: Name or QualifiedDecl
 // Namespace
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(NamespaceStart, 0, CARBON_TOKEN(Namespace))
-CARBON_PARSE_NODE_KIND_BRACKET(Namespace, NamespaceStart,
-                               CARBON_TOKEN(Semi) CARBON_ANY_TOKEN_ON_ERROR)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(NamespaceStart, 0, Namespace)
+CARBON_PARSE_NODE_KIND_BRACKET(Namespace, NamespaceStart, CARBON_IF_VALID(Semi))
 
 // A code block:
 //   CodeBlockStart
 //   _repeated_ _external_: statement
 // CodeBlock
 CARBON_PARSE_NODE_KIND_CHILD_COUNT(CodeBlockStart, 0,
-                                   CARBON_TOKEN(OpenCurlyBrace)
-                                       CARBON_ANY_TOKEN_ON_ERROR)
+                                   CARBON_IF_VALID(OpenCurlyBrace))
 CARBON_PARSE_NODE_KIND_BRACKET(CodeBlock, CodeBlockStart,
-                               CARBON_TOKEN(CloseCurlyBrace)
-                                   CARBON_ANY_TOKEN_ON_ERROR)
+                               CARBON_IF_VALID(CloseCurlyBrace))
 
 // `fn`:
 //     FunctionIntroducer
@@ -245,14 +233,14 @@ CARBON_PARSE_NODE_KIND_BRACKET(CodeBlock, CodeBlockStart,
 // The above is the structure for a definition; for a declaration,
 // FunctionDefinitionStart and later nodes are removed and replaced by
 // FunctionDecl.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(FunctionIntroducer, 0, CARBON_TOKEN(Fn))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ReturnType, 1, CARBON_TOKEN(MinusGreater))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(FunctionIntroducer, 0, Fn)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ReturnType, 1, MinusGreater)
 CARBON_PARSE_NODE_KIND_BRACKET(FunctionDefinitionStart, FunctionIntroducer,
-                               CARBON_TOKEN(OpenCurlyBrace))
+                               OpenCurlyBrace)
 CARBON_PARSE_NODE_KIND_BRACKET(FunctionDefinition, FunctionDefinitionStart,
-                               CARBON_TOKEN(CloseCurlyBrace))
+                               CloseCurlyBrace)
 CARBON_PARSE_NODE_KIND_BRACKET(FunctionDecl, FunctionIntroducer,
-                               CARBON_TOKEN(Semi) CARBON_ANY_TOKEN_ON_ERROR)
+                               CARBON_IF_VALID(Semi))
 
 // A tuple pattern:
 //   TuplePatternStart
@@ -263,11 +251,9 @@ CARBON_PARSE_NODE_KIND_BRACKET(FunctionDecl, FunctionIntroducer,
 //
 // Patterns and PatternListComma may repeat with PatternListComma as a
 // separator.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(TuplePatternStart, 0,
-                                   CARBON_TOKEN(OpenParen))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(PatternListComma, 0, CARBON_TOKEN(Comma))
-CARBON_PARSE_NODE_KIND_BRACKET(TuplePattern, TuplePatternStart,
-                               CARBON_TOKEN(CloseParen))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(TuplePatternStart, 0, OpenParen)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(PatternListComma, 0, Comma)
+CARBON_PARSE_NODE_KIND_BRACKET(TuplePattern, TuplePatternStart, CloseParen)
 
 // An implicit parameter list:
 //   ImplicitParamListStart
@@ -278,10 +264,9 @@ CARBON_PARSE_NODE_KIND_BRACKET(TuplePattern, TuplePatternStart,
 //
 // Patterns and PatternListComma may repeat with PatternListComma as a
 // separator.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImplicitParamListStart, 0,
-                                   CARBON_TOKEN(OpenSquareBracket))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImplicitParamListStart, 0, OpenSquareBracket)
 CARBON_PARSE_NODE_KIND_BRACKET(ImplicitParamList, ImplicitParamListStart,
-                               CARBON_TOKEN(CloseSquareBracket))
+                               CloseSquareBracket)
 
 // An array type, such as  `[i32; 3]` or `[i32;]`:
 //     ArrayExprStart
@@ -289,12 +274,9 @@ CARBON_PARSE_NODE_KIND_BRACKET(ImplicitParamList, ImplicitParamListStart,
 //   ArrayExprSemi
 //   _optional_ _external_: expression
 // ArrayExpr
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ArrayExprStart, 0,
-                                   CARBON_TOKEN(OpenSquareBracket))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ArrayExprSemi, 2,
-                                   CARBON_TOKEN(Semi) CARBON_ANY_TOKEN_ON_ERROR)
-CARBON_PARSE_NODE_KIND_BRACKET(ArrayExpr, ArrayExprSemi,
-                               CARBON_TOKEN(CloseSquareBracket))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ArrayExprStart, 0, OpenSquareBracket)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ArrayExprSemi, 2, CARBON_IF_VALID(Semi))
+CARBON_PARSE_NODE_KIND_BRACKET(ArrayExpr, ArrayExprSemi, CloseSquareBracket)
 
 // A binding pattern, such as `name: Type`:
 //       Name or SelfValueName
@@ -302,13 +284,10 @@ CARBON_PARSE_NODE_KIND_BRACKET(ArrayExpr, ArrayExprSemi,
 //     [Generic]BindingPattern
 //   _optional_ Address
 // _optional_ Template
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(BindingPattern, 2,
-                                   CARBON_TOKEN(Colon)
-                                       CARBON_ANY_TOKEN_ON_ERROR)
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(GenericBindingPattern, 2,
-                                   CARBON_TOKEN(ColonExclaim))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(Address, 1, CARBON_TOKEN(Addr))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(Template, 1, CARBON_TOKEN(Template))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(BindingPattern, 2, CARBON_IF_VALID(Colon))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(GenericBindingPattern, 2, ColonExclaim)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(Address, 1, Addr)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(Template, 1, Template)
 
 // `let`:
 //   LetIntroducer
@@ -319,10 +298,9 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(Template, 1, CARBON_TOKEN(Template))
 // LetDecl
 //
 // Modifier keywords only appear for `let` declarations, not `let` statements.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(LetIntroducer, 0, CARBON_TOKEN(Let))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(LetInitializer, 0, CARBON_TOKEN(Equal))
-CARBON_PARSE_NODE_KIND_BRACKET(LetDecl, LetIntroducer,
-                               CARBON_TOKEN(Semi) CARBON_ANY_TOKEN_ON_ERROR)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(LetIntroducer, 0, Let)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(LetInitializer, 0, Equal)
+CARBON_PARSE_NODE_KIND_BRACKET(LetDecl, LetIntroducer, CARBON_IF_VALID(Semi))
 
 // `var` and `returned var`:
 //   VariableIntroducer
@@ -338,43 +316,37 @@ CARBON_PARSE_NODE_KIND_BRACKET(LetDecl, LetIntroducer,
 // whereas the returned modifier only appears on `var` statements.
 // The VariableInitializer and following expression are paired: either both will
 // be present, or neither will.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(VariableIntroducer, 0,
-                                   CARBON_TOKEN(Var) CARBON_ANY_TOKEN_ON_ERROR)
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ReturnedModifier, 0, CARBON_TOKEN(Returned))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(VariableInitializer, 0, CARBON_TOKEN(Equal))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(VariableIntroducer, 0, CARBON_IF_VALID(Var))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ReturnedModifier, 0, Returned)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(VariableInitializer, 0, Equal)
 CARBON_PARSE_NODE_KIND_BRACKET(VariableDecl, VariableIntroducer,
-                               CARBON_TOKEN(Semi) CARBON_ANY_TOKEN_ON_ERROR)
+                               CARBON_IF_VALID(Semi))
 
 // An expression statement:
 //   _external_: expression
 // ExprStatement
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ExprStatement, 1,
-                                   CARBON_TOKEN(Semi) CARBON_ANY_TOKEN_ON_ERROR)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ExprStatement, 1, CARBON_IF_VALID(Semi))
 
 // `break`:
 //   BreakStatementStart
 // BreakStatement
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(BreakStatementStart, 0, CARBON_TOKEN(Break))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(BreakStatement, 1,
-                                   CARBON_TOKEN(Semi) CARBON_ANY_TOKEN_ON_ERROR)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(BreakStatementStart, 0, Break)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(BreakStatement, 1, CARBON_IF_VALID(Semi))
 
 // `continue`:
 //   ContinueStatementStart
 // ContinueStatement
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ContinueStatementStart, 0,
-                                   CARBON_TOKEN(Continue))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ContinueStatement, 1,
-                                   CARBON_TOKEN(Semi) CARBON_ANY_TOKEN_ON_ERROR)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ContinueStatementStart, 0, Continue)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ContinueStatement, 1, CARBON_IF_VALID(Semi))
 
 // `return`:
 //   ReturnStatementStart
 //   _optional_ ReturnVarModifier or _external_: expression
 // ReturnStatement
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ReturnStatementStart, 0,
-                                   CARBON_TOKEN(Return))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ReturnVarModifier, 0, CARBON_TOKEN(Var))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ReturnStatementStart, 0, Return)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ReturnVarModifier, 0, Var)
 CARBON_PARSE_NODE_KIND_BRACKET(ReturnStatement, ReturnStatementStart,
-                               CARBON_TOKEN(Semi) CARBON_ANY_TOKEN_ON_ERROR)
+                               CARBON_IF_VALID(Semi))
 
 // `for`:
 //     ForHeaderStart
@@ -388,14 +360,11 @@ CARBON_PARSE_NODE_KIND_BRACKET(ReturnStatement, ReturnStatementStart,
 //
 // Versus a normal `var`, ForIn replaces VariableDecl.
 CARBON_PARSE_NODE_KIND_CHILD_COUNT(ForHeaderStart, 0,
-                                   CARBON_TOKEN(OpenParen)
-                                       CARBON_ANY_TOKEN_ON_ERROR)
-CARBON_PARSE_NODE_KIND_BRACKET(ForIn, VariableIntroducer,
-                               CARBON_TOKEN(In) CARBON_ANY_TOKEN_ON_ERROR)
+                                   CARBON_IF_VALID(OpenParen))
+CARBON_PARSE_NODE_KIND_BRACKET(ForIn, VariableIntroducer, CARBON_IF_VALID(In))
 CARBON_PARSE_NODE_KIND_BRACKET(ForHeader, ForHeaderStart,
-                               CARBON_TOKEN(CloseParen)
-                                   CARBON_ANY_TOKEN_ON_ERROR)
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ForStatement, 2, CARBON_TOKEN(For))
+                               CARBON_IF_VALID(CloseParen))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ForStatement, 2, For)
 
 // `if` statement + `else`:
 //     IfConditionStart
@@ -408,13 +377,11 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(ForStatement, 2, CARBON_TOKEN(For))
 //
 // IfStatementElse and the following node are optional based on `else` presence.
 CARBON_PARSE_NODE_KIND_CHILD_COUNT(IfConditionStart, 0,
-                                   CARBON_TOKEN(OpenParen)
-                                       CARBON_ANY_TOKEN_ON_ERROR)
+                                   CARBON_IF_VALID(OpenParen))
 CARBON_PARSE_NODE_KIND_BRACKET(IfCondition, IfConditionStart,
-                               CARBON_TOKEN(CloseParen)
-                                   CARBON_ANY_TOKEN_ON_ERROR)
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(IfStatementElse, 0, CARBON_TOKEN(Else))
-CARBON_PARSE_NODE_KIND_BRACKET(IfStatement, IfCondition, CARBON_TOKEN(If))
+                               CARBON_IF_VALID(CloseParen))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(IfStatementElse, 0, Else)
+CARBON_PARSE_NODE_KIND_BRACKET(IfStatement, IfCondition, If)
 
 // `while`:
 //     WhileConditionStart
@@ -422,21 +389,17 @@ CARBON_PARSE_NODE_KIND_BRACKET(IfStatement, IfCondition, CARBON_TOKEN(If))
 //   WhileCondition
 //   _external_: CodeBlock
 // WhileStatement
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(WhileConditionStart, 0,
-                                   CARBON_TOKEN(OpenParen))
-CARBON_PARSE_NODE_KIND_BRACKET(WhileCondition, WhileConditionStart,
-                               CARBON_TOKEN(CloseParen))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(WhileStatement, 2, CARBON_TOKEN(While))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(WhileConditionStart, 0, OpenParen)
+CARBON_PARSE_NODE_KIND_BRACKET(WhileCondition, WhileConditionStart, CloseParen)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(WhileStatement, 2, While)
 
 // Index expressions, such as `a[1]`:
 //     _external_: expression
 //   IndexExprStart
 //   _external_: expression
 // IndexExpr
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(IndexExprStart, 1,
-                                   CARBON_TOKEN(OpenSquareBracket))
-CARBON_PARSE_NODE_KIND_BRACKET(IndexExpr, IndexExprStart,
-                               CARBON_TOKEN(CloseSquareBracket))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(IndexExprStart, 1, OpenSquareBracket)
+CARBON_PARSE_NODE_KIND_BRACKET(IndexExpr, IndexExprStart, CloseSquareBracket)
 
 // Parenthesized single expressions, such as `(2)`:
 //   ExprOpenParen
@@ -452,12 +415,10 @@ CARBON_PARSE_NODE_KIND_BRACKET(IndexExpr, IndexExprStart,
 //
 // Expressions and TupleLiteralComma may repeat with TupleLiteralComma as a
 // separator.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ExprOpenParen, 0, CARBON_TOKEN(OpenParen))
-CARBON_PARSE_NODE_KIND_BRACKET(ParenExpr, ExprOpenParen,
-                               CARBON_TOKEN(CloseParen))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(TupleLiteralComma, 0, CARBON_TOKEN(Comma))
-CARBON_PARSE_NODE_KIND_BRACKET(TupleLiteral, ExprOpenParen,
-                               CARBON_TOKEN(CloseParen))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ExprOpenParen, 0, OpenParen)
+CARBON_PARSE_NODE_KIND_BRACKET(ParenExpr, ExprOpenParen, CloseParen)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(TupleLiteralComma, 0, Comma)
+CARBON_PARSE_NODE_KIND_BRACKET(TupleLiteral, ExprOpenParen, CloseParen)
 
 // Call expressions, such as `a()`:
 //     _external_: expression
@@ -468,10 +429,9 @@ CARBON_PARSE_NODE_KIND_BRACKET(TupleLiteral, ExprOpenParen,
 // CallExpr
 //
 // Exprs and CallExprComma may repeat with CallExprComma as a separator.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(CallExprStart, 1, CARBON_TOKEN(OpenParen))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(CallExprComma, 0, CARBON_TOKEN(Comma))
-CARBON_PARSE_NODE_KIND_BRACKET(CallExpr, CallExprStart,
-                               CARBON_TOKEN(CloseParen))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(CallExprStart, 1, OpenParen)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(CallExprComma, 0, Comma)
+CARBON_PARSE_NODE_KIND_BRACKET(CallExpr, CallExprStart, CloseParen)
 
 // A qualified declaration, such as `a.b`:
 //   _external_: Name or QualifiedDecl
@@ -480,41 +440,37 @@ CARBON_PARSE_NODE_KIND_BRACKET(CallExpr, CallExprStart,
 //
 // TODO: This will eventually more general expressions, for example with
 // `GenericType(type_args).ChildType(child_type_args).Name`.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(QualifiedDecl, 2, CARBON_TOKEN(Period))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(QualifiedDecl, 2, Period)
 
 // A member access expression, such as `a.b` or
 // `GetObject().(Interface.member)`:
 //   _external_: lhs expression
 //   _external_: rhs expression
 // QualifiedExpr
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(MemberAccessExpr, 2, CARBON_TOKEN(Period))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(MemberAccessExpr, 2, Period)
 
 // A pointer member access expression, such as `a->b` or
 // `GetObject()->(Interface.member)`:
 //   _external_: lhs expression
 //   _external_: rhs expression
 // QualifiedExpr
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(PointerMemberAccessExpr, 2,
-                                   CARBON_TOKEN(MinusGreater))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(PointerMemberAccessExpr, 2, MinusGreater)
 
 // A value literal.
-CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(BoolLiteralFalse, CARBON_TOKEN(False))
-CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(BoolLiteralTrue, CARBON_TOKEN(True))
-CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(IntLiteral, CARBON_TOKEN(IntLiteral))
-CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(RealLiteral, CARBON_TOKEN(RealLiteral))
-CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(StringLiteral, CARBON_TOKEN(StringLiteral))
+CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(BoolLiteralFalse, False)
+CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(BoolLiteralTrue, True)
+CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(IntLiteral, IntLiteral)
+CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(RealLiteral, RealLiteral)
+CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(StringLiteral, StringLiteral)
 
 // A type literal.
-CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(BoolTypeLiteral, CARBON_TOKEN(Bool))
-CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(IntTypeLiteral,
-                                     CARBON_TOKEN(IntTypeLiteral))
+CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(BoolTypeLiteral, Bool)
+CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(IntTypeLiteral, IntTypeLiteral)
 CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(UnsignedIntTypeLiteral,
-                                     CARBON_TOKEN(UnsignedIntTypeLiteral))
-CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(FloatTypeLiteral,
-                                     CARBON_TOKEN(FloatTypeLiteral))
-CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(StringTypeLiteral,
-                                     CARBON_TOKEN(StringTypeLiteral))
-CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(TypeTypeLiteral, CARBON_TOKEN(Type))
+                                     UnsignedIntTypeLiteral)
+CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(FloatTypeLiteral, FloatTypeLiteral)
+CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(StringTypeLiteral, StringTypeLiteral)
+CARBON_PARSE_NODE_KIND_TOKEN_LITERAL(TypeTypeLiteral, Type)
 
 // clang-format off
 
@@ -571,16 +527,15 @@ CARBON_PARSE_NODE_KIND_INFIX_OPERATOR(StarEqual)
 //   ShortCircuitOperand(And|Or)
 //   _external_: expression
 // ShortCircuitOperand(And|Or)
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ShortCircuitOperandAnd, 1, CARBON_TOKEN(And))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ShortCircuitOperandOr, 1, CARBON_TOKEN(Or))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ShortCircuitOperatorAnd, 2,
-                                   CARBON_TOKEN(And))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ShortCircuitOperatorOr, 2, CARBON_TOKEN(Or))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ShortCircuitOperandAnd, 1, And)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ShortCircuitOperandOr, 1, Or)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ShortCircuitOperatorAnd, 2, And)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ShortCircuitOperatorOr, 2, Or)
 
 // A postfix operator, currently only `*`:
 //   _external_: expression
 // PostfixOperatorStar
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(PostfixOperatorStar, 1, CARBON_TOKEN(Star))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(PostfixOperatorStar, 1, Star)
 
 // `if` expression + `then` + `else`:
 //     _external_: expression
@@ -589,10 +544,9 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(PostfixOperatorStar, 1, CARBON_TOKEN(Star))
 //   IfExprThen
 //   _external_: expression
 // IfExprElse
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(IfExprIf, 1, CARBON_TOKEN(If))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(IfExprThen, 1, CARBON_TOKEN(Then))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(IfExprElse, 3,
-                                   CARBON_TOKEN(Else) CARBON_ANY_TOKEN_ON_ERROR)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(IfExprIf, 1, If)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(IfExprThen, 1, Then)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(IfExprElse, 3, CARBON_IF_VALID(Else))
 
 // Struct literals, such as `{.a = 0}`:
 //   StructLiteralOrStructTypeLiteralStart
@@ -621,18 +575,17 @@ CARBON_PARSE_NODE_KIND_CHILD_COUNT(IfExprElse, 3,
 // may be replaced by InvalidParse, which may have a preceding sibling
 // StructFieldDesignator if one was successfully parsed.
 CARBON_PARSE_NODE_KIND_CHILD_COUNT(StructLiteralOrStructTypeLiteralStart, 0,
-                                   CARBON_TOKEN(OpenCurlyBrace))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(StructFieldDesignator, 1,
-                                   CARBON_TOKEN(Period))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(StructFieldValue, 2, CARBON_TOKEN(Equal))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(StructFieldType, 2, CARBON_TOKEN(Colon))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(StructComma, 0, CARBON_TOKEN(Comma))
+                                   OpenCurlyBrace)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(StructFieldDesignator, 1, Period)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(StructFieldValue, 2, Equal)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(StructFieldType, 2, Colon)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(StructComma, 0, Comma)
 CARBON_PARSE_NODE_KIND_BRACKET(StructLiteral,
                                StructLiteralOrStructTypeLiteralStart,
-                               CARBON_TOKEN(CloseCurlyBrace))
+                               CloseCurlyBrace)
 CARBON_PARSE_NODE_KIND_BRACKET(StructTypeLiteral,
                                StructLiteralOrStructTypeLiteralStart,
-                               CARBON_TOKEN(CloseCurlyBrace))
+                               CloseCurlyBrace)
 
 // Various modifiers. These are all a single token.
 CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Abstract)
@@ -656,13 +609,13 @@ CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER(Virtual)
 // The above is the structure for a definition; for a declaration,
 // ClassDefinitionStart and later nodes are removed and replaced by
 // ClassDecl.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ClassIntroducer, 0, CARBON_TOKEN(Class))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ClassIntroducer, 0, Class)
 CARBON_PARSE_NODE_KIND_BRACKET(ClassDefinitionStart, ClassIntroducer,
-                               CARBON_TOKEN(OpenCurlyBrace))
+                               OpenCurlyBrace)
 CARBON_PARSE_NODE_KIND_BRACKET(ClassDefinition, ClassDefinitionStart,
-                               CARBON_TOKEN(CloseCurlyBrace))
+                               CloseCurlyBrace)
 CARBON_PARSE_NODE_KIND_BRACKET(ClassDecl, ClassIntroducer,
-                               CARBON_TOKEN(Semi) CARBON_ANY_TOKEN_ON_ERROR)
+                               CARBON_IF_VALID(Semi))
 
 // `base`:
 //   BaseIntroducer
@@ -670,10 +623,9 @@ CARBON_PARSE_NODE_KIND_BRACKET(ClassDecl, ClassIntroducer,
 //   BaseColon
 //   _external_: expression
 // BaseDecl
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(BaseIntroducer, 0, CARBON_TOKEN(Base))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(BaseColon, 0, CARBON_TOKEN(Colon))
-CARBON_PARSE_NODE_KIND_BRACKET(BaseDecl, BaseIntroducer,
-                               CARBON_TOKEN(Semi) CARBON_ANY_TOKEN_ON_ERROR)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(BaseIntroducer, 0, Base)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(BaseColon, 0, Colon)
+CARBON_PARSE_NODE_KIND_BRACKET(BaseDecl, BaseIntroducer, CARBON_IF_VALID(Semi))
 
 // `interface`:
 //     InterfaceIntroducer
@@ -686,14 +638,13 @@ CARBON_PARSE_NODE_KIND_BRACKET(BaseDecl, BaseIntroducer,
 // The above is the structure for a definition; for a declaration,
 // InterfaceDefinitionStart and later nodes are removed and replaced by
 // InterfaceDecl.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(InterfaceIntroducer, 0,
-                                   CARBON_TOKEN(Interface))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(InterfaceIntroducer, 0, Interface)
 CARBON_PARSE_NODE_KIND_BRACKET(InterfaceDefinitionStart, InterfaceIntroducer,
-                               CARBON_TOKEN(OpenCurlyBrace))
+                               OpenCurlyBrace)
 CARBON_PARSE_NODE_KIND_BRACKET(InterfaceDefinition, InterfaceDefinitionStart,
-                               CARBON_TOKEN(CloseCurlyBrace))
+                               CloseCurlyBrace)
 CARBON_PARSE_NODE_KIND_BRACKET(InterfaceDecl, InterfaceIntroducer,
-                               CARBON_TOKEN(Semi) CARBON_ANY_TOKEN_ON_ERROR)
+                               CARBON_IF_VALID(Semi))
 
 // `impl ... as`:
 //     ImplIntroducer
@@ -709,19 +660,18 @@ CARBON_PARSE_NODE_KIND_BRACKET(InterfaceDecl, InterfaceIntroducer,
 // The above is the structure for a definition; for a declaration,
 // ImplDefinitionStart and later nodes are removed and replaced by
 // ImplDecl.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImplIntroducer, 0, CARBON_TOKEN(Impl))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImplIntroducer, 0, Impl)
 
 // `forall ...`:
 //   _external_: ImplicitParamList
 // ImplForall
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImplForall, 1, CARBON_TOKEN(Forall))
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImplAs, 0, CARBON_TOKEN(As))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImplForall, 1, Forall)
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(ImplAs, 0, As)
 CARBON_PARSE_NODE_KIND_BRACKET(ImplDefinitionStart, ImplIntroducer,
-                               CARBON_TOKEN(OpenCurlyBrace))
+                               OpenCurlyBrace)
 CARBON_PARSE_NODE_KIND_BRACKET(ImplDefinition, ImplDefinitionStart,
-                               CARBON_TOKEN(CloseCurlyBrace))
-CARBON_PARSE_NODE_KIND_BRACKET(ImplDecl, ImplIntroducer,
-                               CARBON_TOKEN(Semi) CARBON_ANY_TOKEN_ON_ERROR)
+                               CloseCurlyBrace)
+CARBON_PARSE_NODE_KIND_BRACKET(ImplDecl, ImplIntroducer, CARBON_IF_VALID(Semi))
 
 // `constraint`:
 //     NamedConstraintIntroducer
@@ -734,16 +684,13 @@ CARBON_PARSE_NODE_KIND_BRACKET(ImplDecl, ImplIntroducer,
 // The above is the structure for a definition; for a declaration,
 // NamedConstraintDefinitionStart and later nodes are removed and replaced by
 // NamedConstraintDecl.
-CARBON_PARSE_NODE_KIND_CHILD_COUNT(NamedConstraintIntroducer, 0,
-                                   CARBON_TOKEN(Constraint))
+CARBON_PARSE_NODE_KIND_CHILD_COUNT(NamedConstraintIntroducer, 0, Constraint)
 CARBON_PARSE_NODE_KIND_BRACKET(NamedConstraintDefinitionStart,
-                               NamedConstraintIntroducer,
-                               CARBON_TOKEN(OpenCurlyBrace))
+                               NamedConstraintIntroducer, OpenCurlyBrace)
 CARBON_PARSE_NODE_KIND_BRACKET(NamedConstraintDefinition,
-                               NamedConstraintDefinitionStart,
-                               CARBON_TOKEN(CloseCurlyBrace))
+                               NamedConstraintDefinitionStart, CloseCurlyBrace)
 CARBON_PARSE_NODE_KIND_BRACKET(NamedConstraintDecl, NamedConstraintIntroducer,
-                               CARBON_TOKEN(Semi))
+                               Semi)
 
 #undef CARBON_PARSE_NODE_KIND
 #undef CARBON_PARSE_NODE_KIND_BRACKET
@@ -752,5 +699,4 @@ CARBON_PARSE_NODE_KIND_BRACKET(NamedConstraintDecl, NamedConstraintIntroducer,
 #undef CARBON_PARSE_NODE_KIND_PREFIX_OPERATOR
 #undef CARBON_PARSE_NODE_KIND_TOKEN_LITERAL
 #undef CARBON_PARSE_NODE_KIND_TOKEN_MODIFIER
-#undef CARBON_TOKEN
-#undef CARBON_ANY_TOKEN_ON_ERROR
+#undef CARBON_IF_VALID

+ 5 - 5
toolchain/parse/node_kind.h

@@ -24,6 +24,11 @@ class NodeKind : public CARBON_ENUM_BASE(NodeKind) {
 #define CARBON_PARSE_NODE_KIND(Name) CARBON_ENUM_CONSTANT_DECL(Name)
 #include "toolchain/parse/node_kind.def"
 
+  // Validates that a `parse_node_kind` parser node can be generated for a
+  // `lex_token_kind` lexer token.
+  auto CheckMatchesTokenKind(Lex::TokenKind lex_token_kind, bool has_error)
+      -> void;
+
   // Returns true if the node is bracketed; otherwise, child_count is used.
   auto has_bracket() const -> bool;
 
@@ -45,11 +50,6 @@ class NodeKind : public CARBON_ENUM_BASE(NodeKind) {
 // We expect the parse node kind to fit compactly into 8 bits.
 static_assert(sizeof(NodeKind) == 1, "Kind objects include padding!");
 
-// Validates that a `parse_node_kind` parser node can be generated for a
-// `lex_token_kind` lexer token.
-void CheckNodeMatchesLexerToken(NodeKind parse_node_kind,
-                                Lex::TokenKind lex_token_kind, bool has_error);
-
 }  // namespace Carbon::Parse
 
 #endif  // CARBON_TOOLCHAIN_PARSE_NODE_KIND_H_