blob: 586123ad51be04e6fec1733b7966aed53cbb8312 [file] [log] [blame]
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/source/line_info.dart';
/// AST visitor that prints tokens into their original positions.
class AstTextPrinter extends ThrowingAstVisitor<void> {
final StringBuffer _buffer;
final LineInfo _lineInfo;
Token _last;
int _lastEnd = 0;
int _lastEndLine = 0;
AstTextPrinter(this._buffer, this._lineInfo);
@override
void visitAdjacentStrings(AdjacentStrings node) {
_nodeList(node.strings);
}
@override
void visitAnnotation(Annotation node) {
_token(node.atSign);
node.name.accept(this);
_token(node.period);
node.constructorName?.accept(this);
node.arguments?.accept(this);
}
@override
void visitArgumentList(ArgumentList node) {
_token(node.leftParenthesis);
_nodeList(node.arguments, node.rightParenthesis);
_token(node.rightParenthesis);
}
@override
void visitAsExpression(AsExpression node) {
node.expression.accept(this);
_token(node.asOperator);
node.type.accept(this);
}
@override
void visitAssertInitializer(AssertInitializer node) {
_token(node.assertKeyword);
_token(node.leftParenthesis);
node.condition.accept(this);
_tokenIfNot(node.condition.endToken.next, node.rightParenthesis);
node.message?.accept(this);
_tokenIfNot(node.message?.endToken?.next, node.rightParenthesis);
_token(node.rightParenthesis);
}
@override
void visitAssertStatement(AssertStatement node) {
_token(node.assertKeyword);
_token(node.leftParenthesis);
node.condition.accept(this);
_tokenIfNot(node.condition.endToken.next, node.rightParenthesis);
node.message?.accept(this);
_tokenIfNot(node.message?.endToken?.next, node.rightParenthesis);
_token(node.rightParenthesis);
_token(node.semicolon);
}
@override
void visitAssignmentExpression(AssignmentExpression node) {
node.leftHandSide.accept(this);
_token(node.operator);
node.rightHandSide.accept(this);
}
@override
void visitAwaitExpression(AwaitExpression node) {
_token(node.awaitKeyword);
node.expression.accept(this);
}
@override
void visitBinaryExpression(BinaryExpression node) {
node.leftOperand.accept(this);
_token(node.operator);
node.rightOperand.accept(this);
}
@override
void visitBlock(Block node) {
_token(node.leftBracket);
_nodeList(node.statements);
_token(node.rightBracket);
}
@override
void visitBlockFunctionBody(BlockFunctionBody node) {
_functionBody(node);
node.block.accept(this);
}
@override
void visitBooleanLiteral(BooleanLiteral node) {
_token(node.literal);
}
@override
void visitBreakStatement(BreakStatement node) {
_token(node.breakKeyword);
node.label?.accept(this);
_token(node.semicolon);
}
@override
void visitCascadeExpression(CascadeExpression node) {
node.target.accept(this);
_nodeList(node.cascadeSections);
}
@override
void visitCatchClause(CatchClause node) {
_token(node.onKeyword);
node.exceptionType?.accept(this);
_token(node.catchKeyword);
_token(node.leftParenthesis);
node.exceptionParameter?.accept(this);
_token(node.comma);
node.stackTraceParameter?.accept(this);
_token(node.rightParenthesis);
node.body.accept(this);
}
@override
void visitClassDeclaration(ClassDeclaration node) {
_compilationUnitMember(node);
_token(node.abstractKeyword);
_token(node.classKeyword);
node.name.accept(this);
node.typeParameters?.accept(this);
node.extendsClause?.accept(this);
node.withClause?.accept(this);
node.implementsClause?.accept(this);
node.nativeClause?.accept(this);
_token(node.leftBracket);
node.members.accept(this);
_token(node.rightBracket);
}
@override
void visitClassTypeAlias(ClassTypeAlias node) {
_compilationUnitMember(node);
_token(node.abstractKeyword);
_token(node.typedefKeyword);
node.name.accept(this);
node.typeParameters?.accept(this);
_token(node.equals);
node.superclass?.accept(this);
node.withClause.accept(this);
node.implementsClause?.accept(this);
_token(node.semicolon);
}
@override
void visitComment(Comment node) {}
@override
void visitCompilationUnit(CompilationUnit node) {
node.scriptTag?.accept(this);
node.directives.accept(this);
node.declarations.accept(this);
_token(node.endToken);
}
@override
void visitConditionalExpression(ConditionalExpression node) {
node.condition.accept(this);
_token(node.question);
node.thenExpression.accept(this);
_token(node.colon);
node.elseExpression.accept(this);
}
@override
void visitConfiguration(Configuration node) {
_token(node.ifKeyword);
_token(node.leftParenthesis);
node.name.accept(this);
_token(node.equalToken);
node.value?.accept(this);
_token(node.rightParenthesis);
node.uri.accept(this);
}
@override
void visitConstructorDeclaration(ConstructorDeclaration node) {
_classMember(node);
_token(node.externalKeyword);
_token(node.constKeyword);
_token(node.factoryKeyword);
node.returnType?.accept(this);
_token(node.period);
node.name?.accept(this);
node.parameters.accept(this);
_token(node.separator);
_nodeList(node.initializers, node.body.beginToken);
node.redirectedConstructor?.accept(this);
node.body.accept(this);
}
@override
void visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
_token(node.thisKeyword);
_token(node.period);
node.fieldName.accept(this);
_token(node.equals);
node.expression.accept(this);
}
@override
void visitConstructorName(ConstructorName node) {
node.type.accept(this);
_token(node.period);
node.name?.accept(this);
}
@override
void visitContinueStatement(ContinueStatement node) {
_token(node.continueKeyword);
node.label?.accept(this);
_token(node.semicolon);
}
@override
void visitDeclaredIdentifier(DeclaredIdentifier node) {
_declaration(node);
_token(node.keyword);
node.type?.accept(this);
node.identifier.accept(this);
}
@override
void visitDefaultFormalParameter(DefaultFormalParameter node) {
node.parameter.accept(this);
_token(node.separator);
node.defaultValue?.accept(this);
}
@override
void visitDoStatement(DoStatement node) {
_token(node.doKeyword);
node.body.accept(this);
_token(node.whileKeyword);
_token(node.leftParenthesis);
node.condition.accept(this);
_token(node.rightParenthesis);
_token(node.semicolon);
}
@override
void visitDottedName(DottedName node) {
_nodeList(node.components, node.endToken.next);
}
@override
void visitDoubleLiteral(DoubleLiteral node) {
_token(node.literal);
}
@override
void visitEmptyFunctionBody(EmptyFunctionBody node) {
_functionBody(node);
_token(node.semicolon);
}
@override
void visitEmptyStatement(EmptyStatement node) {
_token(node.semicolon);
}
@override
void visitEnumConstantDeclaration(EnumConstantDeclaration node) {
_declaration(node);
node.name.accept(this);
}
@override
void visitEnumDeclaration(EnumDeclaration node) {
_compilationUnitMember(node);
_token(node.enumKeyword);
node.name.accept(this);
_token(node.leftBracket);
_nodeList(node.constants, node.rightBracket);
_token(node.rightBracket);
}
@override
void visitExportDirective(ExportDirective node) {
_directive(node);
_token(node.keyword);
node.uri.accept(this);
node.configurations?.accept(this);
_nodeList(node.combinators);
_token(node.semicolon);
}
@override
void visitExpressionFunctionBody(ExpressionFunctionBody node) {
_functionBody(node);
_token(node.functionDefinition);
node.expression.accept(this);
_token(node.semicolon);
}
@override
void visitExpressionStatement(ExpressionStatement node) {
node.expression.accept(this);
_token(node.semicolon);
}
@override
void visitExtendsClause(ExtendsClause node) {
_token(node.extendsKeyword);
node.superclass.accept(this);
}
@override
void visitFieldDeclaration(FieldDeclaration node) {
_classMember(node);
_token(node.staticKeyword);
_token(node.covariantKeyword);
node.fields.accept(this);
_token(node.semicolon);
}
@override
void visitFieldFormalParameter(FieldFormalParameter node) {
_normalFormalParameter(node);
_token(node.keyword);
node.type?.accept(this);
_token(node.thisKeyword);
_token(node.period);
node.identifier.accept(this);
node.typeParameters?.accept(this);
node.parameters?.accept(this);
}
@override
void visitForEachPartsWithDeclaration(ForEachPartsWithDeclaration node) {
node.loopVariable.accept(this);
_token(node.inKeyword);
node.iterable.accept(this);
}
@override
void visitForEachPartsWithIdentifier(ForEachPartsWithIdentifier node) {
node.identifier.accept(this);
_token(node.inKeyword);
node.iterable.accept(this);
}
@override
void visitForElement(ForElement node) {
_token(node.forKeyword);
_token(node.leftParenthesis);
node.forLoopParts.accept(this);
_token(node.rightParenthesis);
node.body.accept(this);
}
@override
void visitFormalParameterList(FormalParameterList node) {
_token(node.leftParenthesis);
var parameters = node.parameters;
for (var i = 0; i < parameters.length; ++i) {
var parameter = parameters[i];
if (node.leftDelimiter?.next == parameter.beginToken) {
_token(node.leftDelimiter);
}
parameter.accept(this);
var itemSeparator = parameter.endToken.next;
if (itemSeparator != node.rightParenthesis) {
_token(itemSeparator);
itemSeparator = itemSeparator.next;
}
if (itemSeparator == node.rightDelimiter) {
_token(node.rightDelimiter);
}
}
_token(node.rightParenthesis);
}
@override
void visitForPartsWithDeclarations(ForPartsWithDeclarations node) {
node.variables.accept(this);
_token(node.leftSeparator);
node.condition?.accept(this);
_token(node.rightSeparator);
_nodeList(node.updaters, node.endToken.next);
}
@override
void visitForPartsWithExpression(ForPartsWithExpression node) {
node.initialization?.accept(this);
_token(node.leftSeparator);
node.condition?.accept(this);
_token(node.rightSeparator);
_nodeList(node.updaters, node.updaters.endToken?.next);
}
@override
void visitForStatement(ForStatement node) {
_token(node.awaitKeyword);
_token(node.forKeyword);
_token(node.leftParenthesis);
node.forLoopParts.accept(this);
_token(node.rightParenthesis);
node.body.accept(this);
}
@override
void visitFunctionDeclaration(FunctionDeclaration node) {
_compilationUnitMember(node);
_token(node.externalKeyword);
node.returnType?.accept(this);
_token(node.propertyKeyword);
node.name.accept(this);
node.functionExpression.accept(this);
}
@override
void visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
node.functionDeclaration.accept(this);
}
@override
void visitFunctionExpression(FunctionExpression node) {
node.typeParameters?.accept(this);
node.parameters?.accept(this);
node.body.accept(this);
}
@override
void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
node.function.accept(this);
node.typeArguments?.accept(this);
node.argumentList.accept(this);
}
@override
void visitFunctionTypeAlias(FunctionTypeAlias node) {
_compilationUnitMember(node);
_token(node.typedefKeyword);
node.returnType?.accept(this);
node.name.accept(this);
node.typeParameters?.accept(this);
node.parameters.accept(this);
_token(node.semicolon);
}
@override
void visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
_normalFormalParameter(node);
node.returnType?.accept(this);
node.identifier.accept(this);
node.typeParameters?.accept(this);
node.parameters.accept(this);
_token(node.question);
}
@override
void visitGenericFunctionType(GenericFunctionType node) {
node.returnType?.accept(this);
_token(node.functionKeyword);
node.typeParameters?.accept(this);
node.parameters.accept(this);
}
@override
void visitGenericTypeAlias(GenericTypeAlias node) {
_compilationUnitMember(node);
_token(node.typedefKeyword);
node.name.accept(this);
node.typeParameters?.accept(this);
_token(node.equals);
node.functionType.accept(this);
_token(node.semicolon);
}
@override
void visitHideCombinator(HideCombinator node) {
_token(node.keyword);
_nodeList(node.hiddenNames, node.endToken.next);
}
@override
void visitIfElement(IfElement node) {
_token(node.ifKeyword);
_token(node.leftParenthesis);
node.condition.accept(this);
_token(node.rightParenthesis);
node.thenElement.accept(this);
_token(node.elseKeyword);
node.elseElement?.accept(this);
}
@override
void visitIfStatement(IfStatement node) {
_token(node.ifKeyword);
_token(node.leftParenthesis);
node.condition.accept(this);
_token(node.rightParenthesis);
node.thenStatement.accept(this);
_token(node.elseKeyword);
node.elseStatement?.accept(this);
}
@override
void visitImplementsClause(ImplementsClause node) {
_token(node.implementsKeyword);
_nodeList(node.interfaces, node.endToken.next);
}
@override
void visitImportDirective(ImportDirective node) {
_directive(node);
_token(node.keyword);
node.uri.accept(this);
node.configurations?.accept(this);
_token(node.deferredKeyword);
_token(node.asKeyword);
node.prefix?.accept(this);
_nodeList(node.combinators);
_token(node.semicolon);
}
@override
void visitIndexExpression(IndexExpression node) {
node.target?.accept(this);
_token(node.period);
_token(node.leftBracket);
node.index.accept(this);
_token(node.rightBracket);
}
@override
void visitInstanceCreationExpression(InstanceCreationExpression node) {
_token(node.keyword);
node.constructorName.accept(this);
node.argumentList.accept(this);
}
@override
void visitIntegerLiteral(IntegerLiteral node) {
_token(node.literal);
}
@override
void visitInterpolationExpression(InterpolationExpression node) {
_token(node.leftBracket);
node.expression.accept(this);
_token(node.rightBracket);
}
@override
void visitInterpolationString(InterpolationString node) {
_token(node.contents);
}
@override
void visitIsExpression(IsExpression node) {
node.expression.accept(this);
_token(node.isOperator);
_token(node.notOperator);
node.type.accept(this);
}
@override
void visitLabel(Label node) {
node.label.accept(this);
_token(node.colon);
}
@override
void visitLabeledStatement(LabeledStatement node) {
_nodeList(node.labels);
node.statement.accept(this);
}
@override
void visitLibraryDirective(LibraryDirective node) {
_directive(node);
_token(node.libraryKeyword);
node.name.accept(this);
_token(node.semicolon);
}
@override
void visitLibraryIdentifier(LibraryIdentifier node) {
_nodeList(node.components, node.endToken.next);
}
@override
void visitListLiteral(ListLiteral node) {
_typedLiteral(node);
_token(node.leftBracket);
_nodeList(node.elements, node.rightBracket);
_token(node.rightBracket);
}
@override
void visitMapLiteralEntry(MapLiteralEntry node) {
node.key.accept(this);
_token(node.separator);
node.value.accept(this);
}
@override
void visitMethodDeclaration(MethodDeclaration node) {
_classMember(node);
_token(node.externalKeyword);
_token(node.modifierKeyword);
node.returnType?.accept(this);
_token(node.propertyKeyword);
_token(node.operatorKeyword);
node.name.accept(this);
node.typeParameters?.accept(this);
node.parameters?.accept(this);
node.body?.accept(this);
}
@override
void visitMethodInvocation(MethodInvocation node) {
node.target?.accept(this);
_token(node.operator);
node.methodName.accept(this);
node.typeArguments?.accept(this);
node.argumentList.accept(this);
}
@override
void visitMixinDeclaration(MixinDeclaration node) {
_compilationUnitMember(node);
_token(node.mixinKeyword);
node.name.accept(this);
node.typeParameters?.accept(this);
node.onClause?.accept(this);
node.implementsClause?.accept(this);
_token(node.leftBracket);
node.members.accept(this);
_token(node.rightBracket);
}
@override
void visitNamedExpression(NamedExpression node) {
node.name.accept(this);
node.expression.accept(this);
}
@override
void visitNativeClause(NativeClause node) {
_token(node.nativeKeyword);
node.name.accept(this);
}
@override
void visitNativeFunctionBody(NativeFunctionBody node) {
_token(node.nativeKeyword);
node.stringLiteral?.accept(this);
_token(node.semicolon);
}
@override
void visitNullLiteral(NullLiteral node) {
_token(node.literal);
}
@override
void visitOnClause(OnClause node) {
_token(node.onKeyword);
_nodeList(node.superclassConstraints, node.endToken.next);
}
@override
void visitParenthesizedExpression(ParenthesizedExpression node) {
_token(node.leftParenthesis);
node.expression.accept(this);
_token(node.rightParenthesis);
}
@override
void visitPartDirective(PartDirective node) {
_directive(node);
_token(node.partKeyword);
node.uri.accept(this);
_token(node.semicolon);
}
@override
void visitPartOfDirective(PartOfDirective node) {
_directive(node);
_token(node.partKeyword);
_token(node.ofKeyword);
node.uri?.accept(this);
node.libraryName?.accept(this);
_token(node.semicolon);
}
@override
void visitPostfixExpression(PostfixExpression node) {
node.operand.accept(this);
_token(node.operator);
}
@override
void visitPrefixedIdentifier(PrefixedIdentifier node) {
node.prefix.accept(this);
_token(node.period);
node.identifier.accept(this);
}
@override
void visitPrefixExpression(PrefixExpression node) {
_token(node.operator);
node.operand.accept(this);
}
@override
void visitPropertyAccess(PropertyAccess node) {
node.target?.accept(this);
_token(node.operator);
node.propertyName.accept(this);
}
@override
void visitRedirectingConstructorInvocation(
RedirectingConstructorInvocation node) {
_token(node.thisKeyword);
_token(node.period);
node.constructorName?.accept(this);
node.argumentList.accept(this);
}
@override
void visitRethrowExpression(RethrowExpression node) {
_token(node.rethrowKeyword);
}
@override
void visitReturnStatement(ReturnStatement node) {
_token(node.returnKeyword);
node.expression?.accept(this);
_token(node.semicolon);
}
@override
void visitScriptTag(ScriptTag node) {
_token(node.scriptTag);
}
@override
void visitSetOrMapLiteral(SetOrMapLiteral node) {
_typedLiteral(node);
_token(node.leftBracket);
_nodeList(node.elements, node.rightBracket);
_token(node.rightBracket);
}
@override
void visitShowCombinator(ShowCombinator node) {
_token(node.keyword);
_nodeList(node.shownNames, node.endToken.next);
}
@override
void visitSimpleFormalParameter(SimpleFormalParameter node) {
_normalFormalParameter(node);
_token(node.keyword);
node.type?.accept(this);
node.identifier?.accept(this);
}
@override
void visitSimpleIdentifier(SimpleIdentifier node) {
_token(node.token);
}
@override
void visitSimpleStringLiteral(SimpleStringLiteral node) {
_token(node.literal);
}
@override
void visitSpreadElement(SpreadElement node) {
_token(node.spreadOperator);
node.expression.accept(this);
}
@override
void visitStringInterpolation(StringInterpolation node) {
_nodeList(node.elements);
}
@override
void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
_token(node.superKeyword);
_token(node.period);
node.constructorName?.accept(this);
node.argumentList.accept(this);
}
@override
void visitSuperExpression(SuperExpression node) {
_token(node.superKeyword);
}
@override
void visitSwitchCase(SwitchCase node) {
_nodeList(node.labels);
_token(node.keyword);
node.expression.accept(this);
_token(node.colon);
_nodeList(node.statements);
}
@override
void visitSwitchDefault(SwitchDefault node) {
_nodeList(node.labels);
_token(node.keyword);
_token(node.colon);
_nodeList(node.statements);
}
@override
void visitSwitchStatement(SwitchStatement node) {
_token(node.switchKeyword);
_token(node.leftParenthesis);
node.expression.accept(this);
_token(node.rightParenthesis);
_token(node.leftBracket);
_nodeList(node.members);
_token(node.rightBracket);
}
@override
void visitSymbolLiteral(SymbolLiteral node) {
_token(node.poundSign);
var components = node.components;
for (var i = 0; i < components.length; ++i) {
var component = components[i];
_token(component);
if (i != components.length - 1) {
_token(component.next);
}
}
}
@override
void visitThisExpression(ThisExpression node) {
_token(node.thisKeyword);
}
@override
void visitThrowExpression(ThrowExpression node) {
_token(node.throwKeyword);
node.expression.accept(this);
}
@override
void visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
_compilationUnitMember(node);
node.variables.accept(this);
_token(node.semicolon);
}
@override
void visitTryStatement(TryStatement node) {
_token(node.tryKeyword);
node.body.accept(this);
_nodeList(node.catchClauses);
_token(node.finallyKeyword);
node.finallyBlock?.accept(this);
}
@override
void visitTypeArgumentList(TypeArgumentList node) {
_token(node.leftBracket);
_nodeList(node.arguments, node.rightBracket);
_token(node.rightBracket);
}
@override
void visitTypeName(TypeName node) {
node.name.accept(this);
node.typeArguments?.accept(this);
}
@override
void visitTypeParameter(TypeParameter node) {
_declaration(node);
node.name?.accept(this);
_token(node.extendsKeyword);
node.bound?.accept(this);
}
@override
void visitTypeParameterList(TypeParameterList node) {
_token(node.leftBracket);
_nodeList(node.typeParameters, node.rightBracket);
_token(node.rightBracket);
}
@override
void visitVariableDeclaration(VariableDeclaration node) {
_annotatedNode(node);
node.name.accept(this);
_token(node.equals);
node.initializer?.accept(this);
}
@override
void visitVariableDeclarationList(VariableDeclarationList node) {
_annotatedNode(node);
_token(node.keyword);
node.type?.accept(this);
_nodeList(node.variables, node.endToken.next);
}
@override
void visitVariableDeclarationStatement(VariableDeclarationStatement node) {
node.variables.accept(this);
_token(node.semicolon);
}
@override
void visitWhileStatement(WhileStatement node) {
_token(node.whileKeyword);
_token(node.leftParenthesis);
node.condition.accept(this);
_token(node.rightParenthesis);
node.body.accept(this);
}
@override
void visitWithClause(WithClause node) {
_token(node.withKeyword);
_nodeList(node.mixinTypes, node.endToken.next);
}
@override
void visitYieldStatement(YieldStatement node) {
_token(node.yieldKeyword);
_token(node.star);
node.expression.accept(this);
_token(node.semicolon);
}
void _annotatedNode(AnnotatedNode node) {
node.documentationComment?.accept(this);
_nodeList(node.metadata);
}
void _classMember(ClassMember node) {
_declaration(node);
}
void _compilationUnitMember(CompilationUnitMember node) {
_declaration(node);
}
void _declaration(Declaration node) {
_annotatedNode(node);
}
void _directive(Directive node) {
_annotatedNode(node);
}
void _functionBody(FunctionBody node) {
_token(node.keyword);
_token(node.star);
}
/// Print nodes from the [nodeList].
///
/// If the [endToken] is not `null`, print one token after every node,
/// unless it is the [endToken].
void _nodeList(List<AstNode> nodeList, [Token endToken]) {
var length = nodeList.length;
for (var i = 0; i < length; ++i) {
var node = nodeList[i];
node.accept(this);
if (endToken != null && node.endToken.next != endToken) {
_token(node.endToken.next);
}
}
}
void _normalFormalParameter(NormalFormalParameter node) {
node.documentationComment?.accept(this);
_nodeList(node.metadata);
_token(node.covariantKeyword);
}
void _token(Token token) {
if (token == null) return;
if (_last != null) {
if (_last.next != token) {
throw StateError(
'|$_last| must be followed by |${_last.next}|, got |$token|',
);
}
}
// Print preceding comments as a separate sequence of tokens.
if (token.precedingComments != null) {
var lastToken = _last;
_last = null;
for (var c = token.precedingComments; c != null; c = c.next) {
_token(c);
}
_last = lastToken;
}
for (var offset = _lastEnd; offset < token.offset; offset++) {
var offsetLocation = _lineInfo.getLocation(offset + 1);
var offsetLine = offsetLocation.lineNumber - 1;
if (offsetLine == _lastEndLine) {
_buffer.write(' ');
} else {
_buffer.write('\n');
_lastEndLine++;
}
}
_buffer.write(token.lexeme);
_last = token;
_lastEnd = token.end;
var endLocation = _lineInfo.getLocation(token.end);
_lastEndLine = endLocation.lineNumber - 1;
}
void _tokenIfNot(Token maybe, Token ifNot) {
if (maybe == null) return;
if (maybe == ifNot) return;
_token(maybe);
}
_typedLiteral(TypedLiteral node) {
_token(node.constKeyword);
node.typeArguments?.accept(this);
}
}