| Index: observatory_pub_packages/analyzer/src/generated/parser.dart
|
| ===================================================================
|
| --- observatory_pub_packages/analyzer/src/generated/parser.dart (revision 0)
|
| +++ observatory_pub_packages/analyzer/src/generated/parser.dart (working copy)
|
| @@ -0,0 +1,9483 @@
|
| +// Copyright (c) 2014, 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.
|
| +
|
| +// This code was auto-generated, is not intended to be edited, and is subject to
|
| +// significant change. Please see the README file for more information.
|
| +
|
| +library engine.parser;
|
| +
|
| +import 'dart:collection';
|
| +import 'java_core.dart';
|
| +import 'java_engine.dart';
|
| +import 'instrumentation.dart';
|
| +import 'error.dart';
|
| +import 'source.dart';
|
| +import 'scanner.dart';
|
| +import 'ast.dart';
|
| +import 'utilities_dart.dart';
|
| +import 'engine.dart' show AnalysisEngine, AnalysisOptionsImpl;
|
| +import 'utilities_collection.dart' show TokenMap;
|
| +
|
| +/**
|
| + * Instances of the class `CommentAndMetadata` implement a simple data-holder for a method
|
| + * that needs to return multiple values.
|
| + */
|
| +class CommentAndMetadata {
|
| + /**
|
| + * The documentation comment that was parsed, or `null` if none was given.
|
| + */
|
| + final Comment comment;
|
| +
|
| + /**
|
| + * The metadata that was parsed.
|
| + */
|
| + final List<Annotation> metadata;
|
| +
|
| + /**
|
| + * Initialize a newly created holder with the given data.
|
| + *
|
| + * @param comment the documentation comment that was parsed
|
| + * @param metadata the metadata that was parsed
|
| + */
|
| + CommentAndMetadata(this.comment, this.metadata);
|
| +}
|
| +
|
| +/**
|
| + * Instances of the class `FinalConstVarOrType` implement a simple data-holder for a method
|
| + * that needs to return multiple values.
|
| + */
|
| +class FinalConstVarOrType {
|
| + /**
|
| + * The 'final', 'const' or 'var' keyword, or `null` if none was given.
|
| + */
|
| + final Token keyword;
|
| +
|
| + /**
|
| + * The type, of `null` if no type was specified.
|
| + */
|
| + final TypeName type;
|
| +
|
| + /**
|
| + * Initialize a newly created holder with the given data.
|
| + *
|
| + * @param keyword the 'final', 'const' or 'var' keyword
|
| + * @param type the type
|
| + */
|
| + FinalConstVarOrType(this.keyword, this.type);
|
| +}
|
| +
|
| +/**
|
| + * Instances of the class `IncrementalParseDispatcher` implement a dispatcher that will invoke
|
| + * the right parse method when re-parsing a specified child of the visited node. All of the methods
|
| + * in this class assume that the parser is positioned to parse the replacement for the node. All of
|
| + * the methods will throw an [IncrementalParseException] if the node could not be parsed for
|
| + * some reason.
|
| + */
|
| +class IncrementalParseDispatcher implements AstVisitor<AstNode> {
|
| + /**
|
| + * The parser used to parse the replacement for the node.
|
| + */
|
| + final Parser _parser;
|
| +
|
| + /**
|
| + * The node that is to be replaced.
|
| + */
|
| + final AstNode _oldNode;
|
| +
|
| + /**
|
| + * Initialize a newly created dispatcher to parse a single node that will replace the given node.
|
| + *
|
| + * @param parser the parser used to parse the replacement for the node
|
| + * @param oldNode the node that is to be replaced
|
| + */
|
| + IncrementalParseDispatcher(this._parser, this._oldNode);
|
| +
|
| + @override
|
| + AstNode visitAdjacentStrings(AdjacentStrings node) {
|
| + if (node.strings.contains(_oldNode)) {
|
| + return _parser.parseStringLiteral();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitAnnotation(Annotation node) {
|
| + if (identical(_oldNode, node.name)) {
|
| + throw new InsufficientContextException();
|
| + } else if (identical(_oldNode, node.constructorName)) {
|
| + throw new InsufficientContextException();
|
| + } else if (identical(_oldNode, node.arguments)) {
|
| + return _parser.parseArgumentList();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitArgumentList(ArgumentList node) {
|
| + if (node.arguments.contains(_oldNode)) {
|
| + return _parser.parseArgument();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitAsExpression(AsExpression node) {
|
| + if (identical(_oldNode, node.expression)) {
|
| + return _parser.parseBitwiseOrExpression();
|
| + } else if (identical(_oldNode, node.type)) {
|
| + return _parser.parseTypeName();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitAssertStatement(AssertStatement node) {
|
| + if (identical(_oldNode, node.condition)) {
|
| + return _parser.parseExpression2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitAssignmentExpression(AssignmentExpression node) {
|
| + if (identical(_oldNode, node.leftHandSide)) {
|
| + // TODO(brianwilkerson) If the assignment is part of a cascade section, then we don't have a
|
| + // single parse method that will work. Otherwise, we can parse a conditional expression, but
|
| + // need to ensure that the resulting expression is assignable.
|
| + // return parser.parseConditionalExpression();
|
| + throw new InsufficientContextException();
|
| + } else if (identical(_oldNode, node.rightHandSide)) {
|
| + if (_isCascadeAllowedInAssignment(node)) {
|
| + return _parser.parseExpression2();
|
| + }
|
| + return _parser.parseExpressionWithoutCascade();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitAwaitExpression(AwaitExpression node) {
|
| + if (identical(_oldNode, node.expression)) {
|
| + // TODO(brianwilkerson) Depending on precedence, this might not be sufficient.
|
| + return _parser.parseExpression2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitBinaryExpression(BinaryExpression node) {
|
| + if (identical(_oldNode, node.leftOperand)) {
|
| + throw new InsufficientContextException();
|
| + } else if (identical(_oldNode, node.rightOperand)) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitBlock(Block node) {
|
| + if (node.statements.contains(_oldNode)) {
|
| + return _parser.parseStatement2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitBlockFunctionBody(BlockFunctionBody node) {
|
| + if (identical(_oldNode, node.block)) {
|
| + return _parser.parseBlock();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitBooleanLiteral(BooleanLiteral node) => _notAChild(node);
|
| +
|
| + @override
|
| + AstNode visitBreakStatement(BreakStatement node) {
|
| + if (identical(_oldNode, node.label)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitCascadeExpression(CascadeExpression node) {
|
| + if (identical(_oldNode, node.target)) {
|
| + return _parser.parseConditionalExpression();
|
| + } else if (node.cascadeSections.contains(_oldNode)) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitCatchClause(CatchClause node) {
|
| + if (identical(_oldNode, node.exceptionType)) {
|
| + return _parser.parseTypeName();
|
| + } else if (identical(_oldNode, node.exceptionParameter)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + } else if (identical(_oldNode, node.stackTraceParameter)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + } else if (identical(_oldNode, node.body)) {
|
| + return _parser.parseBlock();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitClassDeclaration(ClassDeclaration node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (identical(_oldNode, node.name)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + } else if (identical(_oldNode, node.typeParameters)) {
|
| + return _parser.parseTypeParameterList();
|
| + } else if (identical(_oldNode, node.extendsClause)) {
|
| + return _parser.parseExtendsClause();
|
| + } else if (identical(_oldNode, node.withClause)) {
|
| + return _parser.parseWithClause();
|
| + } else if (identical(_oldNode, node.implementsClause)) {
|
| + return _parser.parseImplementsClause();
|
| + } else if (node.members.contains(_oldNode)) {
|
| + ClassMember member = _parser.parseClassMember(node.name.name);
|
| + if (member == null) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return member;
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitClassTypeAlias(ClassTypeAlias node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (identical(_oldNode, node.name)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + } else if (identical(_oldNode, node.typeParameters)) {
|
| + return _parser.parseTypeParameterList();
|
| + } else if (identical(_oldNode, node.superclass)) {
|
| + return _parser.parseTypeName();
|
| + } else if (identical(_oldNode, node.withClause)) {
|
| + return _parser.parseWithClause();
|
| + } else if (identical(_oldNode, node.implementsClause)) {
|
| + return _parser.parseImplementsClause();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitComment(Comment node) {
|
| + throw new InsufficientContextException();
|
| + }
|
| +
|
| + @override
|
| + AstNode visitCommentReference(CommentReference node) {
|
| + if (identical(_oldNode, node.identifier)) {
|
| + return _parser.parsePrefixedIdentifier();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitCompilationUnit(CompilationUnit node) {
|
| + throw new InsufficientContextException();
|
| + }
|
| +
|
| + @override
|
| + AstNode visitConditionalExpression(ConditionalExpression node) {
|
| + if (identical(_oldNode, node.condition)) {
|
| + return _parser.parseLogicalOrExpression();
|
| + } else if (identical(_oldNode, node.thenExpression)) {
|
| + return _parser.parseExpressionWithoutCascade();
|
| + } else if (identical(_oldNode, node.elseExpression)) {
|
| + return _parser.parseExpressionWithoutCascade();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitConstructorDeclaration(ConstructorDeclaration node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (identical(_oldNode, node.returnType)) {
|
| + throw new InsufficientContextException();
|
| + } else if (identical(_oldNode, node.name)) {
|
| + throw new InsufficientContextException();
|
| + } else if (identical(_oldNode, node.parameters)) {
|
| + return _parser.parseFormalParameterList();
|
| + } else if (identical(_oldNode, node.redirectedConstructor)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.initializers.contains(_oldNode)) {
|
| + throw new InsufficientContextException();
|
| + } else if (identical(_oldNode, node.body)) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
|
| + if (identical(_oldNode, node.fieldName)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + } else if (identical(_oldNode, node.expression)) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitConstructorName(ConstructorName node) {
|
| + if (identical(_oldNode, node.type)) {
|
| + return _parser.parseTypeName();
|
| + } else if (identical(_oldNode, node.name)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitContinueStatement(ContinueStatement node) {
|
| + if (identical(_oldNode, node.label)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitDeclaredIdentifier(DeclaredIdentifier node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (identical(_oldNode, node.type)) {
|
| + throw new InsufficientContextException();
|
| + } else if (identical(_oldNode, node.identifier)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitDefaultFormalParameter(DefaultFormalParameter node) {
|
| + if (identical(_oldNode, node.parameter)) {
|
| + return _parser.parseNormalFormalParameter();
|
| + } else if (identical(_oldNode, node.defaultValue)) {
|
| + return _parser.parseExpression2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitDoStatement(DoStatement node) {
|
| + if (identical(_oldNode, node.body)) {
|
| + return _parser.parseStatement2();
|
| + } else if (identical(_oldNode, node.condition)) {
|
| + return _parser.parseExpression2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitDoubleLiteral(DoubleLiteral node) => _notAChild(node);
|
| +
|
| + @override
|
| + AstNode visitEmptyFunctionBody(EmptyFunctionBody node) => _notAChild(node);
|
| +
|
| + @override
|
| + AstNode visitEmptyStatement(EmptyStatement node) => _notAChild(node);
|
| +
|
| + @override
|
| + AstNode visitEnumConstantDeclaration(EnumConstantDeclaration node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (identical(_oldNode, node.name)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitEnumDeclaration(EnumDeclaration node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (identical(_oldNode, node.name)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + } else if (node.constants.contains(_oldNode)) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitExportDirective(ExportDirective node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (identical(_oldNode, node.uri)) {
|
| + return _parser.parseStringLiteral();
|
| + } else if (node.combinators.contains(_oldNode)) {
|
| + throw new IncrementalParseException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitExpressionFunctionBody(ExpressionFunctionBody node) {
|
| + if (identical(_oldNode, node.expression)) {
|
| + return _parser.parseExpression2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitExpressionStatement(ExpressionStatement node) {
|
| + if (identical(_oldNode, node.expression)) {
|
| + return _parser.parseExpression2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitExtendsClause(ExtendsClause node) {
|
| + if (identical(_oldNode, node.superclass)) {
|
| + return _parser.parseTypeName();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitFieldDeclaration(FieldDeclaration node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (identical(_oldNode, node.fields)) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitFieldFormalParameter(FieldFormalParameter node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (identical(_oldNode, node.type)) {
|
| + return _parser.parseTypeName();
|
| + } else if (identical(_oldNode, node.identifier)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + } else if (identical(_oldNode, node.parameters)) {
|
| + return _parser.parseFormalParameterList();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitForEachStatement(ForEachStatement node) {
|
| + if (identical(_oldNode, node.loopVariable)) {
|
| + throw new InsufficientContextException();
|
| + } else if (identical(_oldNode, node.identifier)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + } else if (identical(_oldNode, node.body)) {
|
| + return _parser.parseStatement2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitFormalParameterList(FormalParameterList node) {
|
| + // We don't know which kind of parameter to parse.
|
| + throw new InsufficientContextException();
|
| + }
|
| +
|
| + @override
|
| + AstNode visitForStatement(ForStatement node) {
|
| + if (identical(_oldNode, node.variables)) {
|
| + throw new InsufficientContextException();
|
| + } else if (identical(_oldNode, node.initialization)) {
|
| + throw new InsufficientContextException();
|
| + } else if (identical(_oldNode, node.condition)) {
|
| + return _parser.parseExpression2();
|
| + } else if (node.updaters.contains(_oldNode)) {
|
| + return _parser.parseExpression2();
|
| + } else if (identical(_oldNode, node.body)) {
|
| + return _parser.parseStatement2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitFunctionDeclaration(FunctionDeclaration node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (identical(_oldNode, node.returnType)) {
|
| + return _parser.parseReturnType();
|
| + } else if (identical(_oldNode, node.name)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + } else if (identical(_oldNode, node.functionExpression)) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
|
| + if (identical(_oldNode, node.functionDeclaration)) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitFunctionExpression(FunctionExpression node) {
|
| + if (identical(_oldNode, node.parameters)) {
|
| + return _parser.parseFormalParameterList();
|
| + } else if (identical(_oldNode, node.body)) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
|
| + if (identical(_oldNode, node.function)) {
|
| + throw new InsufficientContextException();
|
| + } else if (identical(_oldNode, node.argumentList)) {
|
| + return _parser.parseArgumentList();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitFunctionTypeAlias(FunctionTypeAlias node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (identical(_oldNode, node.returnType)) {
|
| + return _parser.parseReturnType();
|
| + } else if (identical(_oldNode, node.name)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + } else if (identical(_oldNode, node.typeParameters)) {
|
| + return _parser.parseTypeParameterList();
|
| + } else if (identical(_oldNode, node.parameters)) {
|
| + return _parser.parseFormalParameterList();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (identical(_oldNode, node.returnType)) {
|
| + return _parser.parseReturnType();
|
| + } else if (identical(_oldNode, node.identifier)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + } else if (identical(_oldNode, node.parameters)) {
|
| + return _parser.parseFormalParameterList();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitHideCombinator(HideCombinator node) {
|
| + if (node.hiddenNames.contains(_oldNode)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitIfStatement(IfStatement node) {
|
| + if (identical(_oldNode, node.condition)) {
|
| + return _parser.parseExpression2();
|
| + } else if (identical(_oldNode, node.thenStatement)) {
|
| + return _parser.parseStatement2();
|
| + } else if (identical(_oldNode, node.elseStatement)) {
|
| + return _parser.parseStatement2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitImplementsClause(ImplementsClause node) {
|
| + if (node.interfaces.contains(node)) {
|
| + return _parser.parseTypeName();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitImportDirective(ImportDirective node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (identical(_oldNode, node.uri)) {
|
| + return _parser.parseStringLiteral();
|
| + } else if (identical(_oldNode, node.prefix)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + } else if (node.combinators.contains(_oldNode)) {
|
| + throw new IncrementalParseException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitIndexExpression(IndexExpression node) {
|
| + if (identical(_oldNode, node.target)) {
|
| + throw new InsufficientContextException();
|
| + } else if (identical(_oldNode, node.index)) {
|
| + return _parser.parseExpression2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitInstanceCreationExpression(InstanceCreationExpression node) {
|
| + if (identical(_oldNode, node.constructorName)) {
|
| + return _parser.parseConstructorName();
|
| + } else if (identical(_oldNode, node.argumentList)) {
|
| + return _parser.parseArgumentList();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitIntegerLiteral(IntegerLiteral node) => _notAChild(node);
|
| +
|
| + @override
|
| + AstNode visitInterpolationExpression(InterpolationExpression node) {
|
| + if (identical(_oldNode, node.expression)) {
|
| + if (node.leftBracket == null) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _parser.parseExpression2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitInterpolationString(InterpolationString node) {
|
| + throw new InsufficientContextException();
|
| + }
|
| +
|
| + @override
|
| + AstNode visitIsExpression(IsExpression node) {
|
| + if (identical(_oldNode, node.expression)) {
|
| + return _parser.parseBitwiseOrExpression();
|
| + } else if (identical(_oldNode, node.type)) {
|
| + return _parser.parseTypeName();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitLabel(Label node) {
|
| + if (identical(_oldNode, node.label)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitLabeledStatement(LabeledStatement node) {
|
| + if (node.labels.contains(_oldNode)) {
|
| + return _parser.parseLabel();
|
| + } else if (identical(_oldNode, node.statement)) {
|
| + return _parser.parseStatement2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitLibraryDirective(LibraryDirective node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (identical(_oldNode, node.name)) {
|
| + return _parser.parseLibraryIdentifier();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitLibraryIdentifier(LibraryIdentifier node) {
|
| + if (node.components.contains(_oldNode)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitListLiteral(ListLiteral node) {
|
| + if (identical(_oldNode, node.typeArguments)) {
|
| + return _parser.parseTypeArgumentList();
|
| + } else if (node.elements.contains(_oldNode)) {
|
| + return _parser.parseExpression2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitMapLiteral(MapLiteral node) {
|
| + if (identical(_oldNode, node.typeArguments)) {
|
| + return _parser.parseTypeArgumentList();
|
| + } else if (node.entries.contains(_oldNode)) {
|
| + return _parser.parseMapLiteralEntry();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitMapLiteralEntry(MapLiteralEntry node) {
|
| + if (identical(_oldNode, node.key)) {
|
| + return _parser.parseExpression2();
|
| + } else if (identical(_oldNode, node.value)) {
|
| + return _parser.parseExpression2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitMethodDeclaration(MethodDeclaration node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (identical(_oldNode, node.returnType)) {
|
| + throw new InsufficientContextException();
|
| + } else if (identical(_oldNode, node.name)) {
|
| + if (node.operatorKeyword != null) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _parser.parseSimpleIdentifier();
|
| + } else if (identical(_oldNode, node.body)) {
|
| + //return parser.parseFunctionBody();
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitMethodInvocation(MethodInvocation node) {
|
| + if (identical(_oldNode, node.target)) {
|
| + throw new IncrementalParseException();
|
| + } else if (identical(_oldNode, node.methodName)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + } else if (identical(_oldNode, node.argumentList)) {
|
| + return _parser.parseArgumentList();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitNamedExpression(NamedExpression node) {
|
| + if (identical(_oldNode, node.name)) {
|
| + return _parser.parseLabel();
|
| + } else if (identical(_oldNode, node.expression)) {
|
| + return _parser.parseExpression2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitNativeClause(NativeClause node) {
|
| + if (identical(_oldNode, node.name)) {
|
| + return _parser.parseStringLiteral();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitNativeFunctionBody(NativeFunctionBody node) {
|
| + if (identical(_oldNode, node.stringLiteral)) {
|
| + return _parser.parseStringLiteral();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitNullLiteral(NullLiteral node) => _notAChild(node);
|
| +
|
| + @override
|
| + AstNode visitParenthesizedExpression(ParenthesizedExpression node) {
|
| + if (identical(_oldNode, node.expression)) {
|
| + return _parser.parseExpression2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitPartDirective(PartDirective node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (identical(_oldNode, node.uri)) {
|
| + return _parser.parseStringLiteral();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitPartOfDirective(PartOfDirective node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (identical(_oldNode, node.libraryName)) {
|
| + return _parser.parseLibraryIdentifier();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitPostfixExpression(PostfixExpression node) {
|
| + if (identical(_oldNode, node.operand)) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitPrefixedIdentifier(PrefixedIdentifier node) {
|
| + if (identical(_oldNode, node.prefix)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + } else if (identical(_oldNode, node.identifier)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitPrefixExpression(PrefixExpression node) {
|
| + if (identical(_oldNode, node.operand)) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitPropertyAccess(PropertyAccess node) {
|
| + if (identical(_oldNode, node.target)) {
|
| + throw new InsufficientContextException();
|
| + } else if (identical(_oldNode, node.propertyName)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitRedirectingConstructorInvocation(RedirectingConstructorInvocation node) {
|
| + if (identical(_oldNode, node.constructorName)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + } else if (identical(_oldNode, node.argumentList)) {
|
| + return _parser.parseArgumentList();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitRethrowExpression(RethrowExpression node) => _notAChild(node);
|
| +
|
| + @override
|
| + AstNode visitReturnStatement(ReturnStatement node) {
|
| + if (identical(_oldNode, node.expression)) {
|
| + return _parser.parseExpression2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitScriptTag(ScriptTag node) => _notAChild(node);
|
| +
|
| + @override
|
| + AstNode visitShowCombinator(ShowCombinator node) {
|
| + if (node.shownNames.contains(_oldNode)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitSimpleFormalParameter(SimpleFormalParameter node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (identical(_oldNode, node.type)) {
|
| + throw new InsufficientContextException();
|
| + } else if (identical(_oldNode, node.identifier)) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitSimpleIdentifier(SimpleIdentifier node) => _notAChild(node);
|
| +
|
| + @override
|
| + AstNode visitSimpleStringLiteral(SimpleStringLiteral node) => _notAChild(node);
|
| +
|
| + @override
|
| + AstNode visitStringInterpolation(StringInterpolation node) {
|
| + if (node.elements.contains(_oldNode)) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitSuperConstructorInvocation(SuperConstructorInvocation node) {
|
| + if (identical(_oldNode, node.constructorName)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + } else if (identical(_oldNode, node.argumentList)) {
|
| + return _parser.parseArgumentList();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitSuperExpression(SuperExpression node) => _notAChild(node);
|
| +
|
| + @override
|
| + AstNode visitSwitchCase(SwitchCase node) {
|
| + if (node.labels.contains(_oldNode)) {
|
| + return _parser.parseLabel();
|
| + } else if (identical(_oldNode, node.expression)) {
|
| + return _parser.parseExpression2();
|
| + } else if (node.statements.contains(_oldNode)) {
|
| + return _parser.parseStatement2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitSwitchDefault(SwitchDefault node) {
|
| + if (node.labels.contains(_oldNode)) {
|
| + return _parser.parseLabel();
|
| + } else if (node.statements.contains(_oldNode)) {
|
| + return _parser.parseStatement2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitSwitchStatement(SwitchStatement node) {
|
| + if (identical(_oldNode, node.expression)) {
|
| + return _parser.parseExpression2();
|
| + } else if (node.members.contains(_oldNode)) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitSymbolLiteral(SymbolLiteral node) => _notAChild(node);
|
| +
|
| + @override
|
| + AstNode visitThisExpression(ThisExpression node) => _notAChild(node);
|
| +
|
| + @override
|
| + AstNode visitThrowExpression(ThrowExpression node) {
|
| + if (identical(_oldNode, node.expression)) {
|
| + if (_isCascadeAllowedInThrow(node)) {
|
| + return _parser.parseExpression2();
|
| + }
|
| + return _parser.parseExpressionWithoutCascade();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (identical(_oldNode, node.variables)) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitTryStatement(TryStatement node) {
|
| + if (identical(_oldNode, node.body)) {
|
| + return _parser.parseBlock();
|
| + } else if (node.catchClauses.contains(_oldNode)) {
|
| + throw new InsufficientContextException();
|
| + } else if (identical(_oldNode, node.finallyBlock)) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitTypeArgumentList(TypeArgumentList node) {
|
| + if (node.arguments.contains(_oldNode)) {
|
| + return _parser.parseTypeName();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitTypeName(TypeName node) {
|
| + if (identical(_oldNode, node.name)) {
|
| + return _parser.parsePrefixedIdentifier();
|
| + } else if (identical(_oldNode, node.typeArguments)) {
|
| + return _parser.parseTypeArgumentList();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitTypeParameter(TypeParameter node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (identical(_oldNode, node.name)) {
|
| + return _parser.parseSimpleIdentifier();
|
| + } else if (identical(_oldNode, node.bound)) {
|
| + return _parser.parseTypeName();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitTypeParameterList(TypeParameterList node) {
|
| + if (node.typeParameters.contains(node)) {
|
| + return _parser.parseTypeParameter();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitVariableDeclaration(VariableDeclaration node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (identical(_oldNode, node.name)) {
|
| + throw new InsufficientContextException();
|
| + } else if (identical(_oldNode, node.initializer)) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitVariableDeclarationList(VariableDeclarationList node) {
|
| + if (identical(_oldNode, node.documentationComment)) {
|
| + throw new InsufficientContextException();
|
| + } else if (node.metadata.contains(_oldNode)) {
|
| + return _parser.parseAnnotation();
|
| + } else if (node.variables.contains(_oldNode)) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitVariableDeclarationStatement(VariableDeclarationStatement node) {
|
| + if (identical(_oldNode, node.variables)) {
|
| + throw new InsufficientContextException();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitWhileStatement(WhileStatement node) {
|
| + if (identical(_oldNode, node.condition)) {
|
| + return _parser.parseExpression2();
|
| + } else if (identical(_oldNode, node.body)) {
|
| + return _parser.parseStatement2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitWithClause(WithClause node) {
|
| + if (node.mixinTypes.contains(node)) {
|
| + return _parser.parseTypeName();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + @override
|
| + AstNode visitYieldStatement(YieldStatement node) {
|
| + if (identical(_oldNode, node.expression)) {
|
| + return _parser.parseExpression2();
|
| + }
|
| + return _notAChild(node);
|
| + }
|
| +
|
| + /**
|
| + * Return `true` if the given assignment expression can have a cascade expression on the
|
| + * right-hand side.
|
| + *
|
| + * @param node the assignment expression being tested
|
| + * @return `true` if the right-hand side can be a cascade expression
|
| + */
|
| + bool _isCascadeAllowedInAssignment(AssignmentExpression node) {
|
| + // TODO(brianwilkerson) Implement this method.
|
| + throw new InsufficientContextException();
|
| + }
|
| +
|
| + /**
|
| + * Return `true` if the given throw expression can have a cascade expression.
|
| + *
|
| + * @param node the throw expression being tested
|
| + * @return `true` if the expression can be a cascade expression
|
| + */
|
| + bool _isCascadeAllowedInThrow(ThrowExpression node) {
|
| + // TODO(brianwilkerson) Implement this method.
|
| + throw new InsufficientContextException();
|
| + }
|
| +
|
| + /**
|
| + * Throw an exception indicating that the visited node was not the parent of the node to be
|
| + * replaced.
|
| + *
|
| + * @param visitedNode the visited node that should have been the parent of the node to be replaced
|
| + */
|
| + AstNode _notAChild(AstNode visitedNode) {
|
| + throw new IncrementalParseException.con1("Internal error: the visited node (a ${visitedNode.runtimeType.toString()}) was not the parent of the node to be replaced (a ${_oldNode.runtimeType.toString()})");
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Instances of the class `IncrementalParseException` represent an exception that occurred
|
| + * while attempting to parse a replacement for a specified node in an existing AST structure.
|
| + */
|
| +class IncrementalParseException extends RuntimeException {
|
| + /**
|
| + * Initialize a newly created exception to have no message and to be its own cause.
|
| + */
|
| + IncrementalParseException() : super();
|
| +
|
| + /**
|
| + * Initialize a newly created exception to have the given message and to be its own cause.
|
| + *
|
| + * @param message the message describing the reason for the exception
|
| + */
|
| + IncrementalParseException.con1(String message) : super(message: message);
|
| +
|
| + /**
|
| + * Initialize a newly created exception to have no message and to have the given cause.
|
| + *
|
| + * @param cause the exception that caused this exception
|
| + */
|
| + IncrementalParseException.con2(Exception cause) : super(cause: cause);
|
| +}
|
| +
|
| +/**
|
| + * Instances of the class `IncrementalParser` re-parse a single AST structure within a larger
|
| + * AST structure.
|
| + */
|
| +class IncrementalParser {
|
| + /**
|
| + * The source being parsed.
|
| + */
|
| + final Source _source;
|
| +
|
| + /**
|
| + * A map from old tokens to new tokens used during the cloning process.
|
| + */
|
| + final TokenMap _tokenMap;
|
| +
|
| + /**
|
| + * The error listener that will be informed of any errors that are found during the parse.
|
| + */
|
| + final AnalysisErrorListener _errorListener;
|
| +
|
| + /**
|
| + * The node in the AST structure that contains the revised content.
|
| + */
|
| + AstNode _updatedNode;
|
| +
|
| + /**
|
| + * Initialize a newly created incremental parser to parse a portion of the content of the given
|
| + * source.
|
| + *
|
| + * @param source the source being parsed
|
| + * @param tokenMap a map from old tokens to new tokens used during the cloning process
|
| + * @param errorListener the error listener that will be informed of any errors that are found
|
| + * during the parse
|
| + */
|
| + IncrementalParser(this._source, this._tokenMap, this._errorListener);
|
| +
|
| + /**
|
| + * Return the node in the AST structure that contains the revised content.
|
| + *
|
| + * @return the updated node
|
| + */
|
| + AstNode get updatedNode => _updatedNode;
|
| +
|
| + /**
|
| + * Given a range of tokens that were re-scanned, re-parse the minimum number of tokens to produce
|
| + * a consistent AST structure. The range is represented by the first and last tokens in the range.
|
| + * The tokens are assumed to be contained in the same token stream.
|
| + *
|
| + * @param leftToken the token in the new token stream immediately to the left of the range of
|
| + * tokens that were inserted
|
| + * @param rightToken the token in the new token stream immediately to the right of the range of
|
| + * tokens that were inserted
|
| + * @param originalStart the offset in the original source of the first character that was modified
|
| + * @param originalEnd the offset in the original source of the last character that was modified
|
| + */
|
| + AstNode reparse(AstNode originalStructure, Token leftToken, Token rightToken, int originalStart, int originalEnd) {
|
| + AstNode oldNode = null;
|
| + AstNode newNode = null;
|
| + //
|
| + // Find the first token that needs to be re-parsed.
|
| + //
|
| + Token firstToken = leftToken.next;
|
| + if (identical(firstToken, rightToken)) {
|
| + // If there are no new tokens, then we need to include at least one copied node in the range.
|
| + firstToken = leftToken;
|
| + }
|
| + //
|
| + // Find the smallest AST node that encompasses the range of re-scanned tokens.
|
| + //
|
| + if (originalEnd < originalStart) {
|
| + oldNode = new NodeLocator.con1(originalStart).searchWithin(originalStructure);
|
| + } else {
|
| + oldNode = new NodeLocator.con2(originalStart, originalEnd).searchWithin(originalStructure);
|
| + }
|
| + //
|
| + // Find the token at which parsing is to begin.
|
| + //
|
| + int originalOffset = oldNode.offset;
|
| + Token parseToken = _findTokenAt(firstToken, originalOffset);
|
| + if (parseToken == null) {
|
| + return null;
|
| + }
|
| + //
|
| + // Parse the appropriate AST structure starting at the appropriate place.
|
| + //
|
| + Parser parser = new Parser(_source, _errorListener);
|
| + parser.currentToken = parseToken;
|
| + while (newNode == null) {
|
| + AstNode parent = oldNode.parent;
|
| + if (parent == null) {
|
| + parseToken = _findFirstToken(parseToken);
|
| + parser.currentToken = parseToken;
|
| + return parser.parseCompilationUnit2();
|
| + }
|
| + bool advanceToParent = false;
|
| + try {
|
| + IncrementalParseDispatcher dispatcher = new IncrementalParseDispatcher(parser, oldNode);
|
| + newNode = parent.accept(dispatcher);
|
| + //
|
| + // Validate that the new node can replace the old node.
|
| + //
|
| + Token mappedToken = _tokenMap.get(oldNode.endToken.next);
|
| + if (mappedToken == null || mappedToken.offset != newNode.endToken.next.offset || newNode.offset != oldNode.offset) {
|
| + advanceToParent = true;
|
| + }
|
| + } on InsufficientContextException catch (exception) {
|
| + advanceToParent = true;
|
| + } catch (exception) {
|
| + return null;
|
| + }
|
| + if (advanceToParent) {
|
| + newNode = null;
|
| + oldNode = parent;
|
| + originalOffset = oldNode.offset;
|
| + parseToken = _findTokenAt(parseToken, originalOffset);
|
| + parser.currentToken = parseToken;
|
| + }
|
| + }
|
| + _updatedNode = newNode;
|
| + //
|
| + // Replace the old node with the new node in a copy of the original AST structure.
|
| + //
|
| + if (identical(oldNode, originalStructure)) {
|
| + // We ended up re-parsing the whole structure, so there's no need for a copy.
|
| + ResolutionCopier.copyResolutionData(oldNode, newNode);
|
| + return newNode;
|
| + }
|
| + ResolutionCopier.copyResolutionData(oldNode, newNode);
|
| + IncrementalAstCloner cloner = new IncrementalAstCloner(oldNode, newNode, _tokenMap);
|
| + return originalStructure.accept(cloner) as AstNode;
|
| + }
|
| +
|
| + /**
|
| + * Return the first (non-EOF) token in the token stream containing the given token.
|
| + *
|
| + * @param firstToken the token from which the search is to begin
|
| + * @return the first token in the token stream containing the given token
|
| + */
|
| + Token _findFirstToken(Token firstToken) {
|
| + while (firstToken.type != TokenType.EOF) {
|
| + firstToken = firstToken.previous;
|
| + }
|
| + return firstToken.next;
|
| + }
|
| +
|
| + /**
|
| + * Find the token at or before the given token with the given offset, or `null` if there is
|
| + * no such token.
|
| + *
|
| + * @param firstToken the token from which the search is to begin
|
| + * @param offset the offset of the token to be returned
|
| + * @return the token with the given offset
|
| + */
|
| + Token _findTokenAt(Token firstToken, int offset) {
|
| + while (firstToken.offset > offset && firstToken.type != TokenType.EOF) {
|
| + firstToken = firstToken.previous;
|
| + }
|
| + return firstToken;
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Instances of the class `InsufficientContextException` represent a situation in which an AST
|
| + * node cannot be re-parsed because there is not enough context to know how to re-parse the node.
|
| + * Clients can attempt to re-parse the parent of the node.
|
| + */
|
| +class InsufficientContextException extends IncrementalParseException {
|
| + /**
|
| + * Initialize a newly created exception to have no message and to be its own cause.
|
| + */
|
| + InsufficientContextException() : super();
|
| +
|
| + /**
|
| + * Initialize a newly created exception to have the given message and to be its own cause.
|
| + *
|
| + * @param message the message describing the reason for the exception
|
| + */
|
| + InsufficientContextException.con1(String message) : super.con1(message);
|
| +
|
| + /**
|
| + * Initialize a newly created exception to have no message and to have the given cause.
|
| + *
|
| + * @param cause the exception that caused this exception
|
| + */
|
| + InsufficientContextException.con2(Exception cause) : super.con2(cause);
|
| +}
|
| +
|
| +/**
|
| + * Instances of the class `Modifiers` implement a simple data-holder for a method that needs
|
| + * to return multiple values.
|
| + */
|
| +class Modifiers {
|
| + /**
|
| + * The token representing the keyword 'abstract', or `null` if the keyword was not found.
|
| + */
|
| + Token abstractKeyword;
|
| +
|
| + /**
|
| + * The token representing the keyword 'const', or `null` if the keyword was not found.
|
| + */
|
| + Token constKeyword;
|
| +
|
| + /**
|
| + * The token representing the keyword 'external', or `null` if the keyword was not found.
|
| + */
|
| + Token externalKeyword;
|
| +
|
| + /**
|
| + * The token representing the keyword 'factory', or `null` if the keyword was not found.
|
| + */
|
| + Token factoryKeyword;
|
| +
|
| + /**
|
| + * The token representing the keyword 'final', or `null` if the keyword was not found.
|
| + */
|
| + Token finalKeyword;
|
| +
|
| + /**
|
| + * The token representing the keyword 'static', or `null` if the keyword was not found.
|
| + */
|
| + Token staticKeyword;
|
| +
|
| + /**
|
| + * The token representing the keyword 'var', or `null` if the keyword was not found.
|
| + */
|
| + Token varKeyword;
|
| +
|
| + @override
|
| + String toString() {
|
| + JavaStringBuilder builder = new JavaStringBuilder();
|
| + bool needsSpace = _appendKeyword(builder, false, abstractKeyword);
|
| + needsSpace = _appendKeyword(builder, needsSpace, constKeyword);
|
| + needsSpace = _appendKeyword(builder, needsSpace, externalKeyword);
|
| + needsSpace = _appendKeyword(builder, needsSpace, factoryKeyword);
|
| + needsSpace = _appendKeyword(builder, needsSpace, finalKeyword);
|
| + needsSpace = _appendKeyword(builder, needsSpace, staticKeyword);
|
| + _appendKeyword(builder, needsSpace, varKeyword);
|
| + return builder.toString();
|
| + }
|
| +
|
| + /**
|
| + * If the given keyword is not `null`, append it to the given builder, prefixing it with a
|
| + * space if needed.
|
| + *
|
| + * @param builder the builder to which the keyword will be appended
|
| + * @param needsSpace `true` if the keyword needs to be prefixed with a space
|
| + * @param keyword the keyword to be appended
|
| + * @return `true` if subsequent keywords need to be prefixed with a space
|
| + */
|
| + bool _appendKeyword(JavaStringBuilder builder, bool needsSpace, Token keyword) {
|
| + if (keyword != null) {
|
| + if (needsSpace) {
|
| + builder.appendChar(0x20);
|
| + }
|
| + builder.append(keyword.lexeme);
|
| + return true;
|
| + }
|
| + return needsSpace;
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * Instances of the class `Parser` are used to parse tokens into an AST structure.
|
| + */
|
| +class Parser {
|
| + /**
|
| + * The source being parsed.
|
| + */
|
| + final Source _source;
|
| +
|
| + /**
|
| + * The error listener that will be informed of any errors that are found during the parse.
|
| + */
|
| + final AnalysisErrorListener _errorListener;
|
| +
|
| + /**
|
| + * An [errorListener] lock, if more than `0`, then errors are not reported.
|
| + */
|
| + int _errorListenerLock = 0;
|
| +
|
| + /**
|
| + * A flag indicating whether parser is to parse function bodies.
|
| + */
|
| + bool _parseFunctionBodies = true;
|
| +
|
| + /**
|
| + * A flag indicating whether the parser is to parse the async support.
|
| + */
|
| + bool _parseAsync = AnalysisOptionsImpl.DEFAULT_ENABLE_ASYNC;
|
| +
|
| + /**
|
| + * A flag indicating whether the parser is to parse deferred libraries.
|
| + */
|
| + bool _parseDeferredLibraries = AnalysisOptionsImpl.DEFAULT_ENABLE_DEFERRED_LOADING;
|
| +
|
| + /**
|
| + * A flag indicating whether the parser is to parse enum declarations.
|
| + */
|
| + bool _parseEnum = AnalysisOptionsImpl.DEFAULT_ENABLE_ENUM;
|
| +
|
| + /**
|
| + * The next token to be parsed.
|
| + */
|
| + Token _currentToken;
|
| +
|
| + /**
|
| + * A flag indicating whether the parser is currently in a function body marked as being 'async'.
|
| + */
|
| + bool _inAsync = false;
|
| +
|
| + /**
|
| + * A flag indicating whether the parser is currently in the body of a loop.
|
| + */
|
| + bool _inLoop = false;
|
| +
|
| + /**
|
| + * A flag indicating whether the parser is currently in a switch statement.
|
| + */
|
| + bool _inSwitch = false;
|
| +
|
| + /**
|
| + * A flag indicating whether the parser is currently in a constructor field initializer, with no
|
| + * intervening parens, braces, or brackets.
|
| + */
|
| + bool _inInitializer = false;
|
| +
|
| + static String ASYNC = "async";
|
| +
|
| + static String _AWAIT = "await";
|
| +
|
| + static String _HIDE = "hide";
|
| +
|
| + static String _OF = "of";
|
| +
|
| + static String _ON = "on";
|
| +
|
| + static String _NATIVE = "native";
|
| +
|
| + static String _SHOW = "show";
|
| +
|
| + static String SYNC = "sync";
|
| +
|
| + static String _YIELD = "yield";
|
| +
|
| + /**
|
| + * Initialize a newly created parser.
|
| + *
|
| + * @param source the source being parsed
|
| + * @param errorListener the error listener that will be informed of any errors that are found
|
| + * during the parse
|
| + */
|
| + Parser(this._source, this._errorListener);
|
| +
|
| + /**
|
| + * Parse a compilation unit, starting with the given token.
|
| + *
|
| + * @param token the first token of the compilation unit
|
| + * @return the compilation unit that was parsed
|
| + */
|
| + CompilationUnit parseCompilationUnit(Token token) {
|
| + InstrumentationBuilder instrumentation = Instrumentation.builder2("dart.engine.Parser.parseCompilationUnit");
|
| + try {
|
| + _currentToken = token;
|
| + return parseCompilationUnit2();
|
| + } finally {
|
| + instrumentation.log2(2);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse the script tag and directives in a compilation unit, starting with the given token, until
|
| + * the first non-directive is encountered. The remainder of the compilation unit will not be
|
| + * parsed. Specifically, if there are directives later in the file, they will not be parsed.
|
| + *
|
| + * @param token the first token of the compilation unit
|
| + * @return the compilation unit that was parsed
|
| + */
|
| + CompilationUnit parseDirectives(Token token) {
|
| + InstrumentationBuilder instrumentation = Instrumentation.builder2("dart.engine.Parser.parseDirectives");
|
| + try {
|
| + _currentToken = token;
|
| + return _parseDirectives();
|
| + } finally {
|
| + instrumentation.log2(2);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse an expression, starting with the given token.
|
| + *
|
| + * @param token the first token of the expression
|
| + * @return the expression that was parsed, or `null` if the tokens do not represent a
|
| + * recognizable expression
|
| + */
|
| + Expression parseExpression(Token token) {
|
| + InstrumentationBuilder instrumentation = Instrumentation.builder2("dart.engine.Parser.parseExpression");
|
| + try {
|
| + _currentToken = token;
|
| + return parseExpression2();
|
| + } finally {
|
| + instrumentation.log();
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse a statement, starting with the given token.
|
| + *
|
| + * @param token the first token of the statement
|
| + * @return the statement that was parsed, or `null` if the tokens do not represent a
|
| + * recognizable statement
|
| + */
|
| + Statement parseStatement(Token token) {
|
| + InstrumentationBuilder instrumentation = Instrumentation.builder2("dart.engine.Parser.parseStatement");
|
| + try {
|
| + _currentToken = token;
|
| + return parseStatement2();
|
| + } finally {
|
| + instrumentation.log();
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse a sequence of statements, starting with the given token.
|
| + *
|
| + * @param token the first token of the sequence of statement
|
| + * @return the statements that were parsed, or `null` if the tokens do not represent a
|
| + * recognizable sequence of statements
|
| + */
|
| + List<Statement> parseStatements(Token token) {
|
| + InstrumentationBuilder instrumentation = Instrumentation.builder2("dart.engine.Parser.parseStatements");
|
| + try {
|
| + _currentToken = token;
|
| + return _parseStatementList();
|
| + } finally {
|
| + instrumentation.log();
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Set whether the parser is to parse the async support.
|
| + *
|
| + * @param parseAsync `true` if the parser is to parse the async support
|
| + */
|
| + void set parseAsync(bool parseAsync) {
|
| + this._parseAsync = parseAsync;
|
| + }
|
| +
|
| + /**
|
| + * Set whether the parser is to parse deferred libraries.
|
| + *
|
| + * @param parseDeferredLibraries `true` if the parser is to parse deferred libraries
|
| + */
|
| + void set parseDeferredLibraries(bool parseDeferredLibraries) {
|
| + this._parseDeferredLibraries = parseDeferredLibraries;
|
| + }
|
| +
|
| + /**
|
| + * Set whether the parser is to parse enum declarations.
|
| + *
|
| + * @param parseEnum `true` if the parser is to parse enum declarations
|
| + */
|
| + void set parseEnum(bool parseEnum) {
|
| + this._parseEnum = parseEnum;
|
| + }
|
| +
|
| + /**
|
| + * Set whether parser is to parse function bodies.
|
| + *
|
| + * @param parseFunctionBodies `true` if parser is to parse function bodies
|
| + */
|
| + void set parseFunctionBodies(bool parseFunctionBodies) {
|
| + this._parseFunctionBodies = parseFunctionBodies;
|
| + }
|
| +
|
| + /**
|
| + * Parse an annotation.
|
| + *
|
| + * <pre>
|
| + * annotation ::=
|
| + * '@' qualified ('.' identifier)? arguments?
|
| + * </pre>
|
| + *
|
| + * @return the annotation that was parsed
|
| + */
|
| + Annotation parseAnnotation() {
|
| + Token atSign = _expect(TokenType.AT);
|
| + Identifier name = parsePrefixedIdentifier();
|
| + Token period = null;
|
| + SimpleIdentifier constructorName = null;
|
| + if (_matches(TokenType.PERIOD)) {
|
| + period = andAdvance;
|
| + constructorName = parseSimpleIdentifier();
|
| + }
|
| + ArgumentList arguments = null;
|
| + if (_matches(TokenType.OPEN_PAREN)) {
|
| + arguments = parseArgumentList();
|
| + }
|
| + return new Annotation(atSign, name, period, constructorName, arguments);
|
| + }
|
| +
|
| + /**
|
| + * Parse an argument.
|
| + *
|
| + * <pre>
|
| + * argument ::=
|
| + * namedArgument
|
| + * | expression
|
| + *
|
| + * namedArgument ::=
|
| + * label expression
|
| + * </pre>
|
| + *
|
| + * @return the argument that was parsed
|
| + */
|
| + Expression parseArgument() {
|
| + //
|
| + // Both namedArgument and expression can start with an identifier, but only namedArgument can
|
| + // have an identifier followed by a colon.
|
| + //
|
| + if (_matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) {
|
| + return new NamedExpression(parseLabel(), parseExpression2());
|
| + } else {
|
| + return parseExpression2();
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse a list of arguments.
|
| + *
|
| + * <pre>
|
| + * arguments ::=
|
| + * '(' argumentList? ')'
|
| + *
|
| + * argumentList ::=
|
| + * namedArgument (',' namedArgument)*
|
| + * | expressionList (',' namedArgument)*
|
| + * </pre>
|
| + *
|
| + * @return the argument list that was parsed
|
| + */
|
| + ArgumentList parseArgumentList() {
|
| + Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
|
| + List<Expression> arguments = new List<Expression>();
|
| + if (_matches(TokenType.CLOSE_PAREN)) {
|
| + return new ArgumentList(leftParenthesis, arguments, andAdvance);
|
| + }
|
| + //
|
| + // Even though unnamed arguments must all appear before any named arguments, we allow them to
|
| + // appear in any order so that we can recover faster.
|
| + //
|
| + bool wasInInitializer = _inInitializer;
|
| + _inInitializer = false;
|
| + try {
|
| + Expression argument = parseArgument();
|
| + arguments.add(argument);
|
| + bool foundNamedArgument = argument is NamedExpression;
|
| + bool generatedError = false;
|
| + while (_optional(TokenType.COMMA)) {
|
| + argument = parseArgument();
|
| + arguments.add(argument);
|
| + if (foundNamedArgument) {
|
| + if (!generatedError && argument is! NamedExpression) {
|
| + // Report the error, once, but allow the arguments to be in any order in the AST.
|
| + _reportErrorForCurrentToken(ParserErrorCode.POSITIONAL_AFTER_NAMED_ARGUMENT, []);
|
| + generatedError = true;
|
| + }
|
| + } else if (argument is NamedExpression) {
|
| + foundNamedArgument = true;
|
| + }
|
| + }
|
| + // TODO(brianwilkerson) Recovery: Look at the left parenthesis to see whether there is a
|
| + // matching right parenthesis. If there is, then we're more likely missing a comma and should
|
| + // go back to parsing arguments.
|
| + Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
|
| + return new ArgumentList(leftParenthesis, arguments, rightParenthesis);
|
| + } finally {
|
| + _inInitializer = wasInInitializer;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse a bitwise or expression.
|
| + *
|
| + * <pre>
|
| + * bitwiseOrExpression ::=
|
| + * bitwiseXorExpression ('|' bitwiseXorExpression)*
|
| + * | 'super' ('|' bitwiseXorExpression)+
|
| + * </pre>
|
| + *
|
| + * @return the bitwise or expression that was parsed
|
| + */
|
| + Expression parseBitwiseOrExpression() {
|
| + Expression expression;
|
| + if (_matchesKeyword(Keyword.SUPER) && _tokenMatches(_peek(), TokenType.BAR)) {
|
| + expression = new SuperExpression(andAdvance);
|
| + } else {
|
| + expression = _parseBitwiseXorExpression();
|
| + }
|
| + while (_matches(TokenType.BAR)) {
|
| + Token operator = andAdvance;
|
| + expression = new BinaryExpression(expression, operator, _parseBitwiseXorExpression());
|
| + }
|
| + return expression;
|
| + }
|
| +
|
| + /**
|
| + * Parse a block.
|
| + *
|
| + * <pre>
|
| + * block ::=
|
| + * '{' statements '}'
|
| + * </pre>
|
| + *
|
| + * @return the block that was parsed
|
| + */
|
| + Block parseBlock() {
|
| + Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET);
|
| + List<Statement> statements = new List<Statement>();
|
| + Token statementStart = _currentToken;
|
| + while (!_matches(TokenType.EOF) && !_matches(TokenType.CLOSE_CURLY_BRACKET)) {
|
| + Statement statement = parseStatement2();
|
| + if (statement != null) {
|
| + statements.add(statement);
|
| + }
|
| + if (identical(_currentToken, statementStart)) {
|
| + // Ensure that we are making progress and report an error if we're not.
|
| + _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
|
| + _advance();
|
| + }
|
| + statementStart = _currentToken;
|
| + }
|
| + Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
|
| + return new Block(leftBracket, statements, rightBracket);
|
| + }
|
| +
|
| + /**
|
| + * Parse a class member.
|
| + *
|
| + * <pre>
|
| + * classMemberDefinition ::=
|
| + * declaration ';'
|
| + * | methodSignature functionBody
|
| + * </pre>
|
| + *
|
| + * @param className the name of the class containing the member being parsed
|
| + * @return the class member that was parsed, or `null` if what was found was not a valid
|
| + * class member
|
| + */
|
| + ClassMember parseClassMember(String className) {
|
| + CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
|
| + Modifiers modifiers = _parseModifiers();
|
| + if (_matchesKeyword(Keyword.VOID)) {
|
| + TypeName returnType = parseReturnType();
|
| + if (_matchesKeyword(Keyword.GET) && _tokenMatchesIdentifier(_peek())) {
|
| + _validateModifiersForGetterOrSetterOrMethod(modifiers);
|
| + return _parseGetter(commentAndMetadata, modifiers.externalKeyword, modifiers.staticKeyword, returnType);
|
| + } else if (_matchesKeyword(Keyword.SET) && _tokenMatchesIdentifier(_peek())) {
|
| + _validateModifiersForGetterOrSetterOrMethod(modifiers);
|
| + return _parseSetter(commentAndMetadata, modifiers.externalKeyword, modifiers.staticKeyword, returnType);
|
| + } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) {
|
| + _validateModifiersForOperator(modifiers);
|
| + return _parseOperator(commentAndMetadata, modifiers.externalKeyword, returnType);
|
| + } else if (_matchesIdentifier() && _peek().matchesAny([
|
| + TokenType.OPEN_PAREN,
|
| + TokenType.OPEN_CURLY_BRACKET,
|
| + TokenType.FUNCTION])) {
|
| + _validateModifiersForGetterOrSetterOrMethod(modifiers);
|
| + return _parseMethodDeclarationAfterReturnType(commentAndMetadata, modifiers.externalKeyword, modifiers.staticKeyword, returnType);
|
| + } else {
|
| + //
|
| + // We have found an error of some kind. Try to recover.
|
| + //
|
| + if (_matchesIdentifier()) {
|
| + if (_peek().matchesAny([TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) {
|
| + //
|
| + // We appear to have a variable declaration with a type of "void".
|
| + //
|
| + _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType, []);
|
| + return _parseInitializedIdentifierList(commentAndMetadata, modifiers.staticKeyword, _validateModifiersForField(modifiers), returnType);
|
| + }
|
| + }
|
| + if (_isOperator(_currentToken)) {
|
| + //
|
| + // We appear to have found an operator declaration without the 'operator' keyword.
|
| + //
|
| + _validateModifiersForOperator(modifiers);
|
| + return _parseOperator(commentAndMetadata, modifiers.externalKeyword, returnType);
|
| + }
|
| + _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []);
|
| + return null;
|
| + }
|
| + } else if (_matchesKeyword(Keyword.GET) && _tokenMatchesIdentifier(_peek())) {
|
| + _validateModifiersForGetterOrSetterOrMethod(modifiers);
|
| + return _parseGetter(commentAndMetadata, modifiers.externalKeyword, modifiers.staticKeyword, null);
|
| + } else if (_matchesKeyword(Keyword.SET) && _tokenMatchesIdentifier(_peek())) {
|
| + _validateModifiersForGetterOrSetterOrMethod(modifiers);
|
| + return _parseSetter(commentAndMetadata, modifiers.externalKeyword, modifiers.staticKeyword, null);
|
| + } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) {
|
| + _validateModifiersForOperator(modifiers);
|
| + return _parseOperator(commentAndMetadata, modifiers.externalKeyword, null);
|
| + } else if (!_matchesIdentifier()) {
|
| + if (_isOperator(_currentToken)) {
|
| + //
|
| + // We appear to have found an operator declaration without the 'operator' keyword.
|
| + //
|
| + _validateModifiersForOperator(modifiers);
|
| + return _parseOperator(commentAndMetadata, modifiers.externalKeyword, null);
|
| + }
|
| + Token keyword = modifiers.varKeyword;
|
| + if (keyword == null) {
|
| + keyword = modifiers.finalKeyword;
|
| + }
|
| + if (keyword == null) {
|
| + keyword = modifiers.constKeyword;
|
| + }
|
| + if (keyword != null) {
|
| + //
|
| + // We appear to have found an incomplete field declaration.
|
| + //
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER, []);
|
| + List<VariableDeclaration> variables = new List<VariableDeclaration>();
|
| + variables.add(new VariableDeclaration(null, null, _createSyntheticIdentifier(), null, null));
|
| + return new FieldDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, null, new VariableDeclarationList(null, null, keyword, null, variables), _expectSemicolon());
|
| + }
|
| + _reportErrorForToken(ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken, []);
|
| + if (commentAndMetadata.comment != null || !commentAndMetadata.metadata.isEmpty) {
|
| + //
|
| + // We appear to have found an incomplete declaration at the end of the class. At this point
|
| + // it consists of a metadata, which we don't want to loose, so we'll treat it as a method
|
| + // declaration with a missing name, parameters and empty body.
|
| + //
|
| + return new MethodDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, null, null, null, null, null, _createSyntheticIdentifier(), new FormalParameterList(null, new List<FormalParameter>(), null, null, null), new EmptyFunctionBody(_createSyntheticToken(TokenType.SEMICOLON)));
|
| + }
|
| + return null;
|
| + } else if (_tokenMatches(_peek(), TokenType.PERIOD) && _tokenMatchesIdentifier(_peekAt(2)) && _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) {
|
| + return _parseConstructor(commentAndMetadata, modifiers.externalKeyword, _validateModifiersForConstructor(modifiers), modifiers.factoryKeyword, parseSimpleIdentifier(), andAdvance, parseSimpleIdentifier(), parseFormalParameterList());
|
| + } else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
|
| + SimpleIdentifier methodName = parseSimpleIdentifier();
|
| + FormalParameterList parameters = parseFormalParameterList();
|
| + if (_matches(TokenType.COLON) || modifiers.factoryKeyword != null || methodName.name == className) {
|
| + return _parseConstructor(commentAndMetadata, modifiers.externalKeyword, _validateModifiersForConstructor(modifiers), modifiers.factoryKeyword, methodName, null, null, parameters);
|
| + }
|
| + _validateModifiersForGetterOrSetterOrMethod(modifiers);
|
| + _validateFormalParameterList(parameters);
|
| + return _parseMethodDeclarationAfterParameters(commentAndMetadata, modifiers.externalKeyword, modifiers.staticKeyword, null, methodName, parameters);
|
| + } else if (_peek().matchesAny([TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) {
|
| + if (modifiers.constKeyword == null && modifiers.finalKeyword == null && modifiers.varKeyword == null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, []);
|
| + }
|
| + return _parseInitializedIdentifierList(commentAndMetadata, modifiers.staticKeyword, _validateModifiersForField(modifiers), null);
|
| + }
|
| + TypeName type = parseTypeName();
|
| + if (_matchesKeyword(Keyword.GET) && _tokenMatchesIdentifier(_peek())) {
|
| + _validateModifiersForGetterOrSetterOrMethod(modifiers);
|
| + return _parseGetter(commentAndMetadata, modifiers.externalKeyword, modifiers.staticKeyword, type);
|
| + } else if (_matchesKeyword(Keyword.SET) && _tokenMatchesIdentifier(_peek())) {
|
| + _validateModifiersForGetterOrSetterOrMethod(modifiers);
|
| + return _parseSetter(commentAndMetadata, modifiers.externalKeyword, modifiers.staticKeyword, type);
|
| + } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) {
|
| + _validateModifiersForOperator(modifiers);
|
| + return _parseOperator(commentAndMetadata, modifiers.externalKeyword, type);
|
| + } else if (!_matchesIdentifier()) {
|
| + if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
|
| + //
|
| + // We appear to have found an incomplete declaration at the end of the class. At this point
|
| + // it consists of a type name, so we'll treat it as a field declaration with a missing
|
| + // field name and semicolon.
|
| + //
|
| + return _parseInitializedIdentifierList(commentAndMetadata, modifiers.staticKeyword, _validateModifiersForField(modifiers), type);
|
| + }
|
| + if (_isOperator(_currentToken)) {
|
| + //
|
| + // We appear to have found an operator declaration without the 'operator' keyword.
|
| + //
|
| + _validateModifiersForOperator(modifiers);
|
| + return _parseOperator(commentAndMetadata, modifiers.externalKeyword, type);
|
| + }
|
| + //
|
| + // We appear to have found an incomplete declaration before another declaration.
|
| + // At this point it consists of a type name, so we'll treat it as a field declaration
|
| + // with a missing field name and semicolon.
|
| + //
|
| + _reportErrorForToken(ParserErrorCode.EXPECTED_CLASS_MEMBER, _currentToken, []);
|
| + try {
|
| + _lockErrorListener();
|
| + return _parseInitializedIdentifierList(commentAndMetadata, modifiers.staticKeyword, _validateModifiersForField(modifiers), type);
|
| + } finally {
|
| + _unlockErrorListener();
|
| + }
|
| + } else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
|
| + SimpleIdentifier methodName = parseSimpleIdentifier();
|
| + FormalParameterList parameters = parseFormalParameterList();
|
| + if (methodName.name == className) {
|
| + _reportErrorForNode(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, type, []);
|
| + return _parseConstructor(commentAndMetadata, modifiers.externalKeyword, _validateModifiersForConstructor(modifiers), modifiers.factoryKeyword, methodName, null, null, parameters);
|
| + }
|
| + _validateModifiersForGetterOrSetterOrMethod(modifiers);
|
| + _validateFormalParameterList(parameters);
|
| + return _parseMethodDeclarationAfterParameters(commentAndMetadata, modifiers.externalKeyword, modifiers.staticKeyword, type, methodName, parameters);
|
| + } else if (_tokenMatches(_peek(), TokenType.OPEN_CURLY_BRACKET)) {
|
| + // We have found "TypeName identifier {", and are guessing that this is a getter without the
|
| + // keyword 'get'.
|
| + _validateModifiersForGetterOrSetterOrMethod(modifiers);
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_GET, []);
|
| + _currentToken = _injectToken(new Parser_SyntheticKeywordToken(Keyword.GET, _currentToken.offset));
|
| + return _parseGetter(commentAndMetadata, modifiers.externalKeyword, modifiers.staticKeyword, type);
|
| + }
|
| + return _parseInitializedIdentifierList(commentAndMetadata, modifiers.staticKeyword, _validateModifiersForField(modifiers), type);
|
| + }
|
| +
|
| + /**
|
| + * Parse a compilation unit.
|
| + *
|
| + * Specified:
|
| + *
|
| + * <pre>
|
| + * compilationUnit ::=
|
| + * scriptTag? directive* topLevelDeclaration*
|
| + * </pre>
|
| + * Actual:
|
| + *
|
| + * <pre>
|
| + * compilationUnit ::=
|
| + * scriptTag? topLevelElement*
|
| + *
|
| + * topLevelElement ::=
|
| + * directive
|
| + * | topLevelDeclaration
|
| + * </pre>
|
| + *
|
| + * @return the compilation unit that was parsed
|
| + */
|
| + CompilationUnit parseCompilationUnit2() {
|
| + Token firstToken = _currentToken;
|
| + ScriptTag scriptTag = null;
|
| + if (_matches(TokenType.SCRIPT_TAG)) {
|
| + scriptTag = new ScriptTag(andAdvance);
|
| + }
|
| + //
|
| + // Even though all directives must appear before declarations and must occur in a given order,
|
| + // we allow directives and declarations to occur in any order so that we can recover better.
|
| + //
|
| + bool libraryDirectiveFound = false;
|
| + bool partOfDirectiveFound = false;
|
| + bool partDirectiveFound = false;
|
| + bool directiveFoundAfterDeclaration = false;
|
| + List<Directive> directives = new List<Directive>();
|
| + List<CompilationUnitMember> declarations = new List<CompilationUnitMember>();
|
| + Token memberStart = _currentToken;
|
| + while (!_matches(TokenType.EOF)) {
|
| + CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
|
| + if ((_matchesKeyword(Keyword.IMPORT) || _matchesKeyword(Keyword.EXPORT) || _matchesKeyword(Keyword.LIBRARY) || _matchesKeyword(Keyword.PART)) && !_tokenMatches(_peek(), TokenType.PERIOD) && !_tokenMatches(_peek(), TokenType.LT) && !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
|
| + Directive directive = _parseDirective(commentAndMetadata);
|
| + if (declarations.length > 0 && !directiveFoundAfterDeclaration) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.DIRECTIVE_AFTER_DECLARATION, []);
|
| + directiveFoundAfterDeclaration = true;
|
| + }
|
| + if (directive is LibraryDirective) {
|
| + if (libraryDirectiveFound) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MULTIPLE_LIBRARY_DIRECTIVES, []);
|
| + } else {
|
| + if (directives.length > 0) {
|
| + _reportErrorForToken(ParserErrorCode.LIBRARY_DIRECTIVE_NOT_FIRST, directive.libraryToken, []);
|
| + }
|
| + libraryDirectiveFound = true;
|
| + }
|
| + } else if (directive is PartDirective) {
|
| + partDirectiveFound = true;
|
| + } else if (partDirectiveFound) {
|
| + if (directive is ExportDirective) {
|
| + _reportErrorForToken(ParserErrorCode.EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE, directive.keyword, []);
|
| + } else if (directive is ImportDirective) {
|
| + _reportErrorForToken(ParserErrorCode.IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE, directive.keyword, []);
|
| + }
|
| + }
|
| + if (directive is PartOfDirective) {
|
| + if (partOfDirectiveFound) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MULTIPLE_PART_OF_DIRECTIVES, []);
|
| + } else {
|
| + int directiveCount = directives.length;
|
| + for (int i = 0; i < directiveCount; i++) {
|
| + _reportErrorForToken(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, directives[i].keyword, []);
|
| + }
|
| + partOfDirectiveFound = true;
|
| + }
|
| + } else {
|
| + if (partOfDirectiveFound) {
|
| + _reportErrorForToken(ParserErrorCode.NON_PART_OF_DIRECTIVE_IN_PART, directive.keyword, []);
|
| + }
|
| + }
|
| + directives.add(directive);
|
| + } else if (_matches(TokenType.SEMICOLON)) {
|
| + _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
|
| + _advance();
|
| + } else {
|
| + CompilationUnitMember member = _parseCompilationUnitMember(commentAndMetadata);
|
| + if (member != null) {
|
| + declarations.add(member);
|
| + }
|
| + }
|
| + if (identical(_currentToken, memberStart)) {
|
| + _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
|
| + _advance();
|
| + while (!_matches(TokenType.EOF) && !_couldBeStartOfCompilationUnitMember()) {
|
| + _advance();
|
| + }
|
| + }
|
| + memberStart = _currentToken;
|
| + }
|
| + return new CompilationUnit(firstToken, scriptTag, directives, declarations, _currentToken);
|
| + }
|
| +
|
| + /**
|
| + * Parse a conditional expression.
|
| + *
|
| + * <pre>
|
| + * conditionalExpression ::=
|
| + * logicalOrExpression ('?' expressionWithoutCascade ':' expressionWithoutCascade)?
|
| + * </pre>
|
| + *
|
| + * @return the conditional expression that was parsed
|
| + */
|
| + Expression parseConditionalExpression() {
|
| + Expression condition = parseLogicalOrExpression();
|
| + if (!_matches(TokenType.QUESTION)) {
|
| + return condition;
|
| + }
|
| + Token question = andAdvance;
|
| + Expression thenExpression = parseExpressionWithoutCascade();
|
| + Token colon = _expect(TokenType.COLON);
|
| + Expression elseExpression = parseExpressionWithoutCascade();
|
| + return new ConditionalExpression(condition, question, thenExpression, colon, elseExpression);
|
| + }
|
| +
|
| + /**
|
| + * Parse the name of a constructor.
|
| + *
|
| + * <pre>
|
| + * constructorName:
|
| + * type ('.' identifier)?
|
| + * </pre>
|
| + *
|
| + * @return the constructor name that was parsed
|
| + */
|
| + ConstructorName parseConstructorName() {
|
| + TypeName type = parseTypeName();
|
| + Token period = null;
|
| + SimpleIdentifier name = null;
|
| + if (_matches(TokenType.PERIOD)) {
|
| + period = andAdvance;
|
| + name = parseSimpleIdentifier();
|
| + }
|
| + return new ConstructorName(type, period, name);
|
| + }
|
| +
|
| + /**
|
| + * Parse an expression that might contain a cascade.
|
| + *
|
| + * <pre>
|
| + * expression ::=
|
| + * assignableExpression assignmentOperator expression
|
| + * | conditionalExpression cascadeSection*
|
| + * | throwExpression
|
| + * </pre>
|
| + *
|
| + * @return the expression that was parsed
|
| + */
|
| + Expression parseExpression2() {
|
| + if (_matchesKeyword(Keyword.THROW)) {
|
| + return _parseThrowExpression();
|
| + } else if (_matchesKeyword(Keyword.RETHROW)) {
|
| + // TODO(brianwilkerson) Rethrow is a statement again.
|
| + return _parseRethrowExpression();
|
| + }
|
| + //
|
| + // assignableExpression is a subset of conditionalExpression, so we can parse a conditional
|
| + // expression and then determine whether it is followed by an assignmentOperator, checking for
|
| + // conformance to the restricted grammar after making that determination.
|
| + //
|
| + Expression expression = parseConditionalExpression();
|
| + TokenType tokenType = _currentToken.type;
|
| + if (tokenType == TokenType.PERIOD_PERIOD) {
|
| + List<Expression> cascadeSections = new List<Expression>();
|
| + while (tokenType == TokenType.PERIOD_PERIOD) {
|
| + Expression section = _parseCascadeSection();
|
| + if (section != null) {
|
| + cascadeSections.add(section);
|
| + }
|
| + tokenType = _currentToken.type;
|
| + }
|
| + return new CascadeExpression(expression, cascadeSections);
|
| + } else if (tokenType.isAssignmentOperator) {
|
| + Token operator = andAdvance;
|
| + _ensureAssignable(expression);
|
| + return new AssignmentExpression(expression, operator, parseExpression2());
|
| + }
|
| + return expression;
|
| + }
|
| +
|
| + /**
|
| + * Parse an expression that does not contain any cascades.
|
| + *
|
| + * <pre>
|
| + * expressionWithoutCascade ::=
|
| + * assignableExpression assignmentOperator expressionWithoutCascade
|
| + * | conditionalExpression
|
| + * | throwExpressionWithoutCascade
|
| + * </pre>
|
| + *
|
| + * @return the expression that was parsed
|
| + */
|
| + Expression parseExpressionWithoutCascade() {
|
| + if (_matchesKeyword(Keyword.THROW)) {
|
| + return _parseThrowExpressionWithoutCascade();
|
| + } else if (_matchesKeyword(Keyword.RETHROW)) {
|
| + return _parseRethrowExpression();
|
| + }
|
| + //
|
| + // assignableExpression is a subset of conditionalExpression, so we can parse a conditional
|
| + // expression and then determine whether it is followed by an assignmentOperator, checking for
|
| + // conformance to the restricted grammar after making that determination.
|
| + //
|
| + Expression expression = parseConditionalExpression();
|
| + if (_currentToken.type.isAssignmentOperator) {
|
| + Token operator = andAdvance;
|
| + _ensureAssignable(expression);
|
| + expression = new AssignmentExpression(expression, operator, parseExpressionWithoutCascade());
|
| + }
|
| + return expression;
|
| + }
|
| +
|
| + /**
|
| + * Parse a class extends clause.
|
| + *
|
| + * <pre>
|
| + * classExtendsClause ::=
|
| + * 'extends' type
|
| + * </pre>
|
| + *
|
| + * @return the class extends clause that was parsed
|
| + */
|
| + ExtendsClause parseExtendsClause() {
|
| + Token keyword = _expectKeyword(Keyword.EXTENDS);
|
| + TypeName superclass = parseTypeName();
|
| + return new ExtendsClause(keyword, superclass);
|
| + }
|
| +
|
| + /**
|
| + * Parse a list of formal parameters.
|
| + *
|
| + * <pre>
|
| + * formalParameterList ::=
|
| + * '(' ')'
|
| + * | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
|
| + * | '(' optionalFormalParameters ')'
|
| + *
|
| + * normalFormalParameters ::=
|
| + * normalFormalParameter (',' normalFormalParameter)*
|
| + *
|
| + * optionalFormalParameters ::=
|
| + * optionalPositionalFormalParameters
|
| + * | namedFormalParameters
|
| + *
|
| + * optionalPositionalFormalParameters ::=
|
| + * '[' defaultFormalParameter (',' defaultFormalParameter)* ']'
|
| + *
|
| + * namedFormalParameters ::=
|
| + * '{' defaultNamedParameter (',' defaultNamedParameter)* '}'
|
| + * </pre>
|
| + *
|
| + * @return the formal parameters that were parsed
|
| + */
|
| + FormalParameterList parseFormalParameterList() {
|
| + Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
|
| + if (_matches(TokenType.CLOSE_PAREN)) {
|
| + return new FormalParameterList(leftParenthesis, null, null, null, andAdvance);
|
| + }
|
| + //
|
| + // Even though it is invalid to have default parameters outside of brackets, required parameters
|
| + // inside of brackets, or multiple groups of default and named parameters, we allow all of these
|
| + // cases so that we can recover better.
|
| + //
|
| + List<FormalParameter> parameters = new List<FormalParameter>();
|
| + List<FormalParameter> normalParameters = new List<FormalParameter>();
|
| + List<FormalParameter> positionalParameters = new List<FormalParameter>();
|
| + List<FormalParameter> namedParameters = new List<FormalParameter>();
|
| + List<FormalParameter> currentParameters = normalParameters;
|
| + Token leftSquareBracket = null;
|
| + Token rightSquareBracket = null;
|
| + Token leftCurlyBracket = null;
|
| + Token rightCurlyBracket = null;
|
| + ParameterKind kind = ParameterKind.REQUIRED;
|
| + bool firstParameter = true;
|
| + bool reportedMuliplePositionalGroups = false;
|
| + bool reportedMulipleNamedGroups = false;
|
| + bool reportedMixedGroups = false;
|
| + bool wasOptionalParameter = false;
|
| + Token initialToken = null;
|
| + do {
|
| + if (firstParameter) {
|
| + firstParameter = false;
|
| + } else if (!_optional(TokenType.COMMA)) {
|
| + // TODO(brianwilkerson) The token is wrong, we need to recover from this case.
|
| + if (_getEndToken(leftParenthesis) != null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TOKEN, [TokenType.COMMA.lexeme]);
|
| + } else {
|
| + _reportErrorForToken(ParserErrorCode.MISSING_CLOSING_PARENTHESIS, _currentToken.previous, []);
|
| + break;
|
| + }
|
| + }
|
| + initialToken = _currentToken;
|
| + //
|
| + // Handle the beginning of parameter groups.
|
| + //
|
| + if (_matches(TokenType.OPEN_SQUARE_BRACKET)) {
|
| + wasOptionalParameter = true;
|
| + if (leftSquareBracket != null && !reportedMuliplePositionalGroups) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MULTIPLE_POSITIONAL_PARAMETER_GROUPS, []);
|
| + reportedMuliplePositionalGroups = true;
|
| + }
|
| + if (leftCurlyBracket != null && !reportedMixedGroups) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS, []);
|
| + reportedMixedGroups = true;
|
| + }
|
| + leftSquareBracket = andAdvance;
|
| + currentParameters = positionalParameters;
|
| + kind = ParameterKind.POSITIONAL;
|
| + } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
|
| + wasOptionalParameter = true;
|
| + if (leftCurlyBracket != null && !reportedMulipleNamedGroups) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MULTIPLE_NAMED_PARAMETER_GROUPS, []);
|
| + reportedMulipleNamedGroups = true;
|
| + }
|
| + if (leftSquareBracket != null && !reportedMixedGroups) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MIXED_PARAMETER_GROUPS, []);
|
| + reportedMixedGroups = true;
|
| + }
|
| + leftCurlyBracket = andAdvance;
|
| + currentParameters = namedParameters;
|
| + kind = ParameterKind.NAMED;
|
| + }
|
| + //
|
| + // Parse and record the parameter.
|
| + //
|
| + FormalParameter parameter = _parseFormalParameter(kind);
|
| + parameters.add(parameter);
|
| + currentParameters.add(parameter);
|
| + if (kind == ParameterKind.REQUIRED && wasOptionalParameter) {
|
| + _reportErrorForNode(ParserErrorCode.NORMAL_BEFORE_OPTIONAL_PARAMETERS, parameter, []);
|
| + }
|
| + //
|
| + // Handle the end of parameter groups.
|
| + //
|
| + // TODO(brianwilkerson) Improve the detection and reporting of missing and mismatched delimiters.
|
| + if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) {
|
| + rightSquareBracket = andAdvance;
|
| + currentParameters = normalParameters;
|
| + if (leftSquareBracket == null) {
|
| + if (leftCurlyBracket != null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
|
| + rightCurlyBracket = rightSquareBracket;
|
| + rightSquareBracket = null;
|
| + } else {
|
| + _reportErrorForCurrentToken(ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP, ["["]);
|
| + }
|
| + }
|
| + kind = ParameterKind.REQUIRED;
|
| + } else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
|
| + rightCurlyBracket = andAdvance;
|
| + currentParameters = normalParameters;
|
| + if (leftCurlyBracket == null) {
|
| + if (leftSquareBracket != null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.WRONG_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
|
| + rightSquareBracket = rightCurlyBracket;
|
| + rightCurlyBracket = null;
|
| + } else {
|
| + _reportErrorForCurrentToken(ParserErrorCode.UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP, ["{"]);
|
| + }
|
| + }
|
| + kind = ParameterKind.REQUIRED;
|
| + }
|
| + } while (!_matches(TokenType.CLOSE_PAREN) && !identical(initialToken, _currentToken));
|
| + Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
|
| + //
|
| + // Check that the groups were closed correctly.
|
| + //
|
| + if (leftSquareBracket != null && rightSquareBracket == null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["]"]);
|
| + }
|
| + if (leftCurlyBracket != null && rightCurlyBracket == null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_TERMINATOR_FOR_PARAMETER_GROUP, ["}"]);
|
| + }
|
| + //
|
| + // Build the parameter list.
|
| + //
|
| + if (leftSquareBracket == null) {
|
| + leftSquareBracket = leftCurlyBracket;
|
| + }
|
| + if (rightSquareBracket == null) {
|
| + rightSquareBracket = rightCurlyBracket;
|
| + }
|
| + return new FormalParameterList(leftParenthesis, parameters, leftSquareBracket, rightSquareBracket, rightParenthesis);
|
| + }
|
| +
|
| + /**
|
| + * Parse a function expression.
|
| + *
|
| + * <pre>
|
| + * functionExpression ::=
|
| + * formalParameterList functionExpressionBody
|
| + * </pre>
|
| + *
|
| + * @return the function expression that was parsed
|
| + */
|
| + FunctionExpression parseFunctionExpression() {
|
| + FormalParameterList parameters = parseFormalParameterList();
|
| + _validateFormalParameterList(parameters);
|
| + FunctionBody body = _parseFunctionBody(false, ParserErrorCode.MISSING_FUNCTION_BODY, true);
|
| + return new FunctionExpression(parameters, body);
|
| + }
|
| +
|
| + /**
|
| + * Parse an implements clause.
|
| + *
|
| + * <pre>
|
| + * implementsClause ::=
|
| + * 'implements' type (',' type)*
|
| + * </pre>
|
| + *
|
| + * @return the implements clause that was parsed
|
| + */
|
| + ImplementsClause parseImplementsClause() {
|
| + Token keyword = _expectKeyword(Keyword.IMPLEMENTS);
|
| + List<TypeName> interfaces = new List<TypeName>();
|
| + interfaces.add(parseTypeName());
|
| + while (_optional(TokenType.COMMA)) {
|
| + interfaces.add(parseTypeName());
|
| + }
|
| + return new ImplementsClause(keyword, interfaces);
|
| + }
|
| +
|
| + /**
|
| + * Parse a label.
|
| + *
|
| + * <pre>
|
| + * label ::=
|
| + * identifier ':'
|
| + * </pre>
|
| + *
|
| + * @return the label that was parsed
|
| + */
|
| + Label parseLabel() {
|
| + SimpleIdentifier label = parseSimpleIdentifier();
|
| + Token colon = _expect(TokenType.COLON);
|
| + return new Label(label, colon);
|
| + }
|
| +
|
| + /**
|
| + * Parse a library identifier.
|
| + *
|
| + * <pre>
|
| + * libraryIdentifier ::=
|
| + * identifier ('.' identifier)*
|
| + * </pre>
|
| + *
|
| + * @return the library identifier that was parsed
|
| + */
|
| + LibraryIdentifier parseLibraryIdentifier() {
|
| + List<SimpleIdentifier> components = new List<SimpleIdentifier>();
|
| + components.add(parseSimpleIdentifier());
|
| + while (_matches(TokenType.PERIOD)) {
|
| + _advance();
|
| + components.add(parseSimpleIdentifier());
|
| + }
|
| + return new LibraryIdentifier(components);
|
| + }
|
| +
|
| + /**
|
| + * Parse a logical or expression.
|
| + *
|
| + * <pre>
|
| + * logicalOrExpression ::=
|
| + * logicalAndExpression ('||' logicalAndExpression)*
|
| + * </pre>
|
| + *
|
| + * @return the logical or expression that was parsed
|
| + */
|
| + Expression parseLogicalOrExpression() {
|
| + Expression expression = _parseLogicalAndExpression();
|
| + while (_matches(TokenType.BAR_BAR)) {
|
| + Token operator = andAdvance;
|
| + expression = new BinaryExpression(expression, operator, _parseLogicalAndExpression());
|
| + }
|
| + return expression;
|
| + }
|
| +
|
| + /**
|
| + * Parse a map literal entry.
|
| + *
|
| + * <pre>
|
| + * mapLiteralEntry ::=
|
| + * expression ':' expression
|
| + * </pre>
|
| + *
|
| + * @return the map literal entry that was parsed
|
| + */
|
| + MapLiteralEntry parseMapLiteralEntry() {
|
| + Expression key = parseExpression2();
|
| + Token separator = _expect(TokenType.COLON);
|
| + Expression value = parseExpression2();
|
| + return new MapLiteralEntry(key, separator, value);
|
| + }
|
| +
|
| + /**
|
| + * Parse a normal formal parameter.
|
| + *
|
| + * <pre>
|
| + * normalFormalParameter ::=
|
| + * functionSignature
|
| + * | fieldFormalParameter
|
| + * | simpleFormalParameter
|
| + *
|
| + * functionSignature:
|
| + * metadata returnType? identifier formalParameterList
|
| + *
|
| + * fieldFormalParameter ::=
|
| + * metadata finalConstVarOrType? 'this' '.' identifier
|
| + *
|
| + * simpleFormalParameter ::=
|
| + * declaredIdentifier
|
| + * | metadata identifier
|
| + * </pre>
|
| + *
|
| + * @return the normal formal parameter that was parsed
|
| + */
|
| + NormalFormalParameter parseNormalFormalParameter() {
|
| + CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
|
| + FinalConstVarOrType holder = _parseFinalConstVarOrType(true);
|
| + Token thisKeyword = null;
|
| + Token period = null;
|
| + if (_matchesKeyword(Keyword.THIS)) {
|
| + thisKeyword = andAdvance;
|
| + period = _expect(TokenType.PERIOD);
|
| + }
|
| + SimpleIdentifier identifier = parseSimpleIdentifier();
|
| + if (_matches(TokenType.OPEN_PAREN)) {
|
| + FormalParameterList parameters = parseFormalParameterList();
|
| + if (thisKeyword == null) {
|
| + if (holder.keyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.FUNCTION_TYPED_PARAMETER_VAR, holder.keyword, []);
|
| + }
|
| + return new FunctionTypedFormalParameter(commentAndMetadata.comment, commentAndMetadata.metadata, holder.type, identifier, parameters);
|
| + } else {
|
| + return new FieldFormalParameter(commentAndMetadata.comment, commentAndMetadata.metadata, holder.keyword, holder.type, thisKeyword, period, identifier, parameters);
|
| + }
|
| + }
|
| + TypeName type = holder.type;
|
| + if (type != null) {
|
| + if (_tokenMatchesKeyword(type.name.beginToken, Keyword.VOID)) {
|
| + _reportErrorForToken(ParserErrorCode.VOID_PARAMETER, type.name.beginToken, []);
|
| + } else if (holder.keyword != null && _tokenMatchesKeyword(holder.keyword, Keyword.VAR)) {
|
| + _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, holder.keyword, []);
|
| + }
|
| + }
|
| + if (thisKeyword != null) {
|
| + return new FieldFormalParameter(commentAndMetadata.comment, commentAndMetadata.metadata, holder.keyword, holder.type, thisKeyword, period, identifier, null);
|
| + }
|
| + return new SimpleFormalParameter(commentAndMetadata.comment, commentAndMetadata.metadata, holder.keyword, holder.type, identifier);
|
| + }
|
| +
|
| + /**
|
| + * Parse a prefixed identifier.
|
| + *
|
| + * <pre>
|
| + * prefixedIdentifier ::=
|
| + * identifier ('.' identifier)?
|
| + * </pre>
|
| + *
|
| + * @return the prefixed identifier that was parsed
|
| + */
|
| + Identifier parsePrefixedIdentifier() {
|
| + SimpleIdentifier qualifier = parseSimpleIdentifier();
|
| + if (!_matches(TokenType.PERIOD)) {
|
| + return qualifier;
|
| + }
|
| + Token period = andAdvance;
|
| + SimpleIdentifier qualified = parseSimpleIdentifier();
|
| + return new PrefixedIdentifier(qualifier, period, qualified);
|
| + }
|
| +
|
| + /**
|
| + * Parse a return type.
|
| + *
|
| + * <pre>
|
| + * returnType ::=
|
| + * 'void'
|
| + * | type
|
| + * </pre>
|
| + *
|
| + * @return the return type that was parsed
|
| + */
|
| + TypeName parseReturnType() {
|
| + if (_matchesKeyword(Keyword.VOID)) {
|
| + return new TypeName(new SimpleIdentifier(andAdvance), null);
|
| + } else {
|
| + return parseTypeName();
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse a simple identifier.
|
| + *
|
| + * <pre>
|
| + * identifier ::=
|
| + * IDENTIFIER
|
| + * </pre>
|
| + *
|
| + * @return the simple identifier that was parsed
|
| + */
|
| + SimpleIdentifier parseSimpleIdentifier() {
|
| + if (_matchesIdentifier()) {
|
| + return new SimpleIdentifier(andAdvance);
|
| + }
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER, []);
|
| + return _createSyntheticIdentifier();
|
| + }
|
| +
|
| + /**
|
| + * Parse a statement.
|
| + *
|
| + * <pre>
|
| + * statement ::=
|
| + * label* nonLabeledStatement
|
| + * </pre>
|
| + *
|
| + * @return the statement that was parsed
|
| + */
|
| + Statement parseStatement2() {
|
| + List<Label> labels = new List<Label>();
|
| + while (_matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) {
|
| + labels.add(parseLabel());
|
| + }
|
| + Statement statement = _parseNonLabeledStatement();
|
| + if (labels.isEmpty) {
|
| + return statement;
|
| + }
|
| + return new LabeledStatement(labels, statement);
|
| + }
|
| +
|
| + /**
|
| + * Parse a string literal.
|
| + *
|
| + * <pre>
|
| + * stringLiteral ::=
|
| + * MULTI_LINE_STRING+
|
| + * | SINGLE_LINE_STRING+
|
| + * </pre>
|
| + *
|
| + * @return the string literal that was parsed
|
| + */
|
| + StringLiteral parseStringLiteral() {
|
| + List<StringLiteral> strings = new List<StringLiteral>();
|
| + while (_matches(TokenType.STRING)) {
|
| + Token string = andAdvance;
|
| + if (_matches(TokenType.STRING_INTERPOLATION_EXPRESSION) || _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER)) {
|
| + strings.add(_parseStringInterpolation(string));
|
| + } else {
|
| + strings.add(new SimpleStringLiteral(string, _computeStringValue(string.lexeme, true, true)));
|
| + }
|
| + }
|
| + if (strings.length < 1) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_STRING_LITERAL, []);
|
| + return _createSyntheticStringLiteral();
|
| + } else if (strings.length == 1) {
|
| + return strings[0];
|
| + } else {
|
| + return new AdjacentStrings(strings);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse a list of type arguments.
|
| + *
|
| + * <pre>
|
| + * typeArguments ::=
|
| + * '<' typeList '>'
|
| + *
|
| + * typeList ::=
|
| + * type (',' type)*
|
| + * </pre>
|
| + *
|
| + * @return the type argument list that was parsed
|
| + */
|
| + TypeArgumentList parseTypeArgumentList() {
|
| + Token leftBracket = _expect(TokenType.LT);
|
| + List<TypeName> arguments = new List<TypeName>();
|
| + arguments.add(parseTypeName());
|
| + while (_optional(TokenType.COMMA)) {
|
| + arguments.add(parseTypeName());
|
| + }
|
| + Token rightBracket = _expectGt();
|
| + return new TypeArgumentList(leftBracket, arguments, rightBracket);
|
| + }
|
| +
|
| + /**
|
| + * Parse a type name.
|
| + *
|
| + * <pre>
|
| + * type ::=
|
| + * qualified typeArguments?
|
| + * </pre>
|
| + *
|
| + * @return the type name that was parsed
|
| + */
|
| + TypeName parseTypeName() {
|
| + Identifier typeName;
|
| + if (_matchesKeyword(Keyword.VAR)) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.VAR_AS_TYPE_NAME, []);
|
| + typeName = new SimpleIdentifier(andAdvance);
|
| + } else if (_matchesIdentifier()) {
|
| + typeName = parsePrefixedIdentifier();
|
| + } else {
|
| + typeName = _createSyntheticIdentifier();
|
| + _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TYPE_NAME, []);
|
| + }
|
| + TypeArgumentList typeArguments = null;
|
| + if (_matches(TokenType.LT)) {
|
| + typeArguments = parseTypeArgumentList();
|
| + }
|
| + return new TypeName(typeName, typeArguments);
|
| + }
|
| +
|
| + /**
|
| + * Parse a type parameter.
|
| + *
|
| + * <pre>
|
| + * typeParameter ::=
|
| + * metadata name ('extends' bound)?
|
| + * </pre>
|
| + *
|
| + * @return the type parameter that was parsed
|
| + */
|
| + TypeParameter parseTypeParameter() {
|
| + CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
|
| + SimpleIdentifier name = parseSimpleIdentifier();
|
| + if (_matchesKeyword(Keyword.EXTENDS)) {
|
| + Token keyword = andAdvance;
|
| + TypeName bound = parseTypeName();
|
| + return new TypeParameter(commentAndMetadata.comment, commentAndMetadata.metadata, name, keyword, bound);
|
| + }
|
| + return new TypeParameter(commentAndMetadata.comment, commentAndMetadata.metadata, name, null, null);
|
| + }
|
| +
|
| + /**
|
| + * Parse a list of type parameters.
|
| + *
|
| + * <pre>
|
| + * typeParameterList ::=
|
| + * '<' typeParameter (',' typeParameter)* '>'
|
| + * </pre>
|
| + *
|
| + * @return the list of type parameters that were parsed
|
| + */
|
| + TypeParameterList parseTypeParameterList() {
|
| + Token leftBracket = _expect(TokenType.LT);
|
| + List<TypeParameter> typeParameters = new List<TypeParameter>();
|
| + typeParameters.add(parseTypeParameter());
|
| + while (_optional(TokenType.COMMA)) {
|
| + typeParameters.add(parseTypeParameter());
|
| + }
|
| + Token rightBracket = _expectGt();
|
| + return new TypeParameterList(leftBracket, typeParameters, rightBracket);
|
| + }
|
| +
|
| + /**
|
| + * Parse a with clause.
|
| + *
|
| + * <pre>
|
| + * withClause ::=
|
| + * 'with' typeName (',' typeName)*
|
| + * </pre>
|
| + *
|
| + * @return the with clause that was parsed
|
| + */
|
| + WithClause parseWithClause() {
|
| + Token with2 = _expectKeyword(Keyword.WITH);
|
| + List<TypeName> types = new List<TypeName>();
|
| + types.add(parseTypeName());
|
| + while (_optional(TokenType.COMMA)) {
|
| + types.add(parseTypeName());
|
| + }
|
| + return new WithClause(with2, types);
|
| + }
|
| +
|
| + void set currentToken(Token currentToken) {
|
| + this._currentToken = currentToken;
|
| + }
|
| +
|
| + /**
|
| + * Advance to the next token in the token stream.
|
| + */
|
| + void _advance() {
|
| + _currentToken = _currentToken.next;
|
| + }
|
| +
|
| + /**
|
| + * Append the character equivalent of the given scalar value to the given builder. Use the start
|
| + * and end indices to report an error, and don't append anything to the builder, if the scalar
|
| + * value is invalid.
|
| + *
|
| + * @param builder the builder to which the scalar value is to be appended
|
| + * @param escapeSequence the escape sequence that was parsed to produce the scalar value
|
| + * @param scalarValue the value to be appended
|
| + * @param startIndex the index of the first character representing the scalar value
|
| + * @param endIndex the index of the last character representing the scalar value
|
| + */
|
| + void _appendScalarValue(JavaStringBuilder builder, String escapeSequence, int scalarValue, int startIndex, int endIndex) {
|
| + if (scalarValue < 0 || scalarValue > Character.MAX_CODE_POINT || (scalarValue >= 0xD800 && scalarValue <= 0xDFFF)) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.INVALID_CODE_POINT, [escapeSequence]);
|
| + return;
|
| + }
|
| + if (scalarValue < Character.MAX_VALUE) {
|
| + builder.appendChar(scalarValue);
|
| + } else {
|
| + builder.append(Character.toChars(scalarValue));
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Compute the content of a string with the given literal representation.
|
| + *
|
| + * @param lexeme the literal representation of the string
|
| + * @param first `true` if this is the first token in a string literal
|
| + * @param last `true` if this is the last token in a string literal
|
| + * @return the actual value of the string
|
| + */
|
| + String _computeStringValue(String lexeme, bool first, bool last) {
|
| + bool isRaw = false;
|
| + int start = 0;
|
| + if (first) {
|
| + if (StringUtilities.startsWith4(lexeme, 0, 0x72, 0x22, 0x22, 0x22) || StringUtilities.startsWith4(lexeme, 0, 0x72, 0x27, 0x27, 0x27)) {
|
| + isRaw = true;
|
| + start += 4;
|
| + } else if (StringUtilities.startsWith2(lexeme, 0, 0x72, 0x22) || StringUtilities.startsWith2(lexeme, 0, 0x72, 0x27)) {
|
| + isRaw = true;
|
| + start += 2;
|
| + } else if (StringUtilities.startsWith3(lexeme, 0, 0x22, 0x22, 0x22) || StringUtilities.startsWith3(lexeme, 0, 0x27, 0x27, 0x27)) {
|
| + start += 3;
|
| + } else if (StringUtilities.startsWithChar(lexeme, 0x22) || StringUtilities.startsWithChar(lexeme, 0x27)) {
|
| + start += 1;
|
| + }
|
| + }
|
| + int end = lexeme.length;
|
| + if (last) {
|
| + if (StringUtilities.endsWith3(lexeme, 0x22, 0x22, 0x22) || StringUtilities.endsWith3(lexeme, 0x27, 0x27, 0x27)) {
|
| + end -= 3;
|
| + } else if (StringUtilities.endsWithChar(lexeme, 0x22) || StringUtilities.endsWithChar(lexeme, 0x27)) {
|
| + end -= 1;
|
| + }
|
| + }
|
| + if (end - start + 1 < 0) {
|
| + AnalysisEngine.instance.logger.logError("Internal error: computeStringValue(${lexeme}, ${first}, ${last})");
|
| + return "";
|
| + }
|
| + if (isRaw) {
|
| + return lexeme.substring(start, end);
|
| + }
|
| + JavaStringBuilder builder = new JavaStringBuilder();
|
| + int index = start;
|
| + while (index < end) {
|
| + index = _translateCharacter(builder, lexeme, index);
|
| + }
|
| + return builder.toString();
|
| + }
|
| +
|
| + /**
|
| + * Convert the given method declaration into the nearest valid top-level function declaration.
|
| + *
|
| + * @param method the method to be converted
|
| + * @return the function declaration that most closely captures the components of the given method
|
| + * declaration
|
| + */
|
| + FunctionDeclaration _convertToFunctionDeclaration(MethodDeclaration method) => new FunctionDeclaration(method.documentationComment, method.metadata, method.externalKeyword, method.returnType, method.propertyKeyword, method.name, new FunctionExpression(method.parameters, method.body));
|
| +
|
| + /**
|
| + * Return `true` if the current token could be the start of a compilation unit member. This
|
| + * method is used for recovery purposes to decide when to stop skipping tokens after finding an
|
| + * error while parsing a compilation unit member.
|
| + *
|
| + * @return `true` if the current token could be the start of a compilation unit member
|
| + */
|
| + bool _couldBeStartOfCompilationUnitMember() {
|
| + if ((_matchesKeyword(Keyword.IMPORT) || _matchesKeyword(Keyword.EXPORT) || _matchesKeyword(Keyword.LIBRARY) || _matchesKeyword(Keyword.PART)) && !_tokenMatches(_peek(), TokenType.PERIOD) && !_tokenMatches(_peek(), TokenType.LT)) {
|
| + // This looks like the start of a directive
|
| + return true;
|
| + } else if (_matchesKeyword(Keyword.CLASS)) {
|
| + // This looks like the start of a class definition
|
| + return true;
|
| + } else if (_matchesKeyword(Keyword.TYPEDEF) && !_tokenMatches(_peek(), TokenType.PERIOD) && !_tokenMatches(_peek(), TokenType.LT)) {
|
| + // This looks like the start of a typedef
|
| + return true;
|
| + } else if (_matchesKeyword(Keyword.VOID) || ((_matchesKeyword(Keyword.GET) || _matchesKeyword(Keyword.SET)) && _tokenMatchesIdentifier(_peek())) || (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek()))) {
|
| + // This looks like the start of a function
|
| + return true;
|
| + } else if (_matchesIdentifier()) {
|
| + if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
|
| + // This looks like the start of a function
|
| + return true;
|
| + }
|
| + Token token = _skipReturnType(_currentToken);
|
| + if (token == null) {
|
| + return false;
|
| + }
|
| + if (_matchesKeyword(Keyword.GET) || _matchesKeyword(Keyword.SET) || (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) || _matchesIdentifier()) {
|
| + return true;
|
| + }
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + /**
|
| + * Create a synthetic identifier.
|
| + *
|
| + * @return the synthetic identifier that was created
|
| + */
|
| + SimpleIdentifier _createSyntheticIdentifier() {
|
| + Token syntheticToken;
|
| + if (_currentToken.type == TokenType.KEYWORD) {
|
| + // Consider current keyword token as an identifier.
|
| + // It is not always true, e.g. "^is T" where "^" is place the place for synthetic identifier.
|
| + // By creating SyntheticStringToken we can distinguish a real identifier from synthetic.
|
| + // In the code completion behavior will depend on a cursor position - before or on "is".
|
| + syntheticToken = _injectToken(new SyntheticStringToken(TokenType.IDENTIFIER, _currentToken.lexeme, _currentToken.offset));
|
| + } else {
|
| + syntheticToken = _createSyntheticToken(TokenType.IDENTIFIER);
|
| + }
|
| + return new SimpleIdentifier(syntheticToken);
|
| + }
|
| +
|
| + /**
|
| + * Create a synthetic token representing the given keyword.
|
| + *
|
| + * @return the synthetic token that was created
|
| + */
|
| + Token _createSyntheticKeyword(Keyword keyword) => _injectToken(new Parser_SyntheticKeywordToken(keyword, _currentToken.offset));
|
| +
|
| + /**
|
| + * Create a synthetic string literal.
|
| + *
|
| + * @return the synthetic string literal that was created
|
| + */
|
| + SimpleStringLiteral _createSyntheticStringLiteral() => new SimpleStringLiteral(_createSyntheticToken(TokenType.STRING), "");
|
| +
|
| + /**
|
| + * Create a synthetic token with the given type.
|
| + *
|
| + * @return the synthetic token that was created
|
| + */
|
| + Token _createSyntheticToken(TokenType type) => _injectToken(new StringToken(type, "", _currentToken.offset));
|
| +
|
| + /**
|
| + * Check that the given expression is assignable and report an error if it isn't.
|
| + *
|
| + * <pre>
|
| + * assignableExpression ::=
|
| + * primary (arguments* assignableSelector)+
|
| + * | 'super' assignableSelector
|
| + * | identifier
|
| + *
|
| + * assignableSelector ::=
|
| + * '[' expression ']'
|
| + * | '.' identifier
|
| + * </pre>
|
| + *
|
| + * @param expression the expression being checked
|
| + */
|
| + void _ensureAssignable(Expression expression) {
|
| + if (expression != null && !expression.isAssignable) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE, []);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * If the current token has the expected type, return it after advancing to the next token.
|
| + * Otherwise report an error and return the current token without advancing. Note that the method
|
| + * [expectGt] should be used if the argument to this method would be [TokenType#GT]
|
| + * .
|
| + *
|
| + * @param type the type of token that is expected
|
| + * @return the token that matched the given type
|
| + */
|
| + Token _expect(TokenType type) {
|
| + if (_matches(type)) {
|
| + return andAdvance;
|
| + }
|
| + // Remove uses of this method in favor of matches?
|
| + // Pass in the error code to use to report the error?
|
| + if (type == TokenType.SEMICOLON) {
|
| + _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, [type.lexeme]);
|
| + } else {
|
| + _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TOKEN, [type.lexeme]);
|
| + }
|
| + return _currentToken;
|
| + }
|
| +
|
| + /**
|
| + * If the current token has the type [TokenType#GT], return it after advancing to the next
|
| + * token. Otherwise report an error and return the current token without advancing.
|
| + *
|
| + * @return the token that matched the given type
|
| + */
|
| + Token _expectGt() {
|
| + if (_matchesGt()) {
|
| + return andAdvance;
|
| + }
|
| + _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TOKEN, [TokenType.GT.lexeme]);
|
| + return _currentToken;
|
| + }
|
| +
|
| + /**
|
| + * If the current token is a keyword matching the given string, return it after advancing to the
|
| + * next token. Otherwise report an error and return the current token without advancing.
|
| + *
|
| + * @param keyword the keyword that is expected
|
| + * @return the token that matched the given type
|
| + */
|
| + Token _expectKeyword(Keyword keyword) {
|
| + if (_matchesKeyword(keyword)) {
|
| + return andAdvance;
|
| + }
|
| + // Remove uses of this method in favor of matches?
|
| + // Pass in the error code to use to report the error?
|
| + _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TOKEN, [keyword.syntax]);
|
| + return _currentToken;
|
| + }
|
| +
|
| + /**
|
| + * If [currentToken] is a semicolon, returns it; otherwise reports error and creates a
|
| + * synthetic one.
|
| + *
|
| + * TODO(scheglov) consider pushing this into [expect]
|
| + */
|
| + Token _expectSemicolon() {
|
| + if (_matches(TokenType.SEMICOLON)) {
|
| + return andAdvance;
|
| + } else {
|
| + _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, [";"]);
|
| + return _createSyntheticToken(TokenType.SEMICOLON);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Search the given list of ranges for a range that contains the given index. Return the range
|
| + * that was found, or `null` if none of the ranges contain the index.
|
| + *
|
| + * @param ranges the ranges to be searched
|
| + * @param index the index contained in the returned range
|
| + * @return the range that was found
|
| + */
|
| + List<int> _findRange(List<List<int>> ranges, int index) {
|
| + int rangeCount = ranges.length;
|
| + for (int i = 0; i < rangeCount; i++) {
|
| + List<int> range = ranges[i];
|
| + if (range[0] <= index && index <= range[1]) {
|
| + return range;
|
| + } else if (index < range[0]) {
|
| + return null;
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * Advance to the next token in the token stream, making it the new current token.
|
| + *
|
| + * @return the token that was current before this method was invoked
|
| + */
|
| + Token get andAdvance {
|
| + Token token = _currentToken;
|
| + _advance();
|
| + return token;
|
| + }
|
| +
|
| + /**
|
| + * Return a list of the ranges of characters in the given comment string that should be treated as
|
| + * code blocks.
|
| + *
|
| + * @param comment the comment being processed
|
| + * @return the ranges of characters that should be treated as code blocks
|
| + */
|
| + List<List<int>> _getCodeBlockRanges(String comment) {
|
| + List<List<int>> ranges = new List<List<int>>();
|
| + int length = comment.length;
|
| + if (length < 3) {
|
| + return ranges;
|
| + }
|
| + int index = 0;
|
| + int firstChar = comment.codeUnitAt(0);
|
| + if (firstChar == 0x2F) {
|
| + int secondChar = comment.codeUnitAt(1);
|
| + int thirdChar = comment.codeUnitAt(2);
|
| + if ((secondChar == 0x2A && thirdChar == 0x2A) || (secondChar == 0x2F && thirdChar == 0x2F)) {
|
| + index = 3;
|
| + }
|
| + }
|
| + while (index < length) {
|
| + int currentChar = comment.codeUnitAt(index);
|
| + if (currentChar == 0xD || currentChar == 0xA) {
|
| + index = index + 1;
|
| + while (index < length && Character.isWhitespace(comment.codeUnitAt(index))) {
|
| + index = index + 1;
|
| + }
|
| + if (StringUtilities.startsWith6(comment, index, 0x2A, 0x20, 0x20, 0x20, 0x20, 0x20)) {
|
| + int end = index + 6;
|
| + while (end < length && comment.codeUnitAt(end) != 0xD && comment.codeUnitAt(end) != 0xA) {
|
| + end = end + 1;
|
| + }
|
| + ranges.add(<int> [index, end]);
|
| + index = end;
|
| + }
|
| + } else if (index + 1 < length && currentChar == 0x5B && comment.codeUnitAt(index + 1) == 0x3A) {
|
| + int end = StringUtilities.indexOf2(comment, index + 2, 0x3A, 0x5D);
|
| + if (end < 0) {
|
| + end = length;
|
| + }
|
| + ranges.add(<int> [index, end]);
|
| + index = end + 1;
|
| + } else {
|
| + index = index + 1;
|
| + }
|
| + }
|
| + return ranges;
|
| + }
|
| +
|
| + /**
|
| + * Return the end token associated with the given begin token, or `null` if either the given
|
| + * token is not a begin token or it does not have an end token associated with it.
|
| + *
|
| + * @param beginToken the token that is expected to have an end token associated with it
|
| + * @return the end token associated with the begin token
|
| + */
|
| + Token _getEndToken(Token beginToken) {
|
| + if (beginToken is BeginToken) {
|
| + return beginToken.endToken;
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * Return `true` if the current token is the first token of a return type that is followed
|
| + * by an identifier, possibly followed by a list of type parameters, followed by a
|
| + * left-parenthesis. This is used by parseTypeAlias to determine whether or not to parse a return
|
| + * type.
|
| + *
|
| + * @return `true` if we can successfully parse the rest of a type alias if we first parse a
|
| + * return type.
|
| + */
|
| + bool get hasReturnTypeInTypeAlias {
|
| + Token next = _skipReturnType(_currentToken);
|
| + if (next == null) {
|
| + return false;
|
| + }
|
| + return _tokenMatchesIdentifier(next);
|
| + }
|
| +
|
| + /**
|
| + * Inject the given token into the token stream immediately before the current token.
|
| + *
|
| + * @param token the token to be added to the token stream
|
| + * @return the token that was just added to the token stream
|
| + */
|
| + Token _injectToken(Token token) {
|
| + Token previous = _currentToken.previous;
|
| + token.setNext(_currentToken);
|
| + previous.setNext(token);
|
| + return token;
|
| + }
|
| +
|
| + /**
|
| + * Return `true` if the current token appears to be the beginning of a function declaration.
|
| + *
|
| + * @return `true` if the current token appears to be the beginning of a function declaration
|
| + */
|
| + bool _isFunctionDeclaration() {
|
| + if (_matchesKeyword(Keyword.VOID)) {
|
| + return true;
|
| + }
|
| + Token afterReturnType = _skipTypeName(_currentToken);
|
| + if (afterReturnType == null) {
|
| + // There was no return type, but it is optional, so go back to where we started.
|
| + afterReturnType = _currentToken;
|
| + }
|
| + Token afterIdentifier = _skipSimpleIdentifier(afterReturnType);
|
| + if (afterIdentifier == null) {
|
| + // It's possible that we parsed the function name as if it were a type name, so see whether
|
| + // it makes sense if we assume that there is no type.
|
| + afterIdentifier = _skipSimpleIdentifier(_currentToken);
|
| + }
|
| + if (afterIdentifier == null) {
|
| + return false;
|
| + }
|
| + if (_isFunctionExpression(afterIdentifier)) {
|
| + return true;
|
| + }
|
| + // It's possible that we have found a getter. While this isn't valid at this point we test for
|
| + // it in order to recover better.
|
| + if (_matchesKeyword(Keyword.GET)) {
|
| + Token afterName = _skipSimpleIdentifier(_currentToken.next);
|
| + if (afterName == null) {
|
| + return false;
|
| + }
|
| + return _tokenMatches(afterName, TokenType.FUNCTION) || _tokenMatches(afterName, TokenType.OPEN_CURLY_BRACKET);
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + /**
|
| + * Return `true` if the given token appears to be the beginning of a function expression.
|
| + *
|
| + * @param startToken the token that might be the start of a function expression
|
| + * @return `true` if the given token appears to be the beginning of a function expression
|
| + */
|
| + bool _isFunctionExpression(Token startToken) {
|
| + // Function expressions aren't allowed in initializer lists.
|
| + if (_inInitializer) {
|
| + return false;
|
| + }
|
| + Token afterParameters = _skipFormalParameterList(startToken);
|
| + if (afterParameters == null) {
|
| + return false;
|
| + }
|
| + if (afterParameters.matchesAny([TokenType.OPEN_CURLY_BRACKET, TokenType.FUNCTION])) {
|
| + return true;
|
| + }
|
| + if (_parseAsync) {
|
| + String lexeme = afterParameters.lexeme;
|
| + return lexeme == ASYNC || lexeme == SYNC;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + /**
|
| + * Return `true` if the given character is a valid hexadecimal digit.
|
| + *
|
| + * @param character the character being tested
|
| + * @return `true` if the character is a valid hexadecimal digit
|
| + */
|
| + bool _isHexDigit(int character) => (0x30 <= character && character <= 0x39) || (0x41 <= character && character <= 0x46) || (0x61 <= character && character <= 0x66);
|
| +
|
| + /**
|
| + * Return `true` if the current token is the first token in an initialized variable
|
| + * declaration rather than an expression. This method assumes that we have already skipped past
|
| + * any metadata that might be associated with the declaration.
|
| + *
|
| + * <pre>
|
| + * initializedVariableDeclaration ::=
|
| + * declaredIdentifier ('=' expression)? (',' initializedIdentifier)*
|
| + *
|
| + * declaredIdentifier ::=
|
| + * metadata finalConstVarOrType identifier
|
| + *
|
| + * finalConstVarOrType ::=
|
| + * 'final' type?
|
| + * | 'const' type?
|
| + * | 'var'
|
| + * | type
|
| + *
|
| + * type ::=
|
| + * qualified typeArguments?
|
| + *
|
| + * initializedIdentifier ::=
|
| + * identifier ('=' expression)?
|
| + * </pre>
|
| + *
|
| + * @return `true` if the current token is the first token in an initialized variable
|
| + * declaration
|
| + */
|
| + bool _isInitializedVariableDeclaration() {
|
| + if (_matchesKeyword(Keyword.FINAL) || _matchesKeyword(Keyword.VAR)) {
|
| + // An expression cannot start with a keyword other than 'const', 'rethrow', or 'throw'.
|
| + return true;
|
| + }
|
| + if (_matchesKeyword(Keyword.CONST)) {
|
| + // Look to see whether we might be at the start of a list or map literal, otherwise this
|
| + // should be the start of a variable declaration.
|
| + return !_peek().matchesAny([
|
| + TokenType.LT,
|
| + TokenType.OPEN_CURLY_BRACKET,
|
| + TokenType.OPEN_SQUARE_BRACKET,
|
| + TokenType.INDEX]);
|
| + }
|
| + // We know that we have an identifier, and need to see whether it might be a type name.
|
| + Token token = _skipTypeName(_currentToken);
|
| + if (token == null) {
|
| + // There was no type name, so this can't be a declaration.
|
| + return false;
|
| + }
|
| + token = _skipSimpleIdentifier(token);
|
| + if (token == null) {
|
| + return false;
|
| + }
|
| + TokenType type = token.type;
|
| + return type == TokenType.EQ || type == TokenType.COMMA || type == TokenType.SEMICOLON || _tokenMatchesKeyword(token, Keyword.IN);
|
| + }
|
| +
|
| + /**
|
| + * Given that we have just found bracketed text within a comment, look to see whether that text is
|
| + * (a) followed by a parenthesized link address, (b) followed by a colon, or (c) followed by
|
| + * optional whitespace and another square bracket.
|
| + *
|
| + * This method uses the syntax described by the <a
|
| + * href="http://daringfireball.net/projects/markdown/syntax">markdown</a> project.
|
| + *
|
| + * @param comment the comment text in which the bracketed text was found
|
| + * @param rightIndex the index of the right bracket
|
| + * @return `true` if the bracketed text is followed by a link address
|
| + */
|
| + bool _isLinkText(String comment, int rightIndex) {
|
| + int length = comment.length;
|
| + int index = rightIndex + 1;
|
| + if (index >= length) {
|
| + return false;
|
| + }
|
| + int nextChar = comment.codeUnitAt(index);
|
| + if (nextChar == 0x28 || nextChar == 0x3A) {
|
| + return true;
|
| + }
|
| + while (Character.isWhitespace(nextChar)) {
|
| + index = index + 1;
|
| + if (index >= length) {
|
| + return false;
|
| + }
|
| + nextChar = comment.codeUnitAt(index);
|
| + }
|
| + return nextChar == 0x5B;
|
| + }
|
| +
|
| + /**
|
| + * Return `true` if the given token appears to be the beginning of an operator declaration.
|
| + *
|
| + * @param startToken the token that might be the start of an operator declaration
|
| + * @return `true` if the given token appears to be the beginning of an operator declaration
|
| + */
|
| + bool _isOperator(Token startToken) {
|
| + // Accept any operator here, even if it is not user definable.
|
| + if (!startToken.isOperator) {
|
| + return false;
|
| + }
|
| + // Token "=" means that it is actually field initializer.
|
| + if (startToken.type == TokenType.EQ) {
|
| + return false;
|
| + }
|
| + // Consume all operator tokens.
|
| + Token token = startToken.next;
|
| + while (token.isOperator) {
|
| + token = token.next;
|
| + }
|
| + // Formal parameter list is expect now.
|
| + return _tokenMatches(token, TokenType.OPEN_PAREN);
|
| + }
|
| +
|
| + /**
|
| + * Return `true` if the current token appears to be the beginning of a switch member.
|
| + *
|
| + * @return `true` if the current token appears to be the beginning of a switch member
|
| + */
|
| + bool _isSwitchMember() {
|
| + Token token = _currentToken;
|
| + while (_tokenMatches(token, TokenType.IDENTIFIER) && _tokenMatches(token.next, TokenType.COLON)) {
|
| + token = token.next.next;
|
| + }
|
| + if (token.type == TokenType.KEYWORD) {
|
| + Keyword keyword = (token as KeywordToken).keyword;
|
| + return keyword == Keyword.CASE || keyword == Keyword.DEFAULT;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + /**
|
| + * Return `true` if the given token appears to be the first token of a type name that is
|
| + * followed by a variable or field formal parameter.
|
| + *
|
| + * @param startToken the first token of the sequence being checked
|
| + * @return `true` if there is a type name and variable starting at the given token
|
| + */
|
| + bool _isTypedIdentifier(Token startToken) {
|
| + Token token = _skipReturnType(startToken);
|
| + if (token == null) {
|
| + return false;
|
| + } else if (_tokenMatchesIdentifier(token)) {
|
| + return true;
|
| + } else if (_tokenMatchesKeyword(token, Keyword.THIS) && _tokenMatches(token.next, TokenType.PERIOD) && _tokenMatchesIdentifier(token.next.next)) {
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + /**
|
| + * Compare the given tokens to find the token that appears first in the source being parsed. That
|
| + * is, return the left-most of all of the tokens. The arguments are allowed to be `null`.
|
| + * Return the token with the smallest offset, or `null` if there are no arguments or if all
|
| + * of the arguments are `null`.
|
| + *
|
| + * @param tokens the tokens being compared
|
| + * @return the token with the smallest offset
|
| + */
|
| + Token _lexicallyFirst(List<Token> tokens) {
|
| + Token first = null;
|
| + int firstOffset = 2147483647;
|
| + for (Token token in tokens) {
|
| + if (token != null) {
|
| + int offset = token.offset;
|
| + if (offset < firstOffset) {
|
| + first = token;
|
| + firstOffset = offset;
|
| + }
|
| + }
|
| + }
|
| + return first;
|
| + }
|
| +
|
| + /**
|
| + * Increments the error reporting lock level. If level is more than `0`, then
|
| + * [reportError] wont report any error.
|
| + */
|
| + void _lockErrorListener() {
|
| + _errorListenerLock++;
|
| + }
|
| +
|
| + /**
|
| + * Return `true` if the current token has the given type. Note that the method
|
| + * [matchesGt] should be used if the argument to this method would be
|
| + * [TokenType#GT].
|
| + *
|
| + * @param type the type of token that can optionally appear in the current location
|
| + * @return `true` if the current token has the given type
|
| + */
|
| + bool _matches(TokenType type) => _currentToken.type == type;
|
| +
|
| + /**
|
| + * Return `true` if the current token has a type of [TokenType#GT]. Note that this
|
| + * method, unlike other variants, will modify the token stream if possible to match desired type.
|
| + * In particular, if the next token is either a '>>' or '>>>', the token stream will be re-written
|
| + * and `true` will be returned.
|
| + *
|
| + * @return `true` if the current token has a type of [TokenType#GT]
|
| + */
|
| + bool _matchesGt() {
|
| + TokenType currentType = _currentToken.type;
|
| + if (currentType == TokenType.GT) {
|
| + return true;
|
| + } else if (currentType == TokenType.GT_GT) {
|
| + int offset = _currentToken.offset;
|
| + Token first = new Token(TokenType.GT, offset);
|
| + Token second = new Token(TokenType.GT, offset + 1);
|
| + second.setNext(_currentToken.next);
|
| + first.setNext(second);
|
| + _currentToken.previous.setNext(first);
|
| + _currentToken = first;
|
| + return true;
|
| + } else if (currentType == TokenType.GT_EQ) {
|
| + int offset = _currentToken.offset;
|
| + Token first = new Token(TokenType.GT, offset);
|
| + Token second = new Token(TokenType.EQ, offset + 1);
|
| + second.setNext(_currentToken.next);
|
| + first.setNext(second);
|
| + _currentToken.previous.setNext(first);
|
| + _currentToken = first;
|
| + return true;
|
| + } else if (currentType == TokenType.GT_GT_EQ) {
|
| + int offset = _currentToken.offset;
|
| + Token first = new Token(TokenType.GT, offset);
|
| + Token second = new Token(TokenType.GT, offset + 1);
|
| + Token third = new Token(TokenType.EQ, offset + 2);
|
| + third.setNext(_currentToken.next);
|
| + second.setNext(third);
|
| + first.setNext(second);
|
| + _currentToken.previous.setNext(first);
|
| + _currentToken = first;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + /**
|
| + * Return `true` if the current token is a valid identifier. Valid identifiers include
|
| + * built-in identifiers (pseudo-keywords).
|
| + *
|
| + * @return `true` if the current token is a valid identifier
|
| + */
|
| + bool _matchesIdentifier() => _tokenMatchesIdentifier(_currentToken);
|
| +
|
| + /**
|
| + * Return `true` if the current token matches the given keyword.
|
| + *
|
| + * @param keyword the keyword that can optionally appear in the current location
|
| + * @return `true` if the current token matches the given keyword
|
| + */
|
| + bool _matchesKeyword(Keyword keyword) => _tokenMatchesKeyword(_currentToken, keyword);
|
| +
|
| + /**
|
| + * Return `true` if the current token matches the given identifier.
|
| + *
|
| + * @param identifier the identifier that can optionally appear in the current location
|
| + * @return `true` if the current token matches the given identifier
|
| + */
|
| + bool _matchesString(String identifier) => _currentToken.type == TokenType.IDENTIFIER && _currentToken.lexeme == identifier;
|
| +
|
| + /**
|
| + * If the current token has the given type, then advance to the next token and return `true`
|
| + * . Otherwise, return `false` without advancing. This method should not be invoked with an
|
| + * argument value of [TokenType#GT].
|
| + *
|
| + * @param type the type of token that can optionally appear in the current location
|
| + * @return `true` if the current token has the given type
|
| + */
|
| + bool _optional(TokenType type) {
|
| + if (_matches(type)) {
|
| + _advance();
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + /**
|
| + * Parse an additive expression.
|
| + *
|
| + * <pre>
|
| + * additiveExpression ::=
|
| + * multiplicativeExpression (additiveOperator multiplicativeExpression)*
|
| + * | 'super' (additiveOperator multiplicativeExpression)+
|
| + * </pre>
|
| + *
|
| + * @return the additive expression that was parsed
|
| + */
|
| + Expression _parseAdditiveExpression() {
|
| + Expression expression;
|
| + if (_matchesKeyword(Keyword.SUPER) && _currentToken.next.type.isAdditiveOperator) {
|
| + expression = new SuperExpression(andAdvance);
|
| + } else {
|
| + expression = _parseMultiplicativeExpression();
|
| + }
|
| + while (_currentToken.type.isAdditiveOperator) {
|
| + Token operator = andAdvance;
|
| + expression = new BinaryExpression(expression, operator, _parseMultiplicativeExpression());
|
| + }
|
| + return expression;
|
| + }
|
| +
|
| + /**
|
| + * Parse an assert statement.
|
| + *
|
| + * <pre>
|
| + * assertStatement ::=
|
| + * 'assert' '(' conditionalExpression ')' ';'
|
| + * </pre>
|
| + *
|
| + * @return the assert statement
|
| + */
|
| + AssertStatement _parseAssertStatement() {
|
| + Token keyword = _expectKeyword(Keyword.ASSERT);
|
| + Token leftParen = _expect(TokenType.OPEN_PAREN);
|
| + Expression expression = parseExpression2();
|
| + if (expression is AssignmentExpression) {
|
| + _reportErrorForNode(ParserErrorCode.ASSERT_DOES_NOT_TAKE_ASSIGNMENT, expression, []);
|
| + } else if (expression is CascadeExpression) {
|
| + _reportErrorForNode(ParserErrorCode.ASSERT_DOES_NOT_TAKE_CASCADE, expression, []);
|
| + } else if (expression is ThrowExpression) {
|
| + _reportErrorForNode(ParserErrorCode.ASSERT_DOES_NOT_TAKE_THROW, expression, []);
|
| + } else if (expression is RethrowExpression) {
|
| + _reportErrorForNode(ParserErrorCode.ASSERT_DOES_NOT_TAKE_RETHROW, expression, []);
|
| + }
|
| + Token rightParen = _expect(TokenType.CLOSE_PAREN);
|
| + Token semicolon = _expect(TokenType.SEMICOLON);
|
| + return new AssertStatement(keyword, leftParen, expression, rightParen, semicolon);
|
| + }
|
| +
|
| + /**
|
| + * Parse an assignable expression.
|
| + *
|
| + * <pre>
|
| + * assignableExpression ::=
|
| + * primary (arguments* assignableSelector)+
|
| + * | 'super' assignableSelector
|
| + * | identifier
|
| + * </pre>
|
| + *
|
| + * @param primaryAllowed `true` if the expression is allowed to be a primary without any
|
| + * assignable selector
|
| + * @return the assignable expression that was parsed
|
| + */
|
| + Expression _parseAssignableExpression(bool primaryAllowed) {
|
| + if (_matchesKeyword(Keyword.SUPER)) {
|
| + return _parseAssignableSelector(new SuperExpression(andAdvance), false);
|
| + }
|
| + //
|
| + // A primary expression can start with an identifier. We resolve the ambiguity by determining
|
| + // whether the primary consists of anything other than an identifier and/or is followed by an
|
| + // assignableSelector.
|
| + //
|
| + Expression expression = _parsePrimaryExpression();
|
| + bool isOptional = primaryAllowed || expression is SimpleIdentifier;
|
| + while (true) {
|
| + while (_matches(TokenType.OPEN_PAREN)) {
|
| + ArgumentList argumentList = parseArgumentList();
|
| + if (expression is SimpleIdentifier) {
|
| + expression = new MethodInvocation(null, null, expression as SimpleIdentifier, argumentList);
|
| + } else if (expression is PrefixedIdentifier) {
|
| + PrefixedIdentifier identifier = expression as PrefixedIdentifier;
|
| + expression = new MethodInvocation(identifier.prefix, identifier.period, identifier.identifier, argumentList);
|
| + } else if (expression is PropertyAccess) {
|
| + PropertyAccess access = expression as PropertyAccess;
|
| + expression = new MethodInvocation(access.target, access.operator, access.propertyName, argumentList);
|
| + } else {
|
| + expression = new FunctionExpressionInvocation(expression, argumentList);
|
| + }
|
| + if (!primaryAllowed) {
|
| + isOptional = false;
|
| + }
|
| + }
|
| + Expression selectorExpression = _parseAssignableSelector(expression, isOptional || (expression is PrefixedIdentifier));
|
| + if (identical(selectorExpression, expression)) {
|
| + if (!isOptional && (expression is PrefixedIdentifier)) {
|
| + PrefixedIdentifier identifier = expression as PrefixedIdentifier;
|
| + expression = new PropertyAccess(identifier.prefix, identifier.period, identifier.identifier);
|
| + }
|
| + return expression;
|
| + }
|
| + expression = selectorExpression;
|
| + isOptional = true;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse an assignable selector.
|
| + *
|
| + * <pre>
|
| + * assignableSelector ::=
|
| + * '[' expression ']'
|
| + * | '.' identifier
|
| + * </pre>
|
| + *
|
| + * @param prefix the expression preceding the selector
|
| + * @param optional `true` if the selector is optional
|
| + * @return the assignable selector that was parsed, or the original prefix if there was no
|
| + * assignable selector
|
| + */
|
| + Expression _parseAssignableSelector(Expression prefix, bool optional) {
|
| + if (_matches(TokenType.OPEN_SQUARE_BRACKET)) {
|
| + Token leftBracket = andAdvance;
|
| + bool wasInInitializer = _inInitializer;
|
| + _inInitializer = false;
|
| + try {
|
| + Expression index = parseExpression2();
|
| + Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET);
|
| + return new IndexExpression.forTarget(prefix, leftBracket, index, rightBracket);
|
| + } finally {
|
| + _inInitializer = wasInInitializer;
|
| + }
|
| + } else if (_matches(TokenType.PERIOD)) {
|
| + Token period = andAdvance;
|
| + return new PropertyAccess(prefix, period, parseSimpleIdentifier());
|
| + } else {
|
| + if (!optional) {
|
| + // Report the missing selector.
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_ASSIGNABLE_SELECTOR, []);
|
| + }
|
| + return prefix;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse a await expression.
|
| + *
|
| + * <pre>
|
| + * awaitExpression ::=
|
| + * 'await' unaryExpression
|
| + * </pre>
|
| + *
|
| + * @return the await expression that was parsed
|
| + */
|
| + AwaitExpression _parseAwaitExpression() {
|
| + Token awaitToken = andAdvance;
|
| + Expression expression = _parseUnaryExpression();
|
| + return new AwaitExpression(awaitToken, expression);
|
| + }
|
| +
|
| + /**
|
| + * Parse a bitwise and expression.
|
| + *
|
| + * <pre>
|
| + * bitwiseAndExpression ::=
|
| + * shiftExpression ('&' shiftExpression)*
|
| + * | 'super' ('&' shiftExpression)+
|
| + * </pre>
|
| + *
|
| + * @return the bitwise and expression that was parsed
|
| + */
|
| + Expression _parseBitwiseAndExpression() {
|
| + Expression expression;
|
| + if (_matchesKeyword(Keyword.SUPER) && _tokenMatches(_peek(), TokenType.AMPERSAND)) {
|
| + expression = new SuperExpression(andAdvance);
|
| + } else {
|
| + expression = _parseShiftExpression();
|
| + }
|
| + while (_matches(TokenType.AMPERSAND)) {
|
| + Token operator = andAdvance;
|
| + expression = new BinaryExpression(expression, operator, _parseShiftExpression());
|
| + }
|
| + return expression;
|
| + }
|
| +
|
| + /**
|
| + * Parse a bitwise exclusive-or expression.
|
| + *
|
| + * <pre>
|
| + * bitwiseXorExpression ::=
|
| + * bitwiseAndExpression ('^' bitwiseAndExpression)*
|
| + * | 'super' ('^' bitwiseAndExpression)+
|
| + * </pre>
|
| + *
|
| + * @return the bitwise exclusive-or expression that was parsed
|
| + */
|
| + Expression _parseBitwiseXorExpression() {
|
| + Expression expression;
|
| + if (_matchesKeyword(Keyword.SUPER) && _tokenMatches(_peek(), TokenType.CARET)) {
|
| + expression = new SuperExpression(andAdvance);
|
| + } else {
|
| + expression = _parseBitwiseAndExpression();
|
| + }
|
| + while (_matches(TokenType.CARET)) {
|
| + Token operator = andAdvance;
|
| + expression = new BinaryExpression(expression, operator, _parseBitwiseAndExpression());
|
| + }
|
| + return expression;
|
| + }
|
| +
|
| + /**
|
| + * Parse a break statement.
|
| + *
|
| + * <pre>
|
| + * breakStatement ::=
|
| + * 'break' identifier? ';'
|
| + * </pre>
|
| + *
|
| + * @return the break statement that was parsed
|
| + */
|
| + Statement _parseBreakStatement() {
|
| + Token breakKeyword = _expectKeyword(Keyword.BREAK);
|
| + SimpleIdentifier label = null;
|
| + if (_matchesIdentifier()) {
|
| + label = parseSimpleIdentifier();
|
| + }
|
| + if (!_inLoop && !_inSwitch && label == null) {
|
| + _reportErrorForToken(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP, breakKeyword, []);
|
| + }
|
| + Token semicolon = _expect(TokenType.SEMICOLON);
|
| + return new BreakStatement(breakKeyword, label, semicolon);
|
| + }
|
| +
|
| + /**
|
| + * Parse a cascade section.
|
| + *
|
| + * <pre>
|
| + * cascadeSection ::=
|
| + * '..' (cascadeSelector arguments*) (assignableSelector arguments*)* cascadeAssignment?
|
| + *
|
| + * cascadeSelector ::=
|
| + * '[' expression ']'
|
| + * | identifier
|
| + *
|
| + * cascadeAssignment ::=
|
| + * assignmentOperator expressionWithoutCascade
|
| + * </pre>
|
| + *
|
| + * @return the expression representing the cascaded method invocation
|
| + */
|
| + Expression _parseCascadeSection() {
|
| + Token period = _expect(TokenType.PERIOD_PERIOD);
|
| + Expression expression = null;
|
| + SimpleIdentifier functionName = null;
|
| + if (_matchesIdentifier()) {
|
| + functionName = parseSimpleIdentifier();
|
| + } else if (_currentToken.type == TokenType.OPEN_SQUARE_BRACKET) {
|
| + Token leftBracket = andAdvance;
|
| + bool wasInInitializer = _inInitializer;
|
| + _inInitializer = false;
|
| + try {
|
| + Expression index = parseExpression2();
|
| + Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET);
|
| + expression = new IndexExpression.forCascade(period, leftBracket, index, rightBracket);
|
| + period = null;
|
| + } finally {
|
| + _inInitializer = wasInInitializer;
|
| + }
|
| + } else {
|
| + _reportErrorForToken(ParserErrorCode.MISSING_IDENTIFIER, _currentToken, [_currentToken.lexeme]);
|
| + functionName = _createSyntheticIdentifier();
|
| + }
|
| + assert((expression == null && functionName != null) || (expression != null && functionName == null));
|
| + if (_currentToken.type == TokenType.OPEN_PAREN) {
|
| + while (_currentToken.type == TokenType.OPEN_PAREN) {
|
| + if (functionName != null) {
|
| + expression = new MethodInvocation(expression, period, functionName, parseArgumentList());
|
| + period = null;
|
| + functionName = null;
|
| + } else if (expression == null) {
|
| + // It should not be possible to get here.
|
| + expression = new MethodInvocation(expression, period, _createSyntheticIdentifier(), parseArgumentList());
|
| + } else {
|
| + expression = new FunctionExpressionInvocation(expression, parseArgumentList());
|
| + }
|
| + }
|
| + } else if (functionName != null) {
|
| + expression = new PropertyAccess(expression, period, functionName);
|
| + period = null;
|
| + }
|
| + assert(expression != null);
|
| + bool progress = true;
|
| + while (progress) {
|
| + progress = false;
|
| + Expression selector = _parseAssignableSelector(expression, true);
|
| + if (!identical(selector, expression)) {
|
| + expression = selector;
|
| + progress = true;
|
| + while (_currentToken.type == TokenType.OPEN_PAREN) {
|
| + if (expression is PropertyAccess) {
|
| + PropertyAccess propertyAccess = expression as PropertyAccess;
|
| + expression = new MethodInvocation(propertyAccess.target, propertyAccess.operator, propertyAccess.propertyName, parseArgumentList());
|
| + } else {
|
| + expression = new FunctionExpressionInvocation(expression, parseArgumentList());
|
| + }
|
| + }
|
| + }
|
| + }
|
| + if (_currentToken.type.isAssignmentOperator) {
|
| + Token operator = andAdvance;
|
| + _ensureAssignable(expression);
|
| + expression = new AssignmentExpression(expression, operator, parseExpressionWithoutCascade());
|
| + }
|
| + return expression;
|
| + }
|
| +
|
| + /**
|
| + * Parse a class declaration.
|
| + *
|
| + * <pre>
|
| + * classDeclaration ::=
|
| + * metadata 'abstract'? 'class' name typeParameterList? (extendsClause withClause?)? implementsClause? '{' classMembers '}' |
|
| + * metadata 'abstract'? 'class' mixinApplicationClass
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the metadata to be associated with the member
|
| + * @param abstractKeyword the token for the keyword 'abstract', or `null` if the keyword was
|
| + * not given
|
| + * @return the class declaration that was parsed
|
| + */
|
| + CompilationUnitMember _parseClassDeclaration(CommentAndMetadata commentAndMetadata, Token abstractKeyword) {
|
| + Token keyword = _expectKeyword(Keyword.CLASS);
|
| + if (_matchesIdentifier()) {
|
| + Token next = _peek();
|
| + if (_tokenMatches(next, TokenType.LT)) {
|
| + next = _skipTypeParameterList(next);
|
| + if (next != null && _tokenMatches(next, TokenType.EQ)) {
|
| + return _parseClassTypeAlias(commentAndMetadata, abstractKeyword, keyword);
|
| + }
|
| + } else if (_tokenMatches(next, TokenType.EQ)) {
|
| + return _parseClassTypeAlias(commentAndMetadata, abstractKeyword, keyword);
|
| + }
|
| + }
|
| + SimpleIdentifier name = parseSimpleIdentifier();
|
| + String className = name.name;
|
| + TypeParameterList typeParameters = null;
|
| + if (_matches(TokenType.LT)) {
|
| + typeParameters = parseTypeParameterList();
|
| + }
|
| + //
|
| + // Parse the clauses. The parser accepts clauses in any order, but will generate errors if they
|
| + // are not in the order required by the specification.
|
| + //
|
| + ExtendsClause extendsClause = null;
|
| + WithClause withClause = null;
|
| + ImplementsClause implementsClause = null;
|
| + bool foundClause = true;
|
| + while (foundClause) {
|
| + if (_matchesKeyword(Keyword.EXTENDS)) {
|
| + if (extendsClause == null) {
|
| + extendsClause = parseExtendsClause();
|
| + if (withClause != null) {
|
| + _reportErrorForToken(ParserErrorCode.WITH_BEFORE_EXTENDS, withClause.withKeyword, []);
|
| + } else if (implementsClause != null) {
|
| + _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_EXTENDS, implementsClause.keyword, []);
|
| + }
|
| + } else {
|
| + _reportErrorForToken(ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES, extendsClause.keyword, []);
|
| + parseExtendsClause();
|
| + }
|
| + } else if (_matchesKeyword(Keyword.WITH)) {
|
| + if (withClause == null) {
|
| + withClause = parseWithClause();
|
| + if (implementsClause != null) {
|
| + _reportErrorForToken(ParserErrorCode.IMPLEMENTS_BEFORE_WITH, implementsClause.keyword, []);
|
| + }
|
| + } else {
|
| + _reportErrorForToken(ParserErrorCode.MULTIPLE_WITH_CLAUSES, withClause.withKeyword, []);
|
| + parseWithClause();
|
| + }
|
| + } else if (_matchesKeyword(Keyword.IMPLEMENTS)) {
|
| + if (implementsClause == null) {
|
| + implementsClause = parseImplementsClause();
|
| + } else {
|
| + _reportErrorForToken(ParserErrorCode.MULTIPLE_IMPLEMENTS_CLAUSES, implementsClause.keyword, []);
|
| + parseImplementsClause();
|
| + }
|
| + } else {
|
| + foundClause = false;
|
| + }
|
| + }
|
| + if (withClause != null && extendsClause == null) {
|
| + _reportErrorForToken(ParserErrorCode.WITH_WITHOUT_EXTENDS, withClause.withKeyword, []);
|
| + }
|
| + //
|
| + // Look for and skip over the extra-lingual 'native' specification.
|
| + //
|
| + NativeClause nativeClause = null;
|
| + if (_matchesString(_NATIVE) && _tokenMatches(_peek(), TokenType.STRING)) {
|
| + nativeClause = _parseNativeClause();
|
| + }
|
| + //
|
| + // Parse the body of the class.
|
| + //
|
| + Token leftBracket = null;
|
| + List<ClassMember> members = null;
|
| + Token rightBracket = null;
|
| + if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
|
| + leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET);
|
| + members = _parseClassMembers(className, _getEndToken(leftBracket));
|
| + rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
|
| + } else {
|
| + leftBracket = _createSyntheticToken(TokenType.OPEN_CURLY_BRACKET);
|
| + rightBracket = _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET);
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_CLASS_BODY, []);
|
| + }
|
| + ClassDeclaration classDeclaration = new ClassDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, abstractKeyword, keyword, name, typeParameters, extendsClause, withClause, implementsClause, leftBracket, members, rightBracket);
|
| + classDeclaration.nativeClause = nativeClause;
|
| + return classDeclaration;
|
| + }
|
| +
|
| + /**
|
| + * Parse a list of class members.
|
| + *
|
| + * <pre>
|
| + * classMembers ::=
|
| + * (metadata memberDefinition)*
|
| + * </pre>
|
| + *
|
| + * @param className the name of the class whose members are being parsed
|
| + * @param closingBracket the closing bracket for the class, or `null` if the closing bracket
|
| + * is missing
|
| + * @return the list of class members that were parsed
|
| + */
|
| + List<ClassMember> _parseClassMembers(String className, Token closingBracket) {
|
| + List<ClassMember> members = new List<ClassMember>();
|
| + Token memberStart = _currentToken;
|
| + while (!_matches(TokenType.EOF) && !_matches(TokenType.CLOSE_CURLY_BRACKET) && (closingBracket != null || (!_matchesKeyword(Keyword.CLASS) && !_matchesKeyword(Keyword.TYPEDEF)))) {
|
| + if (_matches(TokenType.SEMICOLON)) {
|
| + _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
|
| + _advance();
|
| + } else {
|
| + ClassMember member = parseClassMember(className);
|
| + if (member != null) {
|
| + members.add(member);
|
| + }
|
| + }
|
| + if (identical(_currentToken, memberStart)) {
|
| + _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
|
| + _advance();
|
| + }
|
| + memberStart = _currentToken;
|
| + }
|
| + return members;
|
| + }
|
| +
|
| + /**
|
| + * Parse a class type alias.
|
| + *
|
| + * <pre>
|
| + * classTypeAlias ::=
|
| + * identifier typeParameters? '=' 'abstract'? mixinApplication
|
| + *
|
| + * mixinApplication ::=
|
| + * type withClause implementsClause? ';'
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the metadata to be associated with the member
|
| + * @param abstractKeyword the token representing the 'abstract' keyword
|
| + * @param classKeyword the token representing the 'class' keyword
|
| + * @return the class type alias that was parsed
|
| + */
|
| + ClassTypeAlias _parseClassTypeAlias(CommentAndMetadata commentAndMetadata, Token abstractKeyword, Token classKeyword) {
|
| + SimpleIdentifier className = parseSimpleIdentifier();
|
| + TypeParameterList typeParameters = null;
|
| + if (_matches(TokenType.LT)) {
|
| + typeParameters = parseTypeParameterList();
|
| + }
|
| + Token equals = _expect(TokenType.EQ);
|
| + TypeName superclass = parseTypeName();
|
| + WithClause withClause = null;
|
| + if (_matchesKeyword(Keyword.WITH)) {
|
| + withClause = parseWithClause();
|
| + } else {
|
| + _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TOKEN, [Keyword.WITH.syntax]);
|
| + }
|
| + ImplementsClause implementsClause = null;
|
| + if (_matchesKeyword(Keyword.IMPLEMENTS)) {
|
| + implementsClause = parseImplementsClause();
|
| + }
|
| + Token semicolon;
|
| + if (_matches(TokenType.SEMICOLON)) {
|
| + semicolon = andAdvance;
|
| + } else {
|
| + if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_TOKEN, [TokenType.SEMICOLON.lexeme]);
|
| + Token leftBracket = andAdvance;
|
| + _parseClassMembers(className.name, _getEndToken(leftBracket));
|
| + _expect(TokenType.CLOSE_CURLY_BRACKET);
|
| + } else {
|
| + _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, [TokenType.SEMICOLON.lexeme]);
|
| + }
|
| + semicolon = _createSyntheticToken(TokenType.SEMICOLON);
|
| + }
|
| + return new ClassTypeAlias(commentAndMetadata.comment, commentAndMetadata.metadata, classKeyword, className, typeParameters, equals, abstractKeyword, superclass, withClause, implementsClause, semicolon);
|
| + }
|
| +
|
| + /**
|
| + * Parse a list of combinators in a directive.
|
| + *
|
| + * <pre>
|
| + * combinator ::=
|
| + * 'show' identifier (',' identifier)*
|
| + * | 'hide' identifier (',' identifier)*
|
| + * </pre>
|
| + *
|
| + * @return the combinators that were parsed
|
| + */
|
| + List<Combinator> _parseCombinators() {
|
| + List<Combinator> combinators = new List<Combinator>();
|
| + while (_matchesString(_SHOW) || _matchesString(_HIDE)) {
|
| + Token keyword = _expect(TokenType.IDENTIFIER);
|
| + if (keyword.lexeme == _SHOW) {
|
| + List<SimpleIdentifier> shownNames = _parseIdentifierList();
|
| + combinators.add(new ShowCombinator(keyword, shownNames));
|
| + } else {
|
| + List<SimpleIdentifier> hiddenNames = _parseIdentifierList();
|
| + combinators.add(new HideCombinator(keyword, hiddenNames));
|
| + }
|
| + }
|
| + return combinators;
|
| + }
|
| +
|
| + /**
|
| + * Parse the documentation comment and metadata preceding a declaration. This method allows any
|
| + * number of documentation comments to occur before, after or between the metadata, but only
|
| + * returns the last (right-most) documentation comment that is found.
|
| + *
|
| + * <pre>
|
| + * metadata ::=
|
| + * annotation*
|
| + * </pre>
|
| + *
|
| + * @return the documentation comment and metadata that were parsed
|
| + */
|
| + CommentAndMetadata _parseCommentAndMetadata() {
|
| + Comment comment = _parseDocumentationComment();
|
| + List<Annotation> metadata = new List<Annotation>();
|
| + while (_matches(TokenType.AT)) {
|
| + metadata.add(parseAnnotation());
|
| + Comment optionalComment = _parseDocumentationComment();
|
| + if (optionalComment != null) {
|
| + comment = optionalComment;
|
| + }
|
| + }
|
| + return new CommentAndMetadata(comment, metadata);
|
| + }
|
| +
|
| + /**
|
| + * Parse a comment reference from the source between square brackets.
|
| + *
|
| + * <pre>
|
| + * commentReference ::=
|
| + * 'new'? prefixedIdentifier
|
| + * </pre>
|
| + *
|
| + * @param referenceSource the source occurring between the square brackets within a documentation
|
| + * comment
|
| + * @param sourceOffset the offset of the first character of the reference source
|
| + * @return the comment reference that was parsed, or `null` if no reference could be found
|
| + */
|
| + CommentReference _parseCommentReference(String referenceSource, int sourceOffset) {
|
| + // TODO(brianwilkerson) The errors are not getting the right offset/length and are being duplicated.
|
| + if (referenceSource.length == 0) {
|
| + Token syntheticToken = new SyntheticStringToken(TokenType.IDENTIFIER, "", sourceOffset);
|
| + return new CommentReference(null, new SimpleIdentifier(syntheticToken));
|
| + }
|
| + try {
|
| + BooleanErrorListener listener = new BooleanErrorListener();
|
| + Scanner scanner = new Scanner(null, new SubSequenceReader(referenceSource, sourceOffset), listener);
|
| + scanner.setSourceStart(1, 1);
|
| + Token firstToken = scanner.tokenize();
|
| + if (listener.errorReported) {
|
| + return null;
|
| + }
|
| + Token newKeyword = null;
|
| + if (_tokenMatchesKeyword(firstToken, Keyword.NEW)) {
|
| + newKeyword = firstToken;
|
| + firstToken = firstToken.next;
|
| + }
|
| + if (_tokenMatchesIdentifier(firstToken)) {
|
| + Token secondToken = firstToken.next;
|
| + Token thirdToken = secondToken.next;
|
| + Token nextToken;
|
| + Identifier identifier;
|
| + if (_tokenMatches(secondToken, TokenType.PERIOD) && _tokenMatchesIdentifier(thirdToken)) {
|
| + identifier = new PrefixedIdentifier(new SimpleIdentifier(firstToken), secondToken, new SimpleIdentifier(thirdToken));
|
| + nextToken = thirdToken.next;
|
| + } else {
|
| + identifier = new SimpleIdentifier(firstToken);
|
| + nextToken = firstToken.next;
|
| + }
|
| + if (nextToken.type != TokenType.EOF) {
|
| + return null;
|
| + }
|
| + return new CommentReference(newKeyword, identifier);
|
| + } else if (_tokenMatchesKeyword(firstToken, Keyword.THIS) || _tokenMatchesKeyword(firstToken, Keyword.NULL) || _tokenMatchesKeyword(firstToken, Keyword.TRUE) || _tokenMatchesKeyword(firstToken, Keyword.FALSE)) {
|
| + // TODO(brianwilkerson) If we want to support this we will need to extend the definition
|
| + // of CommentReference to take an expression rather than an identifier. For now we just
|
| + // ignore it to reduce the number of errors produced, but that's probably not a valid
|
| + // long term approach.
|
| + return null;
|
| + }
|
| + } catch (exception) {
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * Parse all of the comment references occurring in the given array of documentation comments.
|
| + *
|
| + * <pre>
|
| + * commentReference ::=
|
| + * '[' 'new'? qualified ']' libraryReference?
|
| + *
|
| + * libraryReference ::=
|
| + * '(' stringLiteral ')'
|
| + * </pre>
|
| + *
|
| + * @param tokens the comment tokens representing the documentation comments to be parsed
|
| + * @return the comment references that were parsed
|
| + */
|
| + List<CommentReference> _parseCommentReferences(List<Token> tokens) {
|
| + List<CommentReference> references = new List<CommentReference>();
|
| + for (Token token in tokens) {
|
| + String comment = token.lexeme;
|
| + int length = comment.length;
|
| + List<List<int>> codeBlockRanges = _getCodeBlockRanges(comment);
|
| + int leftIndex = comment.indexOf('[');
|
| + while (leftIndex >= 0 && leftIndex + 1 < length) {
|
| + List<int> range = _findRange(codeBlockRanges, leftIndex);
|
| + if (range == null) {
|
| + int nameOffset = token.offset + leftIndex + 1;
|
| + int rightIndex = JavaString.indexOf(comment, ']', leftIndex);
|
| + if (rightIndex >= 0) {
|
| + int firstChar = comment.codeUnitAt(leftIndex + 1);
|
| + if (firstChar != 0x27 && firstChar != 0x22) {
|
| + if (_isLinkText(comment, rightIndex)) {
|
| + } else {
|
| + CommentReference reference = _parseCommentReference(comment.substring(leftIndex + 1, rightIndex), nameOffset);
|
| + if (reference != null) {
|
| + references.add(reference);
|
| + }
|
| + }
|
| + }
|
| + } else {
|
| + // terminating ']' is not typed yet
|
| + int charAfterLeft = comment.codeUnitAt(leftIndex + 1);
|
| + if (Character.isLetterOrDigit(charAfterLeft)) {
|
| + int nameEnd = StringUtilities.indexOfFirstNotLetterDigit(comment, leftIndex + 1);
|
| + String name = comment.substring(leftIndex + 1, nameEnd);
|
| + Token nameToken = new StringToken(TokenType.IDENTIFIER, name, nameOffset);
|
| + references.add(new CommentReference(null, new SimpleIdentifier(nameToken)));
|
| + } else {
|
| + Token nameToken = new SyntheticStringToken(TokenType.IDENTIFIER, "", nameOffset);
|
| + references.add(new CommentReference(null, new SimpleIdentifier(nameToken)));
|
| + }
|
| + // next character
|
| + rightIndex = leftIndex + 1;
|
| + }
|
| + leftIndex = JavaString.indexOf(comment, '[', rightIndex);
|
| + } else {
|
| + leftIndex = JavaString.indexOf(comment, '[', range[1] + 1);
|
| + }
|
| + }
|
| + }
|
| + return references;
|
| + }
|
| +
|
| + /**
|
| + * Parse a compilation unit member.
|
| + *
|
| + * <pre>
|
| + * compilationUnitMember ::=
|
| + * classDefinition
|
| + * | functionTypeAlias
|
| + * | external functionSignature
|
| + * | external getterSignature
|
| + * | external setterSignature
|
| + * | functionSignature functionBody
|
| + * | returnType? getOrSet identifier formalParameterList functionBody
|
| + * | (final | const) type? staticFinalDeclarationList ';'
|
| + * | variableDeclaration ';'
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the metadata to be associated with the member
|
| + * @return the compilation unit member that was parsed, or `null` if what was parsed could
|
| + * not be represented as a compilation unit member
|
| + */
|
| + CompilationUnitMember _parseCompilationUnitMember(CommentAndMetadata commentAndMetadata) {
|
| + Modifiers modifiers = _parseModifiers();
|
| + if (_matchesKeyword(Keyword.CLASS)) {
|
| + return _parseClassDeclaration(commentAndMetadata, _validateModifiersForClass(modifiers));
|
| + } else if (_matchesKeyword(Keyword.TYPEDEF) && !_tokenMatches(_peek(), TokenType.PERIOD) && !_tokenMatches(_peek(), TokenType.LT) && !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
|
| + _validateModifiersForTypedef(modifiers);
|
| + return _parseTypeAlias(commentAndMetadata);
|
| + } else if (_parseEnum && _matchesKeyword(Keyword.ENUM)) {
|
| + _validateModifiersForEnum(modifiers);
|
| + return _parseEnumDeclaration(commentAndMetadata);
|
| + }
|
| + if (_matchesKeyword(Keyword.VOID)) {
|
| + TypeName returnType = parseReturnType();
|
| + if ((_matchesKeyword(Keyword.GET) || _matchesKeyword(Keyword.SET)) && _tokenMatchesIdentifier(_peek())) {
|
| + _validateModifiersForTopLevelFunction(modifiers);
|
| + return _parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyword, returnType);
|
| + } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) {
|
| + _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken, []);
|
| + return _convertToFunctionDeclaration(_parseOperator(commentAndMetadata, modifiers.externalKeyword, returnType));
|
| + } else if (_matchesIdentifier() && _peek().matchesAny([
|
| + TokenType.OPEN_PAREN,
|
| + TokenType.OPEN_CURLY_BRACKET,
|
| + TokenType.FUNCTION])) {
|
| + _validateModifiersForTopLevelFunction(modifiers);
|
| + return _parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyword, returnType);
|
| + } else {
|
| + //
|
| + // We have found an error of some kind. Try to recover.
|
| + //
|
| + if (_matchesIdentifier()) {
|
| + if (_peek().matchesAny([TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) {
|
| + //
|
| + // We appear to have a variable declaration with a type of "void".
|
| + //
|
| + _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType, []);
|
| + return new TopLevelVariableDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, _parseVariableDeclarationListAfterType(null, _validateModifiersForTopLevelVariable(modifiers), null), _expect(TokenType.SEMICOLON));
|
| + }
|
| + }
|
| + _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []);
|
| + return null;
|
| + }
|
| + } else if ((_matchesKeyword(Keyword.GET) || _matchesKeyword(Keyword.SET)) && _tokenMatchesIdentifier(_peek())) {
|
| + _validateModifiersForTopLevelFunction(modifiers);
|
| + return _parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyword, null);
|
| + } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) {
|
| + _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken, []);
|
| + return _convertToFunctionDeclaration(_parseOperator(commentAndMetadata, modifiers.externalKeyword, null));
|
| + } else if (!_matchesIdentifier()) {
|
| + Token keyword = modifiers.varKeyword;
|
| + if (keyword == null) {
|
| + keyword = modifiers.finalKeyword;
|
| + }
|
| + if (keyword == null) {
|
| + keyword = modifiers.constKeyword;
|
| + }
|
| + if (keyword != null) {
|
| + //
|
| + // We appear to have found an incomplete top-level variable declaration.
|
| + //
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER, []);
|
| + List<VariableDeclaration> variables = new List<VariableDeclaration>();
|
| + variables.add(new VariableDeclaration(null, null, _createSyntheticIdentifier(), null, null));
|
| + return new TopLevelVariableDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, new VariableDeclarationList(null, null, keyword, null, variables), _expectSemicolon());
|
| + }
|
| + _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []);
|
| + return null;
|
| + } else if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
|
| + _validateModifiersForTopLevelFunction(modifiers);
|
| + return _parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyword, null);
|
| + } else if (_peek().matchesAny([TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) {
|
| + if (modifiers.constKeyword == null && modifiers.finalKeyword == null && modifiers.varKeyword == null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, []);
|
| + }
|
| + return new TopLevelVariableDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, _parseVariableDeclarationListAfterType(null, _validateModifiersForTopLevelVariable(modifiers), null), _expect(TokenType.SEMICOLON));
|
| + }
|
| + TypeName returnType = parseReturnType();
|
| + if ((_matchesKeyword(Keyword.GET) || _matchesKeyword(Keyword.SET)) && _tokenMatchesIdentifier(_peek())) {
|
| + _validateModifiersForTopLevelFunction(modifiers);
|
| + return _parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyword, returnType);
|
| + } else if (_matchesKeyword(Keyword.OPERATOR) && _isOperator(_peek())) {
|
| + _reportErrorForToken(ParserErrorCode.TOP_LEVEL_OPERATOR, _currentToken, []);
|
| + return _convertToFunctionDeclaration(_parseOperator(commentAndMetadata, modifiers.externalKeyword, returnType));
|
| + } else if (_matches(TokenType.AT)) {
|
| + return new TopLevelVariableDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, _parseVariableDeclarationListAfterType(null, _validateModifiersForTopLevelVariable(modifiers), returnType), _expect(TokenType.SEMICOLON));
|
| + } else if (!_matchesIdentifier()) {
|
| + // TODO(brianwilkerson) Generalize this error. We could also be parsing a top-level variable at this point.
|
| + _reportErrorForToken(ParserErrorCode.EXPECTED_EXECUTABLE, _currentToken, []);
|
| + Token semicolon;
|
| + if (_matches(TokenType.SEMICOLON)) {
|
| + semicolon = andAdvance;
|
| + } else {
|
| + semicolon = _createSyntheticToken(TokenType.SEMICOLON);
|
| + }
|
| + List<VariableDeclaration> variables = new List<VariableDeclaration>();
|
| + variables.add(new VariableDeclaration(null, null, _createSyntheticIdentifier(), null, null));
|
| + return new TopLevelVariableDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, new VariableDeclarationList(null, null, null, returnType, variables), semicolon);
|
| + }
|
| + if (_peek().matchesAny([
|
| + TokenType.OPEN_PAREN,
|
| + TokenType.FUNCTION,
|
| + TokenType.OPEN_CURLY_BRACKET])) {
|
| + _validateModifiersForTopLevelFunction(modifiers);
|
| + return _parseFunctionDeclaration(commentAndMetadata, modifiers.externalKeyword, returnType);
|
| + }
|
| + return new TopLevelVariableDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, _parseVariableDeclarationListAfterType(null, _validateModifiersForTopLevelVariable(modifiers), returnType), _expect(TokenType.SEMICOLON));
|
| + }
|
| +
|
| + /**
|
| + * Parse a const expression.
|
| + *
|
| + * <pre>
|
| + * constExpression ::=
|
| + * instanceCreationExpression
|
| + * | listLiteral
|
| + * | mapLiteral
|
| + * </pre>
|
| + *
|
| + * @return the const expression that was parsed
|
| + */
|
| + Expression _parseConstExpression() {
|
| + Token keyword = _expectKeyword(Keyword.CONST);
|
| + if (_matches(TokenType.OPEN_SQUARE_BRACKET) || _matches(TokenType.INDEX)) {
|
| + return _parseListLiteral(keyword, null);
|
| + } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
|
| + return _parseMapLiteral(keyword, null);
|
| + } else if (_matches(TokenType.LT)) {
|
| + return _parseListOrMapLiteral(keyword);
|
| + }
|
| + return _parseInstanceCreationExpression(keyword);
|
| + }
|
| +
|
| + ConstructorDeclaration _parseConstructor(CommentAndMetadata commentAndMetadata, Token externalKeyword, Token constKeyword, Token factoryKeyword, SimpleIdentifier returnType, Token period, SimpleIdentifier name, FormalParameterList parameters) {
|
| + bool bodyAllowed = externalKeyword == null;
|
| + Token separator = null;
|
| + List<ConstructorInitializer> initializers = null;
|
| + if (_matches(TokenType.COLON)) {
|
| + separator = andAdvance;
|
| + initializers = new List<ConstructorInitializer>();
|
| + do {
|
| + if (_matchesKeyword(Keyword.THIS)) {
|
| + if (_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
|
| + bodyAllowed = false;
|
| + initializers.add(_parseRedirectingConstructorInvocation());
|
| + } else if (_tokenMatches(_peek(), TokenType.PERIOD) && _tokenMatches(_peekAt(3), TokenType.OPEN_PAREN)) {
|
| + bodyAllowed = false;
|
| + initializers.add(_parseRedirectingConstructorInvocation());
|
| + } else {
|
| + initializers.add(_parseConstructorFieldInitializer());
|
| + }
|
| + } else if (_matchesKeyword(Keyword.SUPER)) {
|
| + initializers.add(_parseSuperConstructorInvocation());
|
| + } else {
|
| + initializers.add(_parseConstructorFieldInitializer());
|
| + }
|
| + } while (_optional(TokenType.COMMA));
|
| + }
|
| + ConstructorName redirectedConstructor = null;
|
| + FunctionBody body;
|
| + if (_matches(TokenType.EQ)) {
|
| + separator = andAdvance;
|
| + redirectedConstructor = parseConstructorName();
|
| + body = new EmptyFunctionBody(_expect(TokenType.SEMICOLON));
|
| + if (factoryKeyword == null) {
|
| + _reportErrorForNode(ParserErrorCode.REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR, redirectedConstructor, []);
|
| + }
|
| + } else {
|
| + body = _parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, false);
|
| + if (constKeyword != null && factoryKeyword != null && externalKeyword == null) {
|
| + _reportErrorForToken(ParserErrorCode.CONST_FACTORY, factoryKeyword, []);
|
| + } else if (body is EmptyFunctionBody) {
|
| + if (factoryKeyword != null && externalKeyword == null) {
|
| + _reportErrorForToken(ParserErrorCode.FACTORY_WITHOUT_BODY, factoryKeyword, []);
|
| + }
|
| + } else {
|
| + if (constKeyword != null) {
|
| + _reportErrorForNode(ParserErrorCode.CONST_CONSTRUCTOR_WITH_BODY, body, []);
|
| + } else if (!bodyAllowed) {
|
| + _reportErrorForNode(ParserErrorCode.EXTERNAL_CONSTRUCTOR_WITH_BODY, body, []);
|
| + }
|
| + }
|
| + }
|
| + return new ConstructorDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, externalKeyword, constKeyword, factoryKeyword, returnType, period, name, parameters, separator, initializers, redirectedConstructor, body);
|
| + }
|
| +
|
| + /**
|
| + * Parse a field initializer within a constructor.
|
| + *
|
| + * <pre>
|
| + * fieldInitializer:
|
| + * ('this' '.')? identifier '=' conditionalExpression cascadeSection*
|
| + * </pre>
|
| + *
|
| + * @return the field initializer that was parsed
|
| + */
|
| + ConstructorFieldInitializer _parseConstructorFieldInitializer() {
|
| + Token keyword = null;
|
| + Token period = null;
|
| + if (_matchesKeyword(Keyword.THIS)) {
|
| + keyword = andAdvance;
|
| + period = _expect(TokenType.PERIOD);
|
| + }
|
| + SimpleIdentifier fieldName = parseSimpleIdentifier();
|
| + Token equals = _expect(TokenType.EQ);
|
| + bool wasInInitializer = _inInitializer;
|
| + _inInitializer = true;
|
| + try {
|
| + Expression expression = parseConditionalExpression();
|
| + TokenType tokenType = _currentToken.type;
|
| + if (tokenType == TokenType.PERIOD_PERIOD) {
|
| + List<Expression> cascadeSections = new List<Expression>();
|
| + while (tokenType == TokenType.PERIOD_PERIOD) {
|
| + Expression section = _parseCascadeSection();
|
| + if (section != null) {
|
| + cascadeSections.add(section);
|
| + }
|
| + tokenType = _currentToken.type;
|
| + }
|
| + expression = new CascadeExpression(expression, cascadeSections);
|
| + }
|
| + return new ConstructorFieldInitializer(keyword, period, fieldName, equals, expression);
|
| + } finally {
|
| + _inInitializer = wasInInitializer;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse a continue statement.
|
| + *
|
| + * <pre>
|
| + * continueStatement ::=
|
| + * 'continue' identifier? ';'
|
| + * </pre>
|
| + *
|
| + * @return the continue statement that was parsed
|
| + */
|
| + Statement _parseContinueStatement() {
|
| + Token continueKeyword = _expectKeyword(Keyword.CONTINUE);
|
| + if (!_inLoop && !_inSwitch) {
|
| + _reportErrorForToken(ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP, continueKeyword, []);
|
| + }
|
| + SimpleIdentifier label = null;
|
| + if (_matchesIdentifier()) {
|
| + label = parseSimpleIdentifier();
|
| + }
|
| + if (_inSwitch && !_inLoop && label == null) {
|
| + _reportErrorForToken(ParserErrorCode.CONTINUE_WITHOUT_LABEL_IN_CASE, continueKeyword, []);
|
| + }
|
| + Token semicolon = _expect(TokenType.SEMICOLON);
|
| + return new ContinueStatement(continueKeyword, label, semicolon);
|
| + }
|
| +
|
| + /**
|
| + * Parse a directive.
|
| + *
|
| + * <pre>
|
| + * directive ::=
|
| + * exportDirective
|
| + * | libraryDirective
|
| + * | importDirective
|
| + * | partDirective
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the metadata to be associated with the directive
|
| + * @return the directive that was parsed
|
| + */
|
| + Directive _parseDirective(CommentAndMetadata commentAndMetadata) {
|
| + if (_matchesKeyword(Keyword.IMPORT)) {
|
| + return _parseImportDirective(commentAndMetadata);
|
| + } else if (_matchesKeyword(Keyword.EXPORT)) {
|
| + return _parseExportDirective(commentAndMetadata);
|
| + } else if (_matchesKeyword(Keyword.LIBRARY)) {
|
| + return _parseLibraryDirective(commentAndMetadata);
|
| + } else if (_matchesKeyword(Keyword.PART)) {
|
| + return _parsePartDirective(commentAndMetadata);
|
| + } else {
|
| + // Internal error: this method should not have been invoked if the current token was something
|
| + // other than one of the above.
|
| + throw new IllegalStateException("parseDirective invoked in an invalid state; currentToken = ${_currentToken}");
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse the script tag and directives in a compilation unit until the first non-directive is
|
| + * encountered.
|
| + *
|
| + *
|
| + * <pre>
|
| + * compilationUnit ::=
|
| + * scriptTag? directive*
|
| + * </pre>
|
| + *
|
| + * @return the compilation unit that was parsed
|
| + */
|
| + CompilationUnit _parseDirectives() {
|
| + Token firstToken = _currentToken;
|
| + ScriptTag scriptTag = null;
|
| + if (_matches(TokenType.SCRIPT_TAG)) {
|
| + scriptTag = new ScriptTag(andAdvance);
|
| + }
|
| + List<Directive> directives = new List<Directive>();
|
| + while (!_matches(TokenType.EOF)) {
|
| + CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
|
| + if ((_matchesKeyword(Keyword.IMPORT) || _matchesKeyword(Keyword.EXPORT) || _matchesKeyword(Keyword.LIBRARY) || _matchesKeyword(Keyword.PART)) && !_tokenMatches(_peek(), TokenType.PERIOD) && !_tokenMatches(_peek(), TokenType.LT) && !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
|
| + directives.add(_parseDirective(commentAndMetadata));
|
| + } else if (_matches(TokenType.SEMICOLON)) {
|
| + _advance();
|
| + } else {
|
| + while (!_matches(TokenType.EOF)) {
|
| + _advance();
|
| + }
|
| + return new CompilationUnit(firstToken, scriptTag, directives, new List<CompilationUnitMember>(), _currentToken);
|
| + }
|
| + }
|
| + return new CompilationUnit(firstToken, scriptTag, directives, new List<CompilationUnitMember>(), _currentToken);
|
| + }
|
| +
|
| + /**
|
| + * Parse a documentation comment.
|
| + *
|
| + * <pre>
|
| + * documentationComment ::=
|
| + * multiLineComment?
|
| + * | singleLineComment*
|
| + * </pre>
|
| + *
|
| + * @return the documentation comment that was parsed, or `null` if there was no comment
|
| + */
|
| + Comment _parseDocumentationComment() {
|
| + List<Token> commentTokens = new List<Token>();
|
| + Token commentToken = _currentToken.precedingComments;
|
| + while (commentToken != null) {
|
| + if (commentToken.type == TokenType.SINGLE_LINE_COMMENT) {
|
| + if (StringUtilities.startsWith3(commentToken.lexeme, 0, 0x2F, 0x2F, 0x2F)) {
|
| + if (commentTokens.length == 1 && StringUtilities.startsWith3(commentTokens[0].lexeme, 0, 0x2F, 0x2A, 0x2A)) {
|
| + commentTokens.clear();
|
| + }
|
| + commentTokens.add(commentToken);
|
| + }
|
| + } else {
|
| + if (StringUtilities.startsWith3(commentToken.lexeme, 0, 0x2F, 0x2A, 0x2A)) {
|
| + commentTokens.clear();
|
| + commentTokens.add(commentToken);
|
| + }
|
| + }
|
| + commentToken = commentToken.next;
|
| + }
|
| + if (commentTokens.isEmpty) {
|
| + return null;
|
| + }
|
| + List<Token> tokens = new List.from(commentTokens);
|
| + List<CommentReference> references = _parseCommentReferences(tokens);
|
| + return Comment.createDocumentationCommentWithReferences(tokens, references);
|
| + }
|
| +
|
| + /**
|
| + * Parse a do statement.
|
| + *
|
| + * <pre>
|
| + * doStatement ::=
|
| + * 'do' statement 'while' '(' expression ')' ';'
|
| + * </pre>
|
| + *
|
| + * @return the do statement that was parsed
|
| + */
|
| + Statement _parseDoStatement() {
|
| + bool wasInLoop = _inLoop;
|
| + _inLoop = true;
|
| + try {
|
| + Token doKeyword = _expectKeyword(Keyword.DO);
|
| + Statement body = parseStatement2();
|
| + Token whileKeyword = _expectKeyword(Keyword.WHILE);
|
| + Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
|
| + Expression condition = parseExpression2();
|
| + Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
|
| + Token semicolon = _expect(TokenType.SEMICOLON);
|
| + return new DoStatement(doKeyword, body, whileKeyword, leftParenthesis, condition, rightParenthesis, semicolon);
|
| + } finally {
|
| + _inLoop = wasInLoop;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse an empty statement.
|
| + *
|
| + * <pre>
|
| + * emptyStatement ::=
|
| + * ';'
|
| + * </pre>
|
| + *
|
| + * @return the empty statement that was parsed
|
| + */
|
| + Statement _parseEmptyStatement() => new EmptyStatement(andAdvance);
|
| +
|
| + EnumConstantDeclaration _parseEnumConstantDeclaration() {
|
| + CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
|
| + SimpleIdentifier name;
|
| + if (_matchesIdentifier()) {
|
| + name = parseSimpleIdentifier();
|
| + } else {
|
| + name = _createSyntheticIdentifier();
|
| + }
|
| + return new EnumConstantDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, name);
|
| + }
|
| +
|
| + /**
|
| + * Parse an enum declaration.
|
| + *
|
| + * <pre>
|
| + * enumType ::=
|
| + * metadata 'enum' id '{' id (',' id)* (',')? '}'
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the metadata to be associated with the member
|
| + * @return the enum declaration that was parsed
|
| + */
|
| + EnumDeclaration _parseEnumDeclaration(CommentAndMetadata commentAndMetadata) {
|
| + Token keyword = _expectKeyword(Keyword.ENUM);
|
| + SimpleIdentifier name = parseSimpleIdentifier();
|
| + Token leftBracket = null;
|
| + List<EnumConstantDeclaration> constants = new List<EnumConstantDeclaration>();
|
| + Token rightBracket = null;
|
| + if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
|
| + leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET);
|
| + if (_matchesIdentifier()) {
|
| + constants.add(_parseEnumConstantDeclaration());
|
| + } else if (_matches(TokenType.COMMA) && _tokenMatchesIdentifier(_peek())) {
|
| + constants.add(_parseEnumConstantDeclaration());
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER, []);
|
| + } else {
|
| + constants.add(_parseEnumConstantDeclaration());
|
| + _reportErrorForCurrentToken(ParserErrorCode.EMPTY_ENUM_BODY, []);
|
| + }
|
| + while (_optional(TokenType.COMMA)) {
|
| + if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
|
| + break;
|
| + }
|
| + constants.add(_parseEnumConstantDeclaration());
|
| + }
|
| + rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
|
| + } else {
|
| + leftBracket = _createSyntheticToken(TokenType.OPEN_CURLY_BRACKET);
|
| + rightBracket = _createSyntheticToken(TokenType.CLOSE_CURLY_BRACKET);
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_ENUM_BODY, []);
|
| + }
|
| + return new EnumDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, keyword, name, leftBracket, constants, rightBracket);
|
| + }
|
| +
|
| + /**
|
| + * Parse an equality expression.
|
| + *
|
| + * <pre>
|
| + * equalityExpression ::=
|
| + * relationalExpression (equalityOperator relationalExpression)?
|
| + * | 'super' equalityOperator relationalExpression
|
| + * </pre>
|
| + *
|
| + * @return the equality expression that was parsed
|
| + */
|
| + Expression _parseEqualityExpression() {
|
| + Expression expression;
|
| + if (_matchesKeyword(Keyword.SUPER) && _currentToken.next.type.isEqualityOperator) {
|
| + expression = new SuperExpression(andAdvance);
|
| + } else {
|
| + expression = _parseRelationalExpression();
|
| + }
|
| + bool leftEqualityExpression = false;
|
| + while (_currentToken.type.isEqualityOperator) {
|
| + Token operator = andAdvance;
|
| + if (leftEqualityExpression) {
|
| + _reportErrorForNode(ParserErrorCode.EQUALITY_CANNOT_BE_EQUALITY_OPERAND, expression, []);
|
| + }
|
| + expression = new BinaryExpression(expression, operator, _parseRelationalExpression());
|
| + leftEqualityExpression = true;
|
| + }
|
| + return expression;
|
| + }
|
| +
|
| + /**
|
| + * Parse an export directive.
|
| + *
|
| + * <pre>
|
| + * exportDirective ::=
|
| + * metadata 'export' stringLiteral combinator*';'
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the metadata to be associated with the directive
|
| + * @return the export directive that was parsed
|
| + */
|
| + ExportDirective _parseExportDirective(CommentAndMetadata commentAndMetadata) {
|
| + Token exportKeyword = _expectKeyword(Keyword.EXPORT);
|
| + StringLiteral libraryUri = parseStringLiteral();
|
| + List<Combinator> combinators = _parseCombinators();
|
| + Token semicolon = _expectSemicolon();
|
| + return new ExportDirective(commentAndMetadata.comment, commentAndMetadata.metadata, exportKeyword, libraryUri, combinators, semicolon);
|
| + }
|
| +
|
| + /**
|
| + * Parse a list of expressions.
|
| + *
|
| + * <pre>
|
| + * expressionList ::=
|
| + * expression (',' expression)*
|
| + * </pre>
|
| + *
|
| + * @return the expression that was parsed
|
| + */
|
| + List<Expression> _parseExpressionList() {
|
| + List<Expression> expressions = new List<Expression>();
|
| + expressions.add(parseExpression2());
|
| + while (_optional(TokenType.COMMA)) {
|
| + expressions.add(parseExpression2());
|
| + }
|
| + return expressions;
|
| + }
|
| +
|
| + /**
|
| + * Parse the 'final', 'const', 'var' or type preceding a variable declaration.
|
| + *
|
| + * <pre>
|
| + * finalConstVarOrType ::=
|
| + * | 'final' type?
|
| + * | 'const' type?
|
| + * | 'var'
|
| + * | type
|
| + * </pre>
|
| + *
|
| + * @param optional `true` if the keyword and type are optional
|
| + * @return the 'final', 'const', 'var' or type that was parsed
|
| + */
|
| + FinalConstVarOrType _parseFinalConstVarOrType(bool optional) {
|
| + Token keyword = null;
|
| + TypeName type = null;
|
| + if (_matchesKeyword(Keyword.FINAL) || _matchesKeyword(Keyword.CONST)) {
|
| + keyword = andAdvance;
|
| + if (_isTypedIdentifier(_currentToken)) {
|
| + type = parseTypeName();
|
| + }
|
| + } else if (_matchesKeyword(Keyword.VAR)) {
|
| + keyword = andAdvance;
|
| + } else {
|
| + if (_isTypedIdentifier(_currentToken)) {
|
| + type = parseReturnType();
|
| + } else if (!optional) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_CONST_FINAL_VAR_OR_TYPE, []);
|
| + }
|
| + }
|
| + return new FinalConstVarOrType(keyword, type);
|
| + }
|
| +
|
| + /**
|
| + * Parse a formal parameter. At most one of `isOptional` and `isNamed` can be
|
| + * `true`.
|
| + *
|
| + * <pre>
|
| + * defaultFormalParameter ::=
|
| + * normalFormalParameter ('=' expression)?
|
| + *
|
| + * defaultNamedParameter ::=
|
| + * normalFormalParameter (':' expression)?
|
| + * </pre>
|
| + *
|
| + * @param kind the kind of parameter being expected based on the presence or absence of group
|
| + * delimiters
|
| + * @return the formal parameter that was parsed
|
| + */
|
| + FormalParameter _parseFormalParameter(ParameterKind kind) {
|
| + NormalFormalParameter parameter = parseNormalFormalParameter();
|
| + if (_matches(TokenType.EQ)) {
|
| + Token seperator = andAdvance;
|
| + Expression defaultValue = parseExpression2();
|
| + if (kind == ParameterKind.NAMED) {
|
| + _reportErrorForToken(ParserErrorCode.WRONG_SEPARATOR_FOR_NAMED_PARAMETER, seperator, []);
|
| + } else if (kind == ParameterKind.REQUIRED) {
|
| + _reportErrorForNode(ParserErrorCode.POSITIONAL_PARAMETER_OUTSIDE_GROUP, parameter, []);
|
| + }
|
| + return new DefaultFormalParameter(parameter, kind, seperator, defaultValue);
|
| + } else if (_matches(TokenType.COLON)) {
|
| + Token seperator = andAdvance;
|
| + Expression defaultValue = parseExpression2();
|
| + if (kind == ParameterKind.POSITIONAL) {
|
| + _reportErrorForToken(ParserErrorCode.WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER, seperator, []);
|
| + } else if (kind == ParameterKind.REQUIRED) {
|
| + _reportErrorForNode(ParserErrorCode.NAMED_PARAMETER_OUTSIDE_GROUP, parameter, []);
|
| + }
|
| + return new DefaultFormalParameter(parameter, kind, seperator, defaultValue);
|
| + } else if (kind != ParameterKind.REQUIRED) {
|
| + return new DefaultFormalParameter(parameter, kind, null, null);
|
| + }
|
| + return parameter;
|
| + }
|
| +
|
| + /**
|
| + * Parse a for statement.
|
| + *
|
| + * <pre>
|
| + * forStatement ::=
|
| + * 'for' '(' forLoopParts ')' statement
|
| + *
|
| + * forLoopParts ::=
|
| + * forInitializerStatement expression? ';' expressionList?
|
| + * | declaredIdentifier 'in' expression
|
| + * | identifier 'in' expression
|
| + *
|
| + * forInitializerStatement ::=
|
| + * localVariableDeclaration ';'
|
| + * | expression? ';'
|
| + * </pre>
|
| + *
|
| + * @return the for statement that was parsed
|
| + */
|
| + Statement _parseForStatement() {
|
| + bool wasInLoop = _inLoop;
|
| + _inLoop = true;
|
| + try {
|
| + Token awaitKeyword = null;
|
| + if (_matchesString(_AWAIT)) {
|
| + awaitKeyword = andAdvance;
|
| + }
|
| + Token forKeyword = _expectKeyword(Keyword.FOR);
|
| + Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
|
| + VariableDeclarationList variableList = null;
|
| + Expression initialization = null;
|
| + if (!_matches(TokenType.SEMICOLON)) {
|
| + CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
|
| + if (_matchesIdentifier() && _tokenMatchesKeyword(_peek(), Keyword.IN)) {
|
| + List<VariableDeclaration> variables = new List<VariableDeclaration>();
|
| + SimpleIdentifier variableName = parseSimpleIdentifier();
|
| + variables.add(new VariableDeclaration(null, null, variableName, null, null));
|
| + variableList = new VariableDeclarationList(commentAndMetadata.comment, commentAndMetadata.metadata, null, null, variables);
|
| + } else if (_isInitializedVariableDeclaration()) {
|
| + variableList = _parseVariableDeclarationListAfterMetadata(commentAndMetadata);
|
| + } else {
|
| + initialization = parseExpression2();
|
| + }
|
| + if (_matchesKeyword(Keyword.IN)) {
|
| + DeclaredIdentifier loopVariable = null;
|
| + SimpleIdentifier identifier = null;
|
| + if (variableList == null) {
|
| + // We found: <expression> 'in'
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_VARIABLE_IN_FOR_EACH, []);
|
| + } else {
|
| + NodeList<VariableDeclaration> variables = variableList.variables;
|
| + if (variables.length > 1) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MULTIPLE_VARIABLES_IN_FOR_EACH, [variables.length.toString()]);
|
| + }
|
| + VariableDeclaration variable = variables[0];
|
| + if (variable.initializer != null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.INITIALIZED_VARIABLE_IN_FOR_EACH, []);
|
| + }
|
| + Token keyword = variableList.keyword;
|
| + TypeName type = variableList.type;
|
| + if (keyword != null || type != null) {
|
| + loopVariable = new DeclaredIdentifier(commentAndMetadata.comment, commentAndMetadata.metadata, keyword, type, variable.name);
|
| + } else {
|
| + if (!commentAndMetadata.metadata.isEmpty) {
|
| + }
|
| + identifier = variable.name;
|
| + }
|
| + }
|
| + Token inKeyword = _expectKeyword(Keyword.IN);
|
| + Expression iterator = parseExpression2();
|
| + Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
|
| + Statement body = parseStatement2();
|
| + if (loopVariable == null) {
|
| + return new ForEachStatement.con2(awaitKeyword, forKeyword, leftParenthesis, identifier, inKeyword, iterator, rightParenthesis, body);
|
| + }
|
| + return new ForEachStatement.con1(awaitKeyword, forKeyword, leftParenthesis, loopVariable, inKeyword, iterator, rightParenthesis, body);
|
| + }
|
| + }
|
| + if (awaitKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.INVALID_AWAIT_IN_FOR, awaitKeyword, []);
|
| + }
|
| + Token leftSeparator = _expect(TokenType.SEMICOLON);
|
| + Expression condition = null;
|
| + if (!_matches(TokenType.SEMICOLON)) {
|
| + condition = parseExpression2();
|
| + }
|
| + Token rightSeparator = _expect(TokenType.SEMICOLON);
|
| + List<Expression> updaters = null;
|
| + if (!_matches(TokenType.CLOSE_PAREN)) {
|
| + updaters = _parseExpressionList();
|
| + }
|
| + Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
|
| + Statement body = parseStatement2();
|
| + return new ForStatement(forKeyword, leftParenthesis, variableList, initialization, leftSeparator, condition, rightSeparator, updaters, rightParenthesis, body);
|
| + } finally {
|
| + _inLoop = wasInLoop;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse a function body.
|
| + *
|
| + * <pre>
|
| + * functionBody ::=
|
| + * '=>' expression ';'
|
| + * | block
|
| + *
|
| + * functionExpressionBody ::=
|
| + * '=>' expression
|
| + * | block
|
| + * </pre>
|
| + *
|
| + * @param mayBeEmpty `true` if the function body is allowed to be empty
|
| + * @param emptyErrorCode the error code to report if function body expected, but not found
|
| + * @param inExpression `true` if the function body is being parsed as part of an expression
|
| + * and therefore does not have a terminating semicolon
|
| + * @return the function body that was parsed
|
| + */
|
| + FunctionBody _parseFunctionBody(bool mayBeEmpty, ParserErrorCode emptyErrorCode, bool inExpression) {
|
| + bool wasInAsync = _inAsync;
|
| + bool wasInLoop = _inLoop;
|
| + bool wasInSwitch = _inSwitch;
|
| + _inAsync = false;
|
| + _inLoop = false;
|
| + _inSwitch = false;
|
| + try {
|
| + if (_matches(TokenType.SEMICOLON)) {
|
| + if (!mayBeEmpty) {
|
| + _reportErrorForCurrentToken(emptyErrorCode, []);
|
| + }
|
| + return new EmptyFunctionBody(andAdvance);
|
| + } else if (_matchesString(_NATIVE)) {
|
| + Token nativeToken = andAdvance;
|
| + StringLiteral stringLiteral = null;
|
| + if (_matches(TokenType.STRING)) {
|
| + stringLiteral = parseStringLiteral();
|
| + }
|
| + return new NativeFunctionBody(nativeToken, stringLiteral, _expect(TokenType.SEMICOLON));
|
| + }
|
| + Token keyword = null;
|
| + Token star = null;
|
| + if (_parseAsync) {
|
| + if (_matchesString(ASYNC)) {
|
| + keyword = andAdvance;
|
| + if (_matches(TokenType.STAR)) {
|
| + star = andAdvance;
|
| + }
|
| + _inAsync = true;
|
| + } else if (_matchesString(SYNC)) {
|
| + keyword = andAdvance;
|
| + if (_matches(TokenType.STAR)) {
|
| + star = andAdvance;
|
| + }
|
| + }
|
| + }
|
| + if (_matches(TokenType.FUNCTION)) {
|
| + if (keyword != null) {
|
| + if (!_tokenMatchesString(keyword, ASYNC)) {
|
| + _reportErrorForToken(ParserErrorCode.INVALID_SYNC, keyword, []);
|
| + keyword = null;
|
| + } else if (star != null) {
|
| + _reportErrorForToken(ParserErrorCode.INVALID_STAR_AFTER_ASYNC, star, []);
|
| + }
|
| + }
|
| + Token functionDefinition = andAdvance;
|
| + Expression expression = parseExpression2();
|
| + Token semicolon = null;
|
| + if (!inExpression) {
|
| + semicolon = _expect(TokenType.SEMICOLON);
|
| + }
|
| + if (!_parseFunctionBodies) {
|
| + return new EmptyFunctionBody(_createSyntheticToken(TokenType.SEMICOLON));
|
| + }
|
| + return new ExpressionFunctionBody(keyword, functionDefinition, expression, semicolon);
|
| + } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
|
| + if (keyword != null) {
|
| + if (_tokenMatchesString(keyword, SYNC) && star == null) {
|
| + _reportErrorForToken(ParserErrorCode.MISSING_STAR_AFTER_SYNC, keyword, []);
|
| + }
|
| + }
|
| + if (!_parseFunctionBodies) {
|
| + _skipBlock();
|
| + return new EmptyFunctionBody(_createSyntheticToken(TokenType.SEMICOLON));
|
| + }
|
| + return new BlockFunctionBody(keyword, star, parseBlock());
|
| + } else {
|
| + // Invalid function body
|
| + _reportErrorForCurrentToken(emptyErrorCode, []);
|
| + return new EmptyFunctionBody(_createSyntheticToken(TokenType.SEMICOLON));
|
| + }
|
| + } finally {
|
| + _inAsync = wasInAsync;
|
| + _inLoop = wasInLoop;
|
| + _inSwitch = wasInSwitch;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse a function declaration.
|
| + *
|
| + * <pre>
|
| + * functionDeclaration ::=
|
| + * functionSignature functionBody
|
| + * | returnType? getOrSet identifier formalParameterList functionBody
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the documentation comment and metadata to be associated with the
|
| + * declaration
|
| + * @param externalKeyword the 'external' keyword, or `null` if the function is not external
|
| + * @param returnType the return type, or `null` if there is no return type
|
| + * @param isStatement `true` if the function declaration is being parsed as a statement
|
| + * @return the function declaration that was parsed
|
| + */
|
| + FunctionDeclaration _parseFunctionDeclaration(CommentAndMetadata commentAndMetadata, Token externalKeyword, TypeName returnType) {
|
| + Token keyword = null;
|
| + bool isGetter = false;
|
| + if (_matchesKeyword(Keyword.GET) && !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
|
| + keyword = andAdvance;
|
| + isGetter = true;
|
| + } else if (_matchesKeyword(Keyword.SET) && !_tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
|
| + keyword = andAdvance;
|
| + }
|
| + SimpleIdentifier name = parseSimpleIdentifier();
|
| + FormalParameterList parameters = null;
|
| + if (!isGetter) {
|
| + if (_matches(TokenType.OPEN_PAREN)) {
|
| + parameters = parseFormalParameterList();
|
| + _validateFormalParameterList(parameters);
|
| + } else {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_FUNCTION_PARAMETERS, []);
|
| + }
|
| + } else if (_matches(TokenType.OPEN_PAREN)) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS, []);
|
| + parseFormalParameterList();
|
| + }
|
| + FunctionBody body;
|
| + if (externalKeyword == null) {
|
| + body = _parseFunctionBody(false, ParserErrorCode.MISSING_FUNCTION_BODY, false);
|
| + } else {
|
| + body = new EmptyFunctionBody(_expect(TokenType.SEMICOLON));
|
| + }
|
| + // if (!isStatement && matches(TokenType.SEMICOLON)) {
|
| + // // TODO(brianwilkerson) Improve this error message.
|
| + // reportError(ParserErrorCode.UNEXPECTED_TOKEN, currentToken.getLexeme());
|
| + // advance();
|
| + // }
|
| + return new FunctionDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, externalKeyword, returnType, keyword, name, new FunctionExpression(parameters, body));
|
| + }
|
| +
|
| + /**
|
| + * Parse a function declaration statement.
|
| + *
|
| + * <pre>
|
| + * functionDeclarationStatement ::=
|
| + * functionSignature functionBody
|
| + * </pre>
|
| + *
|
| + * @return the function declaration statement that was parsed
|
| + */
|
| + Statement _parseFunctionDeclarationStatement() {
|
| + Modifiers modifiers = _parseModifiers();
|
| + _validateModifiersForFunctionDeclarationStatement(modifiers);
|
| + return _parseFunctionDeclarationStatementAfterReturnType(_parseCommentAndMetadata(), _parseOptionalReturnType());
|
| + }
|
| +
|
| + /**
|
| + * Parse a function declaration statement.
|
| + *
|
| + * <pre>
|
| + * functionDeclarationStatement ::=
|
| + * functionSignature functionBody
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the documentation comment and metadata to be associated with the
|
| + * declaration
|
| + * @param returnType the return type, or `null` if there is no return type
|
| + * @return the function declaration statement that was parsed
|
| + */
|
| + Statement _parseFunctionDeclarationStatementAfterReturnType(CommentAndMetadata commentAndMetadata, TypeName returnType) {
|
| + FunctionDeclaration declaration = _parseFunctionDeclaration(commentAndMetadata, null, returnType);
|
| + Token propertyKeyword = declaration.propertyKeyword;
|
| + if (propertyKeyword != null) {
|
| + if ((propertyKeyword as KeywordToken).keyword == Keyword.GET) {
|
| + _reportErrorForToken(ParserErrorCode.GETTER_IN_FUNCTION, propertyKeyword, []);
|
| + } else {
|
| + _reportErrorForToken(ParserErrorCode.SETTER_IN_FUNCTION, propertyKeyword, []);
|
| + }
|
| + }
|
| + return new FunctionDeclarationStatement(declaration);
|
| + }
|
| +
|
| + /**
|
| + * Parse a function type alias.
|
| + *
|
| + * <pre>
|
| + * functionTypeAlias ::=
|
| + * functionPrefix typeParameterList? formalParameterList ';'
|
| + *
|
| + * functionPrefix ::=
|
| + * returnType? name
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the metadata to be associated with the member
|
| + * @param keyword the token representing the 'typedef' keyword
|
| + * @return the function type alias that was parsed
|
| + */
|
| + FunctionTypeAlias _parseFunctionTypeAlias(CommentAndMetadata commentAndMetadata, Token keyword) {
|
| + TypeName returnType = null;
|
| + if (hasReturnTypeInTypeAlias) {
|
| + returnType = parseReturnType();
|
| + }
|
| + SimpleIdentifier name = parseSimpleIdentifier();
|
| + TypeParameterList typeParameters = null;
|
| + if (_matches(TokenType.LT)) {
|
| + typeParameters = parseTypeParameterList();
|
| + }
|
| + if (_matches(TokenType.SEMICOLON) || _matches(TokenType.EOF)) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS, []);
|
| + FormalParameterList parameters = new FormalParameterList(_createSyntheticToken(TokenType.OPEN_PAREN), null, null, null, _createSyntheticToken(TokenType.CLOSE_PAREN));
|
| + Token semicolon = _expect(TokenType.SEMICOLON);
|
| + return new FunctionTypeAlias(commentAndMetadata.comment, commentAndMetadata.metadata, keyword, returnType, name, typeParameters, parameters, semicolon);
|
| + } else if (!_matches(TokenType.OPEN_PAREN)) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_TYPEDEF_PARAMETERS, []);
|
| + // TODO(brianwilkerson) Recover from this error. At the very least we should skip to the start
|
| + // of the next valid compilation unit member, allowing for the possibility of finding the
|
| + // typedef parameters before that point.
|
| + return new FunctionTypeAlias(commentAndMetadata.comment, commentAndMetadata.metadata, keyword, returnType, name, typeParameters, new FormalParameterList(_createSyntheticToken(TokenType.OPEN_PAREN), null, null, null, _createSyntheticToken(TokenType.CLOSE_PAREN)), _createSyntheticToken(TokenType.SEMICOLON));
|
| + }
|
| + FormalParameterList parameters = parseFormalParameterList();
|
| + _validateFormalParameterList(parameters);
|
| + Token semicolon = _expect(TokenType.SEMICOLON);
|
| + return new FunctionTypeAlias(commentAndMetadata.comment, commentAndMetadata.metadata, keyword, returnType, name, typeParameters, parameters, semicolon);
|
| + }
|
| +
|
| + /**
|
| + * Parse a getter.
|
| + *
|
| + * <pre>
|
| + * getter ::=
|
| + * getterSignature functionBody?
|
| + *
|
| + * getterSignature ::=
|
| + * 'external'? 'static'? returnType? 'get' identifier
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the documentation comment and metadata to be associated with the
|
| + * declaration
|
| + * @param externalKeyword the 'external' token
|
| + * @param staticKeyword the static keyword, or `null` if the getter is not static
|
| + * @param the return type that has already been parsed, or `null` if there was no return
|
| + * type
|
| + * @return the getter that was parsed
|
| + */
|
| + MethodDeclaration _parseGetter(CommentAndMetadata commentAndMetadata, Token externalKeyword, Token staticKeyword, TypeName returnType) {
|
| + Token propertyKeyword = _expectKeyword(Keyword.GET);
|
| + SimpleIdentifier name = parseSimpleIdentifier();
|
| + if (_matches(TokenType.OPEN_PAREN) && _tokenMatches(_peek(), TokenType.CLOSE_PAREN)) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.GETTER_WITH_PARAMETERS, []);
|
| + _advance();
|
| + _advance();
|
| + }
|
| + FunctionBody body = _parseFunctionBody(externalKeyword != null || staticKeyword == null, ParserErrorCode.STATIC_GETTER_WITHOUT_BODY, false);
|
| + if (externalKeyword != null && body is! EmptyFunctionBody) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_GETTER_WITH_BODY, []);
|
| + }
|
| + return new MethodDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, externalKeyword, staticKeyword, returnType, propertyKeyword, null, name, null, body);
|
| + }
|
| +
|
| + /**
|
| + * Parse a list of identifiers.
|
| + *
|
| + * <pre>
|
| + * identifierList ::=
|
| + * identifier (',' identifier)*
|
| + * </pre>
|
| + *
|
| + * @return the list of identifiers that were parsed
|
| + */
|
| + List<SimpleIdentifier> _parseIdentifierList() {
|
| + List<SimpleIdentifier> identifiers = new List<SimpleIdentifier>();
|
| + identifiers.add(parseSimpleIdentifier());
|
| + while (_matches(TokenType.COMMA)) {
|
| + _advance();
|
| + identifiers.add(parseSimpleIdentifier());
|
| + }
|
| + return identifiers;
|
| + }
|
| +
|
| + /**
|
| + * Parse an if statement.
|
| + *
|
| + * <pre>
|
| + * ifStatement ::=
|
| + * 'if' '(' expression ')' statement ('else' statement)?
|
| + * </pre>
|
| + *
|
| + * @return the if statement that was parsed
|
| + */
|
| + Statement _parseIfStatement() {
|
| + Token ifKeyword = _expectKeyword(Keyword.IF);
|
| + Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
|
| + Expression condition = parseExpression2();
|
| + Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
|
| + Statement thenStatement = parseStatement2();
|
| + Token elseKeyword = null;
|
| + Statement elseStatement = null;
|
| + if (_matchesKeyword(Keyword.ELSE)) {
|
| + elseKeyword = andAdvance;
|
| + elseStatement = parseStatement2();
|
| + }
|
| + return new IfStatement(ifKeyword, leftParenthesis, condition, rightParenthesis, thenStatement, elseKeyword, elseStatement);
|
| + }
|
| +
|
| + /**
|
| + * Parse an import directive.
|
| + *
|
| + * <pre>
|
| + * importDirective ::=
|
| + * metadata 'import' stringLiteral ('as' identifier)? combinator*';'
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the metadata to be associated with the directive
|
| + * @return the import directive that was parsed
|
| + */
|
| + ImportDirective _parseImportDirective(CommentAndMetadata commentAndMetadata) {
|
| + Token importKeyword = _expectKeyword(Keyword.IMPORT);
|
| + StringLiteral libraryUri = parseStringLiteral();
|
| + Token deferredToken = null;
|
| + Token asToken = null;
|
| + SimpleIdentifier prefix = null;
|
| + if (_matchesKeyword(Keyword.DEFERRED)) {
|
| + if (_parseDeferredLibraries) {
|
| + deferredToken = andAdvance;
|
| + } else {
|
| + _reportErrorForCurrentToken(ParserErrorCode.DEFERRED_IMPORTS_NOT_SUPPORTED, []);
|
| + _advance();
|
| + }
|
| + }
|
| + if (_matchesKeyword(Keyword.AS)) {
|
| + asToken = andAdvance;
|
| + prefix = parseSimpleIdentifier();
|
| + } else if (deferredToken != null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_PREFIX_IN_DEFERRED_IMPORT, []);
|
| + }
|
| + List<Combinator> combinators = _parseCombinators();
|
| + Token semicolon = _expectSemicolon();
|
| + return new ImportDirective(commentAndMetadata.comment, commentAndMetadata.metadata, importKeyword, libraryUri, deferredToken, asToken, prefix, combinators, semicolon);
|
| + }
|
| +
|
| + /**
|
| + * Parse a list of initialized identifiers.
|
| + *
|
| + * <pre>
|
| + * ?? ::=
|
| + * 'static'? ('var' | type) initializedIdentifierList ';'
|
| + * | 'final' type? initializedIdentifierList ';'
|
| + *
|
| + * initializedIdentifierList ::=
|
| + * initializedIdentifier (',' initializedIdentifier)*
|
| + *
|
| + * initializedIdentifier ::=
|
| + * identifier ('=' expression)?
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the documentation comment and metadata to be associated with the
|
| + * declaration
|
| + * @param staticKeyword the static keyword, or `null` if the getter is not static
|
| + * @param keyword the token representing the 'final', 'const' or 'var' keyword, or `null` if
|
| + * there is no keyword
|
| + * @param type the type that has already been parsed, or `null` if 'var' was provided
|
| + * @return the getter that was parsed
|
| + */
|
| + FieldDeclaration _parseInitializedIdentifierList(CommentAndMetadata commentAndMetadata, Token staticKeyword, Token keyword, TypeName type) {
|
| + VariableDeclarationList fieldList = _parseVariableDeclarationListAfterType(null, keyword, type);
|
| + return new FieldDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, staticKeyword, fieldList, _expect(TokenType.SEMICOLON));
|
| + }
|
| +
|
| + /**
|
| + * Parse an instance creation expression.
|
| + *
|
| + * <pre>
|
| + * instanceCreationExpression ::=
|
| + * ('new' | 'const') type ('.' identifier)? argumentList
|
| + * </pre>
|
| + *
|
| + * @param keyword the 'new' or 'const' keyword that introduces the expression
|
| + * @return the instance creation expression that was parsed
|
| + */
|
| + InstanceCreationExpression _parseInstanceCreationExpression(Token keyword) {
|
| + ConstructorName constructorName = parseConstructorName();
|
| + ArgumentList argumentList = parseArgumentList();
|
| + return new InstanceCreationExpression(keyword, constructorName, argumentList);
|
| + }
|
| +
|
| + /**
|
| + * Parse a library directive.
|
| + *
|
| + * <pre>
|
| + * libraryDirective ::=
|
| + * metadata 'library' identifier ';'
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the metadata to be associated with the directive
|
| + * @return the library directive that was parsed
|
| + */
|
| + LibraryDirective _parseLibraryDirective(CommentAndMetadata commentAndMetadata) {
|
| + Token keyword = _expectKeyword(Keyword.LIBRARY);
|
| + LibraryIdentifier libraryName = _parseLibraryName(ParserErrorCode.MISSING_NAME_IN_LIBRARY_DIRECTIVE, keyword);
|
| + Token semicolon = _expect(TokenType.SEMICOLON);
|
| + return new LibraryDirective(commentAndMetadata.comment, commentAndMetadata.metadata, keyword, libraryName, semicolon);
|
| + }
|
| +
|
| + /**
|
| + * Parse a library name.
|
| + *
|
| + * <pre>
|
| + * libraryName ::=
|
| + * libraryIdentifier
|
| + * </pre>
|
| + *
|
| + * @param missingNameError the error code to be used if the library name is missing
|
| + * @param missingNameToken the token associated with the error produced if the library name is
|
| + * missing
|
| + * @return the library name that was parsed
|
| + */
|
| + LibraryIdentifier _parseLibraryName(ParserErrorCode missingNameError, Token missingNameToken) {
|
| + if (_matchesIdentifier()) {
|
| + return parseLibraryIdentifier();
|
| + } else if (_matches(TokenType.STRING)) {
|
| + // TODO(brianwilkerson) Recovery: This should be extended to handle arbitrary tokens until we
|
| + // can find a token that can start a compilation unit member.
|
| + StringLiteral string = parseStringLiteral();
|
| + _reportErrorForNode(ParserErrorCode.NON_IDENTIFIER_LIBRARY_NAME, string, []);
|
| + } else {
|
| + _reportErrorForToken(missingNameError, missingNameToken, []);
|
| + }
|
| + List<SimpleIdentifier> components = new List<SimpleIdentifier>();
|
| + components.add(_createSyntheticIdentifier());
|
| + return new LibraryIdentifier(components);
|
| + }
|
| +
|
| + /**
|
| + * Parse a list literal.
|
| + *
|
| + * <pre>
|
| + * listLiteral ::=
|
| + * 'const'? typeArguments? '[' (expressionList ','?)? ']'
|
| + * </pre>
|
| + *
|
| + * @param modifier the 'const' modifier appearing before the literal, or `null` if there is
|
| + * no modifier
|
| + * @param typeArguments the type arguments appearing before the literal, or `null` if there
|
| + * are no type arguments
|
| + * @return the list literal that was parsed
|
| + */
|
| + ListLiteral _parseListLiteral(Token modifier, TypeArgumentList typeArguments) {
|
| + // may be empty list literal
|
| + if (_matches(TokenType.INDEX)) {
|
| + BeginToken leftBracket = new BeginToken(TokenType.OPEN_SQUARE_BRACKET, _currentToken.offset);
|
| + Token rightBracket = new Token(TokenType.CLOSE_SQUARE_BRACKET, _currentToken.offset + 1);
|
| + leftBracket.endToken = rightBracket;
|
| + rightBracket.setNext(_currentToken.next);
|
| + leftBracket.setNext(rightBracket);
|
| + _currentToken.previous.setNext(leftBracket);
|
| + _currentToken = _currentToken.next;
|
| + return new ListLiteral(modifier, typeArguments, leftBracket, null, rightBracket);
|
| + }
|
| + // open
|
| + Token leftBracket = _expect(TokenType.OPEN_SQUARE_BRACKET);
|
| + if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) {
|
| + return new ListLiteral(modifier, typeArguments, leftBracket, null, andAdvance);
|
| + }
|
| + bool wasInInitializer = _inInitializer;
|
| + _inInitializer = false;
|
| + try {
|
| + List<Expression> elements = new List<Expression>();
|
| + elements.add(parseExpression2());
|
| + while (_optional(TokenType.COMMA)) {
|
| + if (_matches(TokenType.CLOSE_SQUARE_BRACKET)) {
|
| + return new ListLiteral(modifier, typeArguments, leftBracket, elements, andAdvance);
|
| + }
|
| + elements.add(parseExpression2());
|
| + }
|
| + Token rightBracket = _expect(TokenType.CLOSE_SQUARE_BRACKET);
|
| + return new ListLiteral(modifier, typeArguments, leftBracket, elements, rightBracket);
|
| + } finally {
|
| + _inInitializer = wasInInitializer;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse a list or map literal.
|
| + *
|
| + * <pre>
|
| + * listOrMapLiteral ::=
|
| + * listLiteral
|
| + * | mapLiteral
|
| + * </pre>
|
| + *
|
| + * @param modifier the 'const' modifier appearing before the literal, or `null` if there is
|
| + * no modifier
|
| + * @return the list or map literal that was parsed
|
| + */
|
| + TypedLiteral _parseListOrMapLiteral(Token modifier) {
|
| + TypeArgumentList typeArguments = null;
|
| + if (_matches(TokenType.LT)) {
|
| + typeArguments = parseTypeArgumentList();
|
| + }
|
| + if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
|
| + return _parseMapLiteral(modifier, typeArguments);
|
| + } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) || _matches(TokenType.INDEX)) {
|
| + return _parseListLiteral(modifier, typeArguments);
|
| + }
|
| + _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_LIST_OR_MAP_LITERAL, []);
|
| + return new ListLiteral(modifier, typeArguments, _createSyntheticToken(TokenType.OPEN_SQUARE_BRACKET), null, _createSyntheticToken(TokenType.CLOSE_SQUARE_BRACKET));
|
| + }
|
| +
|
| + /**
|
| + * Parse a logical and expression.
|
| + *
|
| + * <pre>
|
| + * logicalAndExpression ::=
|
| + * equalityExpression ('&&' equalityExpression)*
|
| + * </pre>
|
| + *
|
| + * @return the logical and expression that was parsed
|
| + */
|
| + Expression _parseLogicalAndExpression() {
|
| + Expression expression = _parseEqualityExpression();
|
| + while (_matches(TokenType.AMPERSAND_AMPERSAND)) {
|
| + Token operator = andAdvance;
|
| + expression = new BinaryExpression(expression, operator, _parseEqualityExpression());
|
| + }
|
| + return expression;
|
| + }
|
| +
|
| + /**
|
| + * Parse a map literal.
|
| + *
|
| + * <pre>
|
| + * mapLiteral ::=
|
| + * 'const'? typeArguments? '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)? '}'
|
| + * </pre>
|
| + *
|
| + * @param modifier the 'const' modifier appearing before the literal, or `null` if there is
|
| + * no modifier
|
| + * @param typeArguments the type arguments that were declared, or `null` if there are no
|
| + * type arguments
|
| + * @return the map literal that was parsed
|
| + */
|
| + MapLiteral _parseMapLiteral(Token modifier, TypeArgumentList typeArguments) {
|
| + Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET);
|
| + List<MapLiteralEntry> entries = new List<MapLiteralEntry>();
|
| + if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
|
| + return new MapLiteral(modifier, typeArguments, leftBracket, entries, andAdvance);
|
| + }
|
| + bool wasInInitializer = _inInitializer;
|
| + _inInitializer = false;
|
| + try {
|
| + entries.add(parseMapLiteralEntry());
|
| + while (_optional(TokenType.COMMA)) {
|
| + if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
|
| + return new MapLiteral(modifier, typeArguments, leftBracket, entries, andAdvance);
|
| + }
|
| + entries.add(parseMapLiteralEntry());
|
| + }
|
| + Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
|
| + return new MapLiteral(modifier, typeArguments, leftBracket, entries, rightBracket);
|
| + } finally {
|
| + _inInitializer = wasInInitializer;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse a method declaration.
|
| + *
|
| + * <pre>
|
| + * functionDeclaration ::=
|
| + * ('external' 'static'?)? functionSignature functionBody
|
| + * | 'external'? functionSignature ';'
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the documentation comment and metadata to be associated with the
|
| + * declaration
|
| + * @param externalKeyword the 'external' token
|
| + * @param staticKeyword the static keyword, or `null` if the getter is not static
|
| + * @param returnType the return type of the method
|
| + * @param name the name of the method
|
| + * @param parameters the parameters to the method
|
| + * @return the method declaration that was parsed
|
| + */
|
| + MethodDeclaration _parseMethodDeclarationAfterParameters(CommentAndMetadata commentAndMetadata, Token externalKeyword, Token staticKeyword, TypeName returnType, SimpleIdentifier name, FormalParameterList parameters) {
|
| + FunctionBody body = _parseFunctionBody(externalKeyword != null || staticKeyword == null, ParserErrorCode.MISSING_FUNCTION_BODY, false);
|
| + if (externalKeyword != null) {
|
| + if (body is! EmptyFunctionBody) {
|
| + _reportErrorForNode(ParserErrorCode.EXTERNAL_METHOD_WITH_BODY, body, []);
|
| + }
|
| + } else if (staticKeyword != null) {
|
| + if (body is EmptyFunctionBody) {
|
| + _reportErrorForNode(ParserErrorCode.ABSTRACT_STATIC_METHOD, body, []);
|
| + }
|
| + }
|
| + return new MethodDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, externalKeyword, staticKeyword, returnType, null, null, name, parameters, body);
|
| + }
|
| +
|
| + /**
|
| + * Parse a method declaration.
|
| + *
|
| + * <pre>
|
| + * functionDeclaration ::=
|
| + * 'external'? 'static'? functionSignature functionBody
|
| + * | 'external'? functionSignature ';'
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the documentation comment and metadata to be associated with the
|
| + * declaration
|
| + * @param externalKeyword the 'external' token
|
| + * @param staticKeyword the static keyword, or `null` if the getter is not static
|
| + * @param returnType the return type of the method
|
| + * @return the method declaration that was parsed
|
| + */
|
| + MethodDeclaration _parseMethodDeclarationAfterReturnType(CommentAndMetadata commentAndMetadata, Token externalKeyword, Token staticKeyword, TypeName returnType) {
|
| + SimpleIdentifier methodName = parseSimpleIdentifier();
|
| + FormalParameterList parameters = parseFormalParameterList();
|
| + _validateFormalParameterList(parameters);
|
| + return _parseMethodDeclarationAfterParameters(commentAndMetadata, externalKeyword, staticKeyword, returnType, methodName, parameters);
|
| + }
|
| +
|
| + /**
|
| + * Parse the modifiers preceding a declaration. This method allows the modifiers to appear in any
|
| + * order but does generate errors for duplicated modifiers. Checks for other problems, such as
|
| + * having the modifiers appear in the wrong order or specifying both 'const' and 'final', are
|
| + * reported in one of the methods whose name is prefixed with `validateModifiersFor`.
|
| + *
|
| + * <pre>
|
| + * modifiers ::=
|
| + * ('abstract' | 'const' | 'external' | 'factory' | 'final' | 'static' | 'var')*
|
| + * </pre>
|
| + *
|
| + * @return the modifiers that were parsed
|
| + */
|
| + Modifiers _parseModifiers() {
|
| + Modifiers modifiers = new Modifiers();
|
| + bool progress = true;
|
| + while (progress) {
|
| + if (_tokenMatches(_peek(), TokenType.PERIOD) || _tokenMatches(_peek(), TokenType.LT) || _tokenMatches(_peek(), TokenType.OPEN_PAREN)) {
|
| + return modifiers;
|
| + }
|
| + if (_matchesKeyword(Keyword.ABSTRACT)) {
|
| + if (modifiers.abstractKeyword != null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
|
| + _advance();
|
| + } else {
|
| + modifiers.abstractKeyword = andAdvance;
|
| + }
|
| + } else if (_matchesKeyword(Keyword.CONST)) {
|
| + if (modifiers.constKeyword != null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
|
| + _advance();
|
| + } else {
|
| + modifiers.constKeyword = andAdvance;
|
| + }
|
| + } else if (_matchesKeyword(Keyword.EXTERNAL) && !_tokenMatches(_peek(), TokenType.PERIOD) && !_tokenMatches(_peek(), TokenType.LT)) {
|
| + if (modifiers.externalKeyword != null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
|
| + _advance();
|
| + } else {
|
| + modifiers.externalKeyword = andAdvance;
|
| + }
|
| + } else if (_matchesKeyword(Keyword.FACTORY) && !_tokenMatches(_peek(), TokenType.PERIOD) && !_tokenMatches(_peek(), TokenType.LT)) {
|
| + if (modifiers.factoryKeyword != null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
|
| + _advance();
|
| + } else {
|
| + modifiers.factoryKeyword = andAdvance;
|
| + }
|
| + } else if (_matchesKeyword(Keyword.FINAL)) {
|
| + if (modifiers.finalKeyword != null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
|
| + _advance();
|
| + } else {
|
| + modifiers.finalKeyword = andAdvance;
|
| + }
|
| + } else if (_matchesKeyword(Keyword.STATIC) && !_tokenMatches(_peek(), TokenType.PERIOD) && !_tokenMatches(_peek(), TokenType.LT)) {
|
| + if (modifiers.staticKeyword != null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
|
| + _advance();
|
| + } else {
|
| + modifiers.staticKeyword = andAdvance;
|
| + }
|
| + } else if (_matchesKeyword(Keyword.VAR)) {
|
| + if (modifiers.varKeyword != null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.DUPLICATED_MODIFIER, [_currentToken.lexeme]);
|
| + _advance();
|
| + } else {
|
| + modifiers.varKeyword = andAdvance;
|
| + }
|
| + } else {
|
| + progress = false;
|
| + }
|
| + }
|
| + return modifiers;
|
| + }
|
| +
|
| + /**
|
| + * Parse a multiplicative expression.
|
| + *
|
| + * <pre>
|
| + * multiplicativeExpression ::=
|
| + * unaryExpression (multiplicativeOperator unaryExpression)*
|
| + * | 'super' (multiplicativeOperator unaryExpression)+
|
| + * </pre>
|
| + *
|
| + * @return the multiplicative expression that was parsed
|
| + */
|
| + Expression _parseMultiplicativeExpression() {
|
| + Expression expression;
|
| + if (_matchesKeyword(Keyword.SUPER) && _currentToken.next.type.isMultiplicativeOperator) {
|
| + expression = new SuperExpression(andAdvance);
|
| + } else {
|
| + expression = _parseUnaryExpression();
|
| + }
|
| + while (_currentToken.type.isMultiplicativeOperator) {
|
| + Token operator = andAdvance;
|
| + expression = new BinaryExpression(expression, operator, _parseUnaryExpression());
|
| + }
|
| + return expression;
|
| + }
|
| +
|
| + /**
|
| + * Parse a class native clause.
|
| + *
|
| + * <pre>
|
| + * classNativeClause ::=
|
| + * 'native' name
|
| + * </pre>
|
| + *
|
| + * @return the class native clause that was parsed
|
| + */
|
| + NativeClause _parseNativeClause() {
|
| + Token keyword = andAdvance;
|
| + StringLiteral name = parseStringLiteral();
|
| + return new NativeClause(keyword, name);
|
| + }
|
| +
|
| + /**
|
| + * Parse a new expression.
|
| + *
|
| + * <pre>
|
| + * newExpression ::=
|
| + * instanceCreationExpression
|
| + * </pre>
|
| + *
|
| + * @return the new expression that was parsed
|
| + */
|
| + InstanceCreationExpression _parseNewExpression() => _parseInstanceCreationExpression(_expectKeyword(Keyword.NEW));
|
| +
|
| + /**
|
| + * Parse a non-labeled statement.
|
| + *
|
| + * <pre>
|
| + * nonLabeledStatement ::=
|
| + * block
|
| + * | assertStatement
|
| + * | breakStatement
|
| + * | continueStatement
|
| + * | doStatement
|
| + * | forStatement
|
| + * | ifStatement
|
| + * | returnStatement
|
| + * | switchStatement
|
| + * | tryStatement
|
| + * | whileStatement
|
| + * | variableDeclarationList ';'
|
| + * | expressionStatement
|
| + * | functionSignature functionBody
|
| + * </pre>
|
| + *
|
| + * @return the non-labeled statement that was parsed
|
| + */
|
| + Statement _parseNonLabeledStatement() {
|
| + // TODO(brianwilkerson) Pass the comment and metadata on where appropriate.
|
| + CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
|
| + if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
|
| + if (_tokenMatches(_peek(), TokenType.STRING)) {
|
| + Token afterString = _skipStringLiteral(_currentToken.next);
|
| + if (afterString != null && afterString.type == TokenType.COLON) {
|
| + return new ExpressionStatement(parseExpression2(), _expect(TokenType.SEMICOLON));
|
| + }
|
| + }
|
| + return parseBlock();
|
| + } else if (_matches(TokenType.KEYWORD) && !(_currentToken as KeywordToken).keyword.isPseudoKeyword) {
|
| + Keyword keyword = (_currentToken as KeywordToken).keyword;
|
| + // TODO(jwren) compute some metrics to figure out a better order for this if-then sequence to optimize performance
|
| + if (keyword == Keyword.ASSERT) {
|
| + return _parseAssertStatement();
|
| + } else if (keyword == Keyword.BREAK) {
|
| + return _parseBreakStatement();
|
| + } else if (keyword == Keyword.CONTINUE) {
|
| + return _parseContinueStatement();
|
| + } else if (keyword == Keyword.DO) {
|
| + return _parseDoStatement();
|
| + } else if (keyword == Keyword.FOR) {
|
| + return _parseForStatement();
|
| + } else if (keyword == Keyword.IF) {
|
| + return _parseIfStatement();
|
| + } else if (keyword == Keyword.RETHROW) {
|
| + return new ExpressionStatement(_parseRethrowExpression(), _expect(TokenType.SEMICOLON));
|
| + } else if (keyword == Keyword.RETURN) {
|
| + return _parseReturnStatement();
|
| + } else if (keyword == Keyword.SWITCH) {
|
| + return _parseSwitchStatement();
|
| + } else if (keyword == Keyword.THROW) {
|
| + return new ExpressionStatement(_parseThrowExpression(), _expect(TokenType.SEMICOLON));
|
| + } else if (keyword == Keyword.TRY) {
|
| + return _parseTryStatement();
|
| + } else if (keyword == Keyword.WHILE) {
|
| + return _parseWhileStatement();
|
| + } else if (keyword == Keyword.VAR || keyword == Keyword.FINAL) {
|
| + return _parseVariableDeclarationStatementAfterMetadata(commentAndMetadata);
|
| + } else if (keyword == Keyword.VOID) {
|
| + TypeName returnType = parseReturnType();
|
| + if (_matchesIdentifier() && _peek().matchesAny([
|
| + TokenType.OPEN_PAREN,
|
| + TokenType.OPEN_CURLY_BRACKET,
|
| + TokenType.FUNCTION])) {
|
| + return _parseFunctionDeclarationStatementAfterReturnType(commentAndMetadata, returnType);
|
| + } else {
|
| + //
|
| + // We have found an error of some kind. Try to recover.
|
| + //
|
| + if (_matchesIdentifier()) {
|
| + if (_peek().matchesAny([TokenType.EQ, TokenType.COMMA, TokenType.SEMICOLON])) {
|
| + //
|
| + // We appear to have a variable declaration with a type of "void".
|
| + //
|
| + _reportErrorForNode(ParserErrorCode.VOID_VARIABLE, returnType, []);
|
| + return _parseVariableDeclarationStatementAfterMetadata(commentAndMetadata);
|
| + }
|
| + } else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
|
| + //
|
| + // We appear to have found an incomplete statement at the end of a block. Parse it as a
|
| + // variable declaration.
|
| + //
|
| + return _parseVariableDeclarationStatementAfterType(commentAndMetadata, null, returnType);
|
| + }
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT, []);
|
| + // TODO(brianwilkerson) Recover from this error.
|
| + return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON));
|
| + }
|
| + } else if (keyword == Keyword.CONST) {
|
| + if (_peek().matchesAny([
|
| + TokenType.LT,
|
| + TokenType.OPEN_CURLY_BRACKET,
|
| + TokenType.OPEN_SQUARE_BRACKET,
|
| + TokenType.INDEX])) {
|
| + return new ExpressionStatement(parseExpression2(), _expect(TokenType.SEMICOLON));
|
| + } else if (_tokenMatches(_peek(), TokenType.IDENTIFIER)) {
|
| + Token afterType = _skipTypeName(_peek());
|
| + if (afterType != null) {
|
| + if (_tokenMatches(afterType, TokenType.OPEN_PAREN) || (_tokenMatches(afterType, TokenType.PERIOD) && _tokenMatches(afterType.next, TokenType.IDENTIFIER) && _tokenMatches(afterType.next.next, TokenType.OPEN_PAREN))) {
|
| + return new ExpressionStatement(parseExpression2(), _expect(TokenType.SEMICOLON));
|
| + }
|
| + }
|
| + }
|
| + return _parseVariableDeclarationStatementAfterMetadata(commentAndMetadata);
|
| + } else if (keyword == Keyword.NEW || keyword == Keyword.TRUE || keyword == Keyword.FALSE || keyword == Keyword.NULL || keyword == Keyword.SUPER || keyword == Keyword.THIS) {
|
| + return new ExpressionStatement(parseExpression2(), _expect(TokenType.SEMICOLON));
|
| + } else {
|
| + //
|
| + // We have found an error of some kind. Try to recover.
|
| + //
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT, []);
|
| + return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON));
|
| + }
|
| + } else if (_inAsync && _matchesString(_YIELD)) {
|
| + return _parseYieldStatement();
|
| + } else if (_inAsync && _matchesString(_AWAIT)) {
|
| + if (_tokenMatchesKeyword(_peek(), Keyword.FOR)) {
|
| + return _parseForStatement();
|
| + }
|
| + return new ExpressionStatement(parseExpression2(), _expect(TokenType.SEMICOLON));
|
| + } else if (_matches(TokenType.SEMICOLON)) {
|
| + return _parseEmptyStatement();
|
| + } else if (_isInitializedVariableDeclaration()) {
|
| + return _parseVariableDeclarationStatementAfterMetadata(commentAndMetadata);
|
| + } else if (_isFunctionDeclaration()) {
|
| + return _parseFunctionDeclarationStatement();
|
| + } else if (_matches(TokenType.CLOSE_CURLY_BRACKET)) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_STATEMENT, []);
|
| + return new EmptyStatement(_createSyntheticToken(TokenType.SEMICOLON));
|
| + } else {
|
| + return new ExpressionStatement(parseExpression2(), _expect(TokenType.SEMICOLON));
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse an operator declaration.
|
| + *
|
| + * <pre>
|
| + * operatorDeclaration ::=
|
| + * operatorSignature (';' | functionBody)
|
| + *
|
| + * operatorSignature ::=
|
| + * 'external'? returnType? 'operator' operator formalParameterList
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the documentation comment and metadata to be associated with the
|
| + * declaration
|
| + * @param externalKeyword the 'external' token
|
| + * @param the return type that has already been parsed, or `null` if there was no return
|
| + * type
|
| + * @return the operator declaration that was parsed
|
| + */
|
| + MethodDeclaration _parseOperator(CommentAndMetadata commentAndMetadata, Token externalKeyword, TypeName returnType) {
|
| + Token operatorKeyword;
|
| + if (_matchesKeyword(Keyword.OPERATOR)) {
|
| + operatorKeyword = andAdvance;
|
| + } else {
|
| + _reportErrorForToken(ParserErrorCode.MISSING_KEYWORD_OPERATOR, _currentToken, []);
|
| + operatorKeyword = _createSyntheticKeyword(Keyword.OPERATOR);
|
| + }
|
| + if (!_currentToken.isUserDefinableOperator) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.NON_USER_DEFINABLE_OPERATOR, [_currentToken.lexeme]);
|
| + }
|
| + SimpleIdentifier name = new SimpleIdentifier(andAdvance);
|
| + if (_matches(TokenType.EQ)) {
|
| + Token previous = _currentToken.previous;
|
| + if ((_tokenMatches(previous, TokenType.EQ_EQ) || _tokenMatches(previous, TokenType.BANG_EQ)) && _currentToken.offset == previous.offset + 2) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.INVALID_OPERATOR, ["${previous.lexeme}${_currentToken.lexeme}"]);
|
| + _advance();
|
| + }
|
| + }
|
| + FormalParameterList parameters = parseFormalParameterList();
|
| + _validateFormalParameterList(parameters);
|
| + FunctionBody body = _parseFunctionBody(true, ParserErrorCode.MISSING_FUNCTION_BODY, false);
|
| + if (externalKeyword != null && body is! EmptyFunctionBody) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_OPERATOR_WITH_BODY, []);
|
| + }
|
| + return new MethodDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, externalKeyword, null, returnType, null, operatorKeyword, name, parameters, body);
|
| + }
|
| +
|
| + /**
|
| + * Parse a return type if one is given, otherwise return `null` without advancing.
|
| + *
|
| + * @return the return type that was parsed
|
| + */
|
| + TypeName _parseOptionalReturnType() {
|
| + if (_matchesKeyword(Keyword.VOID)) {
|
| + return parseReturnType();
|
| + } else if (_matchesIdentifier() && !_matchesKeyword(Keyword.GET) && !_matchesKeyword(Keyword.SET) && !_matchesKeyword(Keyword.OPERATOR) && (_tokenMatchesIdentifier(_peek()) || _tokenMatches(_peek(), TokenType.LT))) {
|
| + return parseReturnType();
|
| + } else if (_matchesIdentifier() && _tokenMatches(_peek(), TokenType.PERIOD) && _tokenMatchesIdentifier(_peekAt(2)) && (_tokenMatchesIdentifier(_peekAt(3)) || _tokenMatches(_peekAt(3), TokenType.LT))) {
|
| + return parseReturnType();
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * Parse a part or part-of directive.
|
| + *
|
| + * <pre>
|
| + * partDirective ::=
|
| + * metadata 'part' stringLiteral ';'
|
| + *
|
| + * partOfDirective ::=
|
| + * metadata 'part' 'of' identifier ';'
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the metadata to be associated with the directive
|
| + * @return the part or part-of directive that was parsed
|
| + */
|
| + Directive _parsePartDirective(CommentAndMetadata commentAndMetadata) {
|
| + Token partKeyword = _expectKeyword(Keyword.PART);
|
| + if (_matchesString(_OF)) {
|
| + Token ofKeyword = andAdvance;
|
| + LibraryIdentifier libraryName = _parseLibraryName(ParserErrorCode.MISSING_NAME_IN_PART_OF_DIRECTIVE, ofKeyword);
|
| + Token semicolon = _expect(TokenType.SEMICOLON);
|
| + return new PartOfDirective(commentAndMetadata.comment, commentAndMetadata.metadata, partKeyword, ofKeyword, libraryName, semicolon);
|
| + }
|
| + StringLiteral partUri = parseStringLiteral();
|
| + Token semicolon = _expect(TokenType.SEMICOLON);
|
| + return new PartDirective(commentAndMetadata.comment, commentAndMetadata.metadata, partKeyword, partUri, semicolon);
|
| + }
|
| +
|
| + /**
|
| + * Parse a postfix expression.
|
| + *
|
| + * <pre>
|
| + * postfixExpression ::=
|
| + * assignableExpression postfixOperator
|
| + * | primary selector*
|
| + *
|
| + * selector ::=
|
| + * assignableSelector
|
| + * | argumentList
|
| + * </pre>
|
| + *
|
| + * @return the postfix expression that was parsed
|
| + */
|
| + Expression _parsePostfixExpression() {
|
| + Expression operand = _parseAssignableExpression(true);
|
| + if (_matches(TokenType.OPEN_SQUARE_BRACKET) || _matches(TokenType.PERIOD) || _matches(TokenType.OPEN_PAREN)) {
|
| + do {
|
| + if (_matches(TokenType.OPEN_PAREN)) {
|
| + ArgumentList argumentList = parseArgumentList();
|
| + if (operand is PropertyAccess) {
|
| + PropertyAccess access = operand as PropertyAccess;
|
| + operand = new MethodInvocation(access.target, access.operator, access.propertyName, argumentList);
|
| + } else {
|
| + operand = new FunctionExpressionInvocation(operand, argumentList);
|
| + }
|
| + } else {
|
| + operand = _parseAssignableSelector(operand, true);
|
| + }
|
| + } while (_matches(TokenType.OPEN_SQUARE_BRACKET) || _matches(TokenType.PERIOD) || _matches(TokenType.OPEN_PAREN));
|
| + return operand;
|
| + }
|
| + if (!_currentToken.type.isIncrementOperator) {
|
| + return operand;
|
| + }
|
| + _ensureAssignable(operand);
|
| + Token operator = andAdvance;
|
| + return new PostfixExpression(operand, operator);
|
| + }
|
| +
|
| + /**
|
| + * Parse a primary expression.
|
| + *
|
| + * <pre>
|
| + * primary ::=
|
| + * thisExpression
|
| + * | 'super' assignableSelector
|
| + * | functionExpression
|
| + * | literal
|
| + * | identifier
|
| + * | newExpression
|
| + * | constObjectExpression
|
| + * | '(' expression ')'
|
| + * | argumentDefinitionTest
|
| + *
|
| + * literal ::=
|
| + * nullLiteral
|
| + * | booleanLiteral
|
| + * | numericLiteral
|
| + * | stringLiteral
|
| + * | symbolLiteral
|
| + * | mapLiteral
|
| + * | listLiteral
|
| + * </pre>
|
| + *
|
| + * @return the primary expression that was parsed
|
| + */
|
| + Expression _parsePrimaryExpression() {
|
| + if (_matchesKeyword(Keyword.THIS)) {
|
| + return new ThisExpression(andAdvance);
|
| + } else if (_matchesKeyword(Keyword.SUPER)) {
|
| + return _parseAssignableSelector(new SuperExpression(andAdvance), false);
|
| + } else if (_matchesKeyword(Keyword.NULL)) {
|
| + return new NullLiteral(andAdvance);
|
| + } else if (_matchesKeyword(Keyword.FALSE)) {
|
| + return new BooleanLiteral(andAdvance, false);
|
| + } else if (_matchesKeyword(Keyword.TRUE)) {
|
| + return new BooleanLiteral(andAdvance, true);
|
| + } else if (_matches(TokenType.DOUBLE)) {
|
| + Token token = andAdvance;
|
| + double value = 0.0;
|
| + try {
|
| + value = double.parse(token.lexeme);
|
| + } on FormatException catch (exception) {
|
| + }
|
| + return new DoubleLiteral(token, value);
|
| + } else if (_matches(TokenType.HEXADECIMAL)) {
|
| + Token token = andAdvance;
|
| + int value = null;
|
| + try {
|
| + value = int.parse(token.lexeme.substring(2), radix: 16);
|
| + } on FormatException catch (exception) {
|
| + }
|
| + return new IntegerLiteral(token, value);
|
| + } else if (_matches(TokenType.INT)) {
|
| + Token token = andAdvance;
|
| + int value = null;
|
| + try {
|
| + value = int.parse(token.lexeme);
|
| + } on FormatException catch (exception) {
|
| + }
|
| + return new IntegerLiteral(token, value);
|
| + } else if (_matches(TokenType.STRING)) {
|
| + return parseStringLiteral();
|
| + } else if (_matches(TokenType.OPEN_CURLY_BRACKET)) {
|
| + return _parseMapLiteral(null, null);
|
| + } else if (_matches(TokenType.OPEN_SQUARE_BRACKET) || _matches(TokenType.INDEX)) {
|
| + return _parseListLiteral(null, null);
|
| + } else if (_matchesIdentifier()) {
|
| + // TODO(brianwilkerson) The code below was an attempt to recover from an error case, but it
|
| + // needs to be applied as a recovery only after we know that parsing it as an identifier
|
| + // doesn't work. Leaving the code as a reminder of how to recover.
|
| + // if (isFunctionExpression(peek())) {
|
| + // //
|
| + // // Function expressions were allowed to have names at one point, but this is now illegal.
|
| + // //
|
| + // reportError(ParserErrorCode.NAMED_FUNCTION_EXPRESSION, getAndAdvance());
|
| + // return parseFunctionExpression();
|
| + // }
|
| + return parsePrefixedIdentifier();
|
| + } else if (_matchesKeyword(Keyword.NEW)) {
|
| + return _parseNewExpression();
|
| + } else if (_matchesKeyword(Keyword.CONST)) {
|
| + return _parseConstExpression();
|
| + } else if (_matches(TokenType.OPEN_PAREN)) {
|
| + if (_isFunctionExpression(_currentToken)) {
|
| + return parseFunctionExpression();
|
| + }
|
| + Token leftParenthesis = andAdvance;
|
| + bool wasInInitializer = _inInitializer;
|
| + _inInitializer = false;
|
| + try {
|
| + Expression expression = parseExpression2();
|
| + Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
|
| + return new ParenthesizedExpression(leftParenthesis, expression, rightParenthesis);
|
| + } finally {
|
| + _inInitializer = wasInInitializer;
|
| + }
|
| + } else if (_matches(TokenType.LT)) {
|
| + return _parseListOrMapLiteral(null);
|
| + } else if (_matches(TokenType.QUESTION) && _tokenMatches(_peek(), TokenType.IDENTIFIER)) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
|
| + _advance();
|
| + return _parsePrimaryExpression();
|
| + } else if (_matchesKeyword(Keyword.VOID)) {
|
| + //
|
| + // Recover from having a return type of "void" where a return type is not expected.
|
| + //
|
| + // TODO(brianwilkerson) Improve this error message.
|
| + _reportErrorForCurrentToken(ParserErrorCode.UNEXPECTED_TOKEN, [_currentToken.lexeme]);
|
| + _advance();
|
| + return _parsePrimaryExpression();
|
| + } else if (_matches(TokenType.HASH)) {
|
| + return _parseSymbolLiteral();
|
| + } else {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER, []);
|
| + return _createSyntheticIdentifier();
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse a redirecting constructor invocation.
|
| + *
|
| + * <pre>
|
| + * redirectingConstructorInvocation ::=
|
| + * 'this' ('.' identifier)? arguments
|
| + * </pre>
|
| + *
|
| + * @return the redirecting constructor invocation that was parsed
|
| + */
|
| + RedirectingConstructorInvocation _parseRedirectingConstructorInvocation() {
|
| + Token keyword = _expectKeyword(Keyword.THIS);
|
| + Token period = null;
|
| + SimpleIdentifier constructorName = null;
|
| + if (_matches(TokenType.PERIOD)) {
|
| + period = andAdvance;
|
| + constructorName = parseSimpleIdentifier();
|
| + }
|
| + ArgumentList argumentList = parseArgumentList();
|
| + return new RedirectingConstructorInvocation(keyword, period, constructorName, argumentList);
|
| + }
|
| +
|
| + /**
|
| + * Parse a relational expression.
|
| + *
|
| + * <pre>
|
| + * relationalExpression ::=
|
| + * bitwiseOrExpression ('is' '!'? type | 'as' type | relationalOperator bitwiseOrExpression)?
|
| + * | 'super' relationalOperator bitwiseOrExpression
|
| + * </pre>
|
| + *
|
| + * @return the relational expression that was parsed
|
| + */
|
| + Expression _parseRelationalExpression() {
|
| + if (_matchesKeyword(Keyword.SUPER) && _currentToken.next.type.isRelationalOperator) {
|
| + Expression expression = new SuperExpression(andAdvance);
|
| + Token operator = andAdvance;
|
| + expression = new BinaryExpression(expression, operator, parseBitwiseOrExpression());
|
| + return expression;
|
| + }
|
| + Expression expression = parseBitwiseOrExpression();
|
| + if (_matchesKeyword(Keyword.AS)) {
|
| + Token asOperator = andAdvance;
|
| + expression = new AsExpression(expression, asOperator, parseTypeName());
|
| + } else if (_matchesKeyword(Keyword.IS)) {
|
| + Token isOperator = andAdvance;
|
| + Token notOperator = null;
|
| + if (_matches(TokenType.BANG)) {
|
| + notOperator = andAdvance;
|
| + }
|
| + expression = new IsExpression(expression, isOperator, notOperator, parseTypeName());
|
| + } else if (_currentToken.type.isRelationalOperator) {
|
| + Token operator = andAdvance;
|
| + expression = new BinaryExpression(expression, operator, parseBitwiseOrExpression());
|
| + }
|
| + return expression;
|
| + }
|
| +
|
| + /**
|
| + * Parse a rethrow expression.
|
| + *
|
| + * <pre>
|
| + * rethrowExpression ::=
|
| + * 'rethrow'
|
| + * </pre>
|
| + *
|
| + * @return the rethrow expression that was parsed
|
| + */
|
| + Expression _parseRethrowExpression() => new RethrowExpression(_expectKeyword(Keyword.RETHROW));
|
| +
|
| + /**
|
| + * Parse a return statement.
|
| + *
|
| + * <pre>
|
| + * returnStatement ::=
|
| + * 'return' expression? ';'
|
| + * </pre>
|
| + *
|
| + * @return the return statement that was parsed
|
| + */
|
| + Statement _parseReturnStatement() {
|
| + Token returnKeyword = _expectKeyword(Keyword.RETURN);
|
| + if (_matches(TokenType.SEMICOLON)) {
|
| + return new ReturnStatement(returnKeyword, null, andAdvance);
|
| + }
|
| + Expression expression = parseExpression2();
|
| + Token semicolon = _expect(TokenType.SEMICOLON);
|
| + return new ReturnStatement(returnKeyword, expression, semicolon);
|
| + }
|
| +
|
| + /**
|
| + * Parse a setter.
|
| + *
|
| + * <pre>
|
| + * setter ::=
|
| + * setterSignature functionBody?
|
| + *
|
| + * setterSignature ::=
|
| + * 'external'? 'static'? returnType? 'set' identifier formalParameterList
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the documentation comment and metadata to be associated with the
|
| + * declaration
|
| + * @param externalKeyword the 'external' token
|
| + * @param staticKeyword the static keyword, or `null` if the setter is not static
|
| + * @param the return type that has already been parsed, or `null` if there was no return
|
| + * type
|
| + * @return the setter that was parsed
|
| + */
|
| + MethodDeclaration _parseSetter(CommentAndMetadata commentAndMetadata, Token externalKeyword, Token staticKeyword, TypeName returnType) {
|
| + Token propertyKeyword = _expectKeyword(Keyword.SET);
|
| + SimpleIdentifier name = parseSimpleIdentifier();
|
| + FormalParameterList parameters = parseFormalParameterList();
|
| + _validateFormalParameterList(parameters);
|
| + FunctionBody body = _parseFunctionBody(externalKeyword != null || staticKeyword == null, ParserErrorCode.STATIC_SETTER_WITHOUT_BODY, false);
|
| + if (externalKeyword != null && body is! EmptyFunctionBody) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.EXTERNAL_SETTER_WITH_BODY, []);
|
| + }
|
| + return new MethodDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, externalKeyword, staticKeyword, returnType, propertyKeyword, null, name, parameters, body);
|
| + }
|
| +
|
| + /**
|
| + * Parse a shift expression.
|
| + *
|
| + * <pre>
|
| + * shiftExpression ::=
|
| + * additiveExpression (shiftOperator additiveExpression)*
|
| + * | 'super' (shiftOperator additiveExpression)+
|
| + * </pre>
|
| + *
|
| + * @return the shift expression that was parsed
|
| + */
|
| + Expression _parseShiftExpression() {
|
| + Expression expression;
|
| + if (_matchesKeyword(Keyword.SUPER) && _currentToken.next.type.isShiftOperator) {
|
| + expression = new SuperExpression(andAdvance);
|
| + } else {
|
| + expression = _parseAdditiveExpression();
|
| + }
|
| + while (_currentToken.type.isShiftOperator) {
|
| + Token operator = andAdvance;
|
| + expression = new BinaryExpression(expression, operator, _parseAdditiveExpression());
|
| + }
|
| + return expression;
|
| + }
|
| +
|
| + /**
|
| + * Parse a list of statements within a switch statement.
|
| + *
|
| + * <pre>
|
| + * statements ::=
|
| + * statement*
|
| + * </pre>
|
| + *
|
| + * @return the statements that were parsed
|
| + */
|
| + List<Statement> _parseStatementList() {
|
| + List<Statement> statements = new List<Statement>();
|
| + Token statementStart = _currentToken;
|
| + while (!_matches(TokenType.EOF) && !_matches(TokenType.CLOSE_CURLY_BRACKET) && !_isSwitchMember()) {
|
| + statements.add(parseStatement2());
|
| + if (identical(_currentToken, statementStart)) {
|
| + _reportErrorForToken(ParserErrorCode.UNEXPECTED_TOKEN, _currentToken, [_currentToken.lexeme]);
|
| + _advance();
|
| + }
|
| + statementStart = _currentToken;
|
| + }
|
| + return statements;
|
| + }
|
| +
|
| + /**
|
| + * Parse a string literal that contains interpolations.
|
| + *
|
| + * @return the string literal that was parsed
|
| + */
|
| + StringInterpolation _parseStringInterpolation(Token string) {
|
| + List<InterpolationElement> elements = new List<InterpolationElement>();
|
| + bool hasMore = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION) || _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER);
|
| + elements.add(new InterpolationString(string, _computeStringValue(string.lexeme, true, !hasMore)));
|
| + while (hasMore) {
|
| + if (_matches(TokenType.STRING_INTERPOLATION_EXPRESSION)) {
|
| + Token openToken = andAdvance;
|
| + bool wasInInitializer = _inInitializer;
|
| + _inInitializer = false;
|
| + try {
|
| + Expression expression = parseExpression2();
|
| + Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
|
| + elements.add(new InterpolationExpression(openToken, expression, rightBracket));
|
| + } finally {
|
| + _inInitializer = wasInInitializer;
|
| + }
|
| + } else {
|
| + Token openToken = andAdvance;
|
| + Expression expression = null;
|
| + if (_matchesKeyword(Keyword.THIS)) {
|
| + expression = new ThisExpression(andAdvance);
|
| + } else {
|
| + expression = parseSimpleIdentifier();
|
| + }
|
| + elements.add(new InterpolationExpression(openToken, expression, null));
|
| + }
|
| + if (_matches(TokenType.STRING)) {
|
| + string = andAdvance;
|
| + hasMore = _matches(TokenType.STRING_INTERPOLATION_EXPRESSION) || _matches(TokenType.STRING_INTERPOLATION_IDENTIFIER);
|
| + elements.add(new InterpolationString(string, _computeStringValue(string.lexeme, false, !hasMore)));
|
| + } else {
|
| + hasMore = false;
|
| + }
|
| + }
|
| + return new StringInterpolation(elements);
|
| + }
|
| +
|
| + /**
|
| + * Parse a super constructor invocation.
|
| + *
|
| + * <pre>
|
| + * superConstructorInvocation ::=
|
| + * 'super' ('.' identifier)? arguments
|
| + * </pre>
|
| + *
|
| + * @return the super constructor invocation that was parsed
|
| + */
|
| + SuperConstructorInvocation _parseSuperConstructorInvocation() {
|
| + Token keyword = _expectKeyword(Keyword.SUPER);
|
| + Token period = null;
|
| + SimpleIdentifier constructorName = null;
|
| + if (_matches(TokenType.PERIOD)) {
|
| + period = andAdvance;
|
| + constructorName = parseSimpleIdentifier();
|
| + }
|
| + ArgumentList argumentList = parseArgumentList();
|
| + return new SuperConstructorInvocation(keyword, period, constructorName, argumentList);
|
| + }
|
| +
|
| + /**
|
| + * Parse a switch statement.
|
| + *
|
| + * <pre>
|
| + * switchStatement ::=
|
| + * 'switch' '(' expression ')' '{' switchCase* defaultCase? '}'
|
| + *
|
| + * switchCase ::=
|
| + * label* ('case' expression ':') statements
|
| + *
|
| + * defaultCase ::=
|
| + * label* 'default' ':' statements
|
| + * </pre>
|
| + *
|
| + * @return the switch statement that was parsed
|
| + */
|
| + SwitchStatement _parseSwitchStatement() {
|
| + bool wasInSwitch = _inSwitch;
|
| + _inSwitch = true;
|
| + try {
|
| + HashSet<String> definedLabels = new HashSet<String>();
|
| + Token keyword = _expectKeyword(Keyword.SWITCH);
|
| + Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
|
| + Expression expression = parseExpression2();
|
| + Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
|
| + Token leftBracket = _expect(TokenType.OPEN_CURLY_BRACKET);
|
| + Token defaultKeyword = null;
|
| + List<SwitchMember> members = new List<SwitchMember>();
|
| + while (!_matches(TokenType.EOF) && !_matches(TokenType.CLOSE_CURLY_BRACKET)) {
|
| + List<Label> labels = new List<Label>();
|
| + while (_matchesIdentifier() && _tokenMatches(_peek(), TokenType.COLON)) {
|
| + SimpleIdentifier identifier = parseSimpleIdentifier();
|
| + String label = identifier.token.lexeme;
|
| + if (definedLabels.contains(label)) {
|
| + _reportErrorForToken(ParserErrorCode.DUPLICATE_LABEL_IN_SWITCH_STATEMENT, identifier.token, [label]);
|
| + } else {
|
| + definedLabels.add(label);
|
| + }
|
| + Token colon = _expect(TokenType.COLON);
|
| + labels.add(new Label(identifier, colon));
|
| + }
|
| + if (_matchesKeyword(Keyword.CASE)) {
|
| + Token caseKeyword = andAdvance;
|
| + Expression caseExpression = parseExpression2();
|
| + Token colon = _expect(TokenType.COLON);
|
| + members.add(new SwitchCase(labels, caseKeyword, caseExpression, colon, _parseStatementList()));
|
| + if (defaultKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.SWITCH_HAS_CASE_AFTER_DEFAULT_CASE, caseKeyword, []);
|
| + }
|
| + } else if (_matchesKeyword(Keyword.DEFAULT)) {
|
| + if (defaultKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.SWITCH_HAS_MULTIPLE_DEFAULT_CASES, _peek(), []);
|
| + }
|
| + defaultKeyword = andAdvance;
|
| + Token colon = _expect(TokenType.COLON);
|
| + members.add(new SwitchDefault(labels, defaultKeyword, colon, _parseStatementList()));
|
| + } else {
|
| + // We need to advance, otherwise we could end up in an infinite loop, but this could be a
|
| + // lot smarter about recovering from the error.
|
| + _reportErrorForCurrentToken(ParserErrorCode.EXPECTED_CASE_OR_DEFAULT, []);
|
| + while (!_matches(TokenType.EOF) && !_matches(TokenType.CLOSE_CURLY_BRACKET) && !_matchesKeyword(Keyword.CASE) && !_matchesKeyword(Keyword.DEFAULT)) {
|
| + _advance();
|
| + }
|
| + }
|
| + }
|
| + Token rightBracket = _expect(TokenType.CLOSE_CURLY_BRACKET);
|
| + return new SwitchStatement(keyword, leftParenthesis, expression, rightParenthesis, leftBracket, members, rightBracket);
|
| + } finally {
|
| + _inSwitch = wasInSwitch;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse a symbol literal.
|
| + *
|
| + * <pre>
|
| + * symbolLiteral ::=
|
| + * '#' identifier ('.' identifier)*
|
| + * </pre>
|
| + *
|
| + * @return the symbol literal that was parsed
|
| + */
|
| + SymbolLiteral _parseSymbolLiteral() {
|
| + Token poundSign = andAdvance;
|
| + List<Token> components = new List<Token>();
|
| + if (_matchesIdentifier()) {
|
| + components.add(andAdvance);
|
| + while (_matches(TokenType.PERIOD)) {
|
| + _advance();
|
| + if (_matchesIdentifier()) {
|
| + components.add(andAdvance);
|
| + } else {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER, []);
|
| + components.add(_createSyntheticToken(TokenType.IDENTIFIER));
|
| + break;
|
| + }
|
| + }
|
| + } else if (_currentToken.isOperator) {
|
| + components.add(andAdvance);
|
| + } else if (_tokenMatchesKeyword(_currentToken, Keyword.VOID)) {
|
| + components.add(andAdvance);
|
| + } else {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER, []);
|
| + components.add(_createSyntheticToken(TokenType.IDENTIFIER));
|
| + }
|
| + return new SymbolLiteral(poundSign, new List.from(components));
|
| + }
|
| +
|
| + /**
|
| + * Parse a throw expression.
|
| + *
|
| + * <pre>
|
| + * throwExpression ::=
|
| + * 'throw' expression
|
| + * </pre>
|
| + *
|
| + * @return the throw expression that was parsed
|
| + */
|
| + Expression _parseThrowExpression() {
|
| + Token keyword = _expectKeyword(Keyword.THROW);
|
| + if (_matches(TokenType.SEMICOLON) || _matches(TokenType.CLOSE_PAREN)) {
|
| + _reportErrorForToken(ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken, []);
|
| + return new ThrowExpression(keyword, _createSyntheticIdentifier());
|
| + }
|
| + Expression expression = parseExpression2();
|
| + return new ThrowExpression(keyword, expression);
|
| + }
|
| +
|
| + /**
|
| + * Parse a throw expression.
|
| + *
|
| + * <pre>
|
| + * throwExpressionWithoutCascade ::=
|
| + * 'throw' expressionWithoutCascade
|
| + * </pre>
|
| + *
|
| + * @return the throw expression that was parsed
|
| + */
|
| + Expression _parseThrowExpressionWithoutCascade() {
|
| + Token keyword = _expectKeyword(Keyword.THROW);
|
| + if (_matches(TokenType.SEMICOLON) || _matches(TokenType.CLOSE_PAREN)) {
|
| + _reportErrorForToken(ParserErrorCode.MISSING_EXPRESSION_IN_THROW, _currentToken, []);
|
| + return new ThrowExpression(keyword, _createSyntheticIdentifier());
|
| + }
|
| + Expression expression = parseExpressionWithoutCascade();
|
| + return new ThrowExpression(keyword, expression);
|
| + }
|
| +
|
| + /**
|
| + * Parse a try statement.
|
| + *
|
| + * <pre>
|
| + * tryStatement ::=
|
| + * 'try' block (onPart+ finallyPart? | finallyPart)
|
| + *
|
| + * onPart ::=
|
| + * catchPart block
|
| + * | 'on' type catchPart? block
|
| + *
|
| + * catchPart ::=
|
| + * 'catch' '(' identifier (',' identifier)? ')'
|
| + *
|
| + * finallyPart ::=
|
| + * 'finally' block
|
| + * </pre>
|
| + *
|
| + * @return the try statement that was parsed
|
| + */
|
| + Statement _parseTryStatement() {
|
| + Token tryKeyword = _expectKeyword(Keyword.TRY);
|
| + Block body = parseBlock();
|
| + List<CatchClause> catchClauses = new List<CatchClause>();
|
| + Block finallyClause = null;
|
| + while (_matchesString(_ON) || _matchesKeyword(Keyword.CATCH)) {
|
| + Token onKeyword = null;
|
| + TypeName exceptionType = null;
|
| + if (_matchesString(_ON)) {
|
| + onKeyword = andAdvance;
|
| + exceptionType = parseTypeName();
|
| + }
|
| + Token catchKeyword = null;
|
| + Token leftParenthesis = null;
|
| + SimpleIdentifier exceptionParameter = null;
|
| + Token comma = null;
|
| + SimpleIdentifier stackTraceParameter = null;
|
| + Token rightParenthesis = null;
|
| + if (_matchesKeyword(Keyword.CATCH)) {
|
| + catchKeyword = andAdvance;
|
| + leftParenthesis = _expect(TokenType.OPEN_PAREN);
|
| + exceptionParameter = parseSimpleIdentifier();
|
| + if (_matches(TokenType.COMMA)) {
|
| + comma = andAdvance;
|
| + stackTraceParameter = parseSimpleIdentifier();
|
| + }
|
| + rightParenthesis = _expect(TokenType.CLOSE_PAREN);
|
| + }
|
| + Block catchBody = parseBlock();
|
| + catchClauses.add(new CatchClause(onKeyword, exceptionType, catchKeyword, leftParenthesis, exceptionParameter, comma, stackTraceParameter, rightParenthesis, catchBody));
|
| + }
|
| + Token finallyKeyword = null;
|
| + if (_matchesKeyword(Keyword.FINALLY)) {
|
| + finallyKeyword = andAdvance;
|
| + finallyClause = parseBlock();
|
| + } else {
|
| + if (catchClauses.isEmpty) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_CATCH_OR_FINALLY, []);
|
| + }
|
| + }
|
| + return new TryStatement(tryKeyword, body, catchClauses, finallyKeyword, finallyClause);
|
| + }
|
| +
|
| + /**
|
| + * Parse a type alias.
|
| + *
|
| + * <pre>
|
| + * typeAlias ::=
|
| + * 'typedef' typeAliasBody
|
| + *
|
| + * typeAliasBody ::=
|
| + * classTypeAlias
|
| + * | functionTypeAlias
|
| + *
|
| + * classTypeAlias ::=
|
| + * identifier typeParameters? '=' 'abstract'? mixinApplication
|
| + *
|
| + * mixinApplication ::=
|
| + * qualified withClause implementsClause? ';'
|
| + *
|
| + * functionTypeAlias ::=
|
| + * functionPrefix typeParameterList? formalParameterList ';'
|
| + *
|
| + * functionPrefix ::=
|
| + * returnType? name
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the metadata to be associated with the member
|
| + * @return the type alias that was parsed
|
| + */
|
| + TypeAlias _parseTypeAlias(CommentAndMetadata commentAndMetadata) {
|
| + Token keyword = _expectKeyword(Keyword.TYPEDEF);
|
| + if (_matchesIdentifier()) {
|
| + Token next = _peek();
|
| + if (_tokenMatches(next, TokenType.LT)) {
|
| + next = _skipTypeParameterList(next);
|
| + if (next != null && _tokenMatches(next, TokenType.EQ)) {
|
| + TypeAlias typeAlias = _parseClassTypeAlias(commentAndMetadata, null, keyword);
|
| + _reportErrorForToken(ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword, []);
|
| + return typeAlias;
|
| + }
|
| + } else if (_tokenMatches(next, TokenType.EQ)) {
|
| + TypeAlias typeAlias = _parseClassTypeAlias(commentAndMetadata, null, keyword);
|
| + _reportErrorForToken(ParserErrorCode.DEPRECATED_CLASS_TYPE_ALIAS, keyword, []);
|
| + return typeAlias;
|
| + }
|
| + }
|
| + return _parseFunctionTypeAlias(commentAndMetadata, keyword);
|
| + }
|
| +
|
| + /**
|
| + * Parse a unary expression.
|
| + *
|
| + * <pre>
|
| + * unaryExpression ::=
|
| + * prefixOperator unaryExpression
|
| + * | awaitExpression
|
| + * | postfixExpression
|
| + * | unaryOperator 'super'
|
| + * | '-' 'super'
|
| + * | incrementOperator assignableExpression
|
| + * </pre>
|
| + *
|
| + * @return the unary expression that was parsed
|
| + */
|
| + Expression _parseUnaryExpression() {
|
| + if (_matches(TokenType.MINUS) || _matches(TokenType.BANG) || _matches(TokenType.TILDE)) {
|
| + Token operator = andAdvance;
|
| + if (_matchesKeyword(Keyword.SUPER)) {
|
| + if (_tokenMatches(_peek(), TokenType.OPEN_SQUARE_BRACKET) || _tokenMatches(_peek(), TokenType.PERIOD)) {
|
| + // "prefixOperator unaryExpression"
|
| + // --> "prefixOperator postfixExpression"
|
| + // --> "prefixOperator primary selector*"
|
| + // --> "prefixOperator 'super' assignableSelector selector*"
|
| + return new PrefixExpression(operator, _parseUnaryExpression());
|
| + }
|
| + return new PrefixExpression(operator, new SuperExpression(andAdvance));
|
| + }
|
| + return new PrefixExpression(operator, _parseUnaryExpression());
|
| + } else if (_currentToken.type.isIncrementOperator) {
|
| + Token operator = andAdvance;
|
| + if (_matchesKeyword(Keyword.SUPER)) {
|
| + if (_tokenMatches(_peek(), TokenType.OPEN_SQUARE_BRACKET) || _tokenMatches(_peek(), TokenType.PERIOD)) {
|
| + // --> "prefixOperator 'super' assignableSelector selector*"
|
| + return new PrefixExpression(operator, _parseUnaryExpression());
|
| + }
|
| + //
|
| + // Even though it is not valid to use an incrementing operator ('++' or '--') before 'super',
|
| + // we can (and therefore must) interpret "--super" as semantically equivalent to "-(-super)".
|
| + // Unfortunately, we cannot do the same for "++super" because "+super" is also not valid.
|
| + //
|
| + if (operator.type == TokenType.MINUS_MINUS) {
|
| + int offset = operator.offset;
|
| + Token firstOperator = new Token(TokenType.MINUS, offset);
|
| + Token secondOperator = new Token(TokenType.MINUS, offset + 1);
|
| + secondOperator.setNext(_currentToken);
|
| + firstOperator.setNext(secondOperator);
|
| + operator.previous.setNext(firstOperator);
|
| + return new PrefixExpression(firstOperator, new PrefixExpression(secondOperator, new SuperExpression(andAdvance)));
|
| + } else {
|
| + // Invalid operator before 'super'
|
| + _reportErrorForCurrentToken(ParserErrorCode.INVALID_OPERATOR_FOR_SUPER, [operator.lexeme]);
|
| + return new PrefixExpression(operator, new SuperExpression(andAdvance));
|
| + }
|
| + }
|
| + return new PrefixExpression(operator, _parseAssignableExpression(false));
|
| + } else if (_matches(TokenType.PLUS)) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.MISSING_IDENTIFIER, []);
|
| + return _createSyntheticIdentifier();
|
| + } else if (_inAsync && _matchesString(_AWAIT)) {
|
| + return _parseAwaitExpression();
|
| + }
|
| + return _parsePostfixExpression();
|
| + }
|
| +
|
| + /**
|
| + * Parse a variable declaration.
|
| + *
|
| + * <pre>
|
| + * variableDeclaration ::=
|
| + * identifier ('=' expression)?
|
| + * </pre>
|
| + *
|
| + * @return the variable declaration that was parsed
|
| + */
|
| + VariableDeclaration _parseVariableDeclaration() {
|
| + CommentAndMetadata commentAndMetadata = _parseCommentAndMetadata();
|
| + SimpleIdentifier name = parseSimpleIdentifier();
|
| + Token equals = null;
|
| + Expression initializer = null;
|
| + if (_matches(TokenType.EQ)) {
|
| + equals = andAdvance;
|
| + initializer = parseExpression2();
|
| + }
|
| + return new VariableDeclaration(commentAndMetadata.comment, commentAndMetadata.metadata, name, equals, initializer);
|
| + }
|
| +
|
| + /**
|
| + * Parse a variable declaration list.
|
| + *
|
| + * <pre>
|
| + * variableDeclarationList ::=
|
| + * finalConstVarOrType variableDeclaration (',' variableDeclaration)*
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the metadata to be associated with the variable declaration list
|
| + * @return the variable declaration list that was parsed
|
| + */
|
| + VariableDeclarationList _parseVariableDeclarationListAfterMetadata(CommentAndMetadata commentAndMetadata) {
|
| + FinalConstVarOrType holder = _parseFinalConstVarOrType(false);
|
| + return _parseVariableDeclarationListAfterType(commentAndMetadata, holder.keyword, holder.type);
|
| + }
|
| +
|
| + /**
|
| + * Parse a variable declaration list.
|
| + *
|
| + * <pre>
|
| + * variableDeclarationList ::=
|
| + * finalConstVarOrType variableDeclaration (',' variableDeclaration)*
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the metadata to be associated with the variable declaration list, or
|
| + * `null` if there is no attempt at parsing the comment and metadata
|
| + * @param keyword the token representing the 'final', 'const' or 'var' keyword, or `null` if
|
| + * there is no keyword
|
| + * @param type the type of the variables in the list
|
| + * @return the variable declaration list that was parsed
|
| + */
|
| + VariableDeclarationList _parseVariableDeclarationListAfterType(CommentAndMetadata commentAndMetadata, Token keyword, TypeName type) {
|
| + if (type != null && keyword != null && _tokenMatchesKeyword(keyword, Keyword.VAR)) {
|
| + _reportErrorForToken(ParserErrorCode.VAR_AND_TYPE, keyword, []);
|
| + }
|
| + List<VariableDeclaration> variables = new List<VariableDeclaration>();
|
| + variables.add(_parseVariableDeclaration());
|
| + while (_matches(TokenType.COMMA)) {
|
| + _advance();
|
| + variables.add(_parseVariableDeclaration());
|
| + }
|
| + return new VariableDeclarationList(commentAndMetadata != null ? commentAndMetadata.comment : null, commentAndMetadata != null ? commentAndMetadata.metadata : null, keyword, type, variables);
|
| + }
|
| +
|
| + /**
|
| + * Parse a variable declaration statement.
|
| + *
|
| + * <pre>
|
| + * variableDeclarationStatement ::=
|
| + * variableDeclarationList ';'
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the metadata to be associated with the variable declaration
|
| + * statement, or `null` if there is no attempt at parsing the comment and metadata
|
| + * @return the variable declaration statement that was parsed
|
| + */
|
| + VariableDeclarationStatement _parseVariableDeclarationStatementAfterMetadata(CommentAndMetadata commentAndMetadata) {
|
| + // Token startToken = currentToken;
|
| + VariableDeclarationList variableList = _parseVariableDeclarationListAfterMetadata(commentAndMetadata);
|
| + // if (!matches(TokenType.SEMICOLON)) {
|
| + // if (matches(startToken, Keyword.VAR) && isTypedIdentifier(startToken.getNext())) {
|
| + // // TODO(brianwilkerson) This appears to be of the form "var type variable". We should do
|
| + // // a better job of recovering in this case.
|
| + // }
|
| + // }
|
| + Token semicolon = _expect(TokenType.SEMICOLON);
|
| + return new VariableDeclarationStatement(variableList, semicolon);
|
| + }
|
| +
|
| + /**
|
| + * Parse a variable declaration statement.
|
| + *
|
| + * <pre>
|
| + * variableDeclarationStatement ::=
|
| + * variableDeclarationList ';'
|
| + * </pre>
|
| + *
|
| + * @param commentAndMetadata the metadata to be associated with the variable declaration
|
| + * statement, or `null` if there is no attempt at parsing the comment and metadata
|
| + * @param keyword the token representing the 'final', 'const' or 'var' keyword, or `null` if
|
| + * there is no keyword
|
| + * @param type the type of the variables in the list
|
| + * @return the variable declaration statement that was parsed
|
| + */
|
| + VariableDeclarationStatement _parseVariableDeclarationStatementAfterType(CommentAndMetadata commentAndMetadata, Token keyword, TypeName type) {
|
| + VariableDeclarationList variableList = _parseVariableDeclarationListAfterType(commentAndMetadata, keyword, type);
|
| + Token semicolon = _expect(TokenType.SEMICOLON);
|
| + return new VariableDeclarationStatement(variableList, semicolon);
|
| + }
|
| +
|
| + /**
|
| + * Parse a while statement.
|
| + *
|
| + * <pre>
|
| + * whileStatement ::=
|
| + * 'while' '(' expression ')' statement
|
| + * </pre>
|
| + *
|
| + * @return the while statement that was parsed
|
| + */
|
| + Statement _parseWhileStatement() {
|
| + bool wasInLoop = _inLoop;
|
| + _inLoop = true;
|
| + try {
|
| + Token keyword = _expectKeyword(Keyword.WHILE);
|
| + Token leftParenthesis = _expect(TokenType.OPEN_PAREN);
|
| + Expression condition = parseExpression2();
|
| + Token rightParenthesis = _expect(TokenType.CLOSE_PAREN);
|
| + Statement body = parseStatement2();
|
| + return new WhileStatement(keyword, leftParenthesis, condition, rightParenthesis, body);
|
| + } finally {
|
| + _inLoop = wasInLoop;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse a yield statement.
|
| + *
|
| + * <pre>
|
| + * yieldStatement ::=
|
| + * 'yield' '*'? expression ';'
|
| + * </pre>
|
| + *
|
| + * @return the yield statement that was parsed
|
| + */
|
| + YieldStatement _parseYieldStatement() {
|
| + Token yieldToken = andAdvance;
|
| + Token star = null;
|
| + if (_matches(TokenType.STAR)) {
|
| + star = andAdvance;
|
| + }
|
| + Expression expression = parseExpression2();
|
| + Token semicolon = _expect(TokenType.SEMICOLON);
|
| + return new YieldStatement(yieldToken, star, expression, semicolon);
|
| + }
|
| +
|
| + /**
|
| + * Return the token that is immediately after the current token. This is equivalent to
|
| + * [peekAt].
|
| + *
|
| + * @return the token that is immediately after the current token
|
| + */
|
| + Token _peek() => _currentToken.next;
|
| +
|
| + /**
|
| + * Return the token that is the given distance after the current token.
|
| + *
|
| + * @param distance the number of tokens to look ahead, where `0` is the current token,
|
| + * `1` is the next token, etc.
|
| + * @return the token that is the given distance after the current token
|
| + */
|
| + Token _peekAt(int distance) {
|
| + Token token = _currentToken;
|
| + for (int i = 0; i < distance; i++) {
|
| + token = token.next;
|
| + }
|
| + return token;
|
| + }
|
| +
|
| + /**
|
| + * Report the given [AnalysisError].
|
| + *
|
| + * @param error the error to be reported
|
| + */
|
| + void _reportError(AnalysisError error) {
|
| + if (_errorListenerLock != 0) {
|
| + return;
|
| + }
|
| + _errorListener.onError(error);
|
| + }
|
| +
|
| + /**
|
| + * Report an error with the given error code and arguments.
|
| + *
|
| + * @param errorCode the error code of the error to be reported
|
| + * @param arguments the arguments to the error, used to compose the error message
|
| + */
|
| + void _reportErrorForCurrentToken(ParserErrorCode errorCode, List<Object> arguments) {
|
| + _reportErrorForToken(errorCode, _currentToken, arguments);
|
| + }
|
| +
|
| + /**
|
| + * Report an error with the given error code and arguments.
|
| + *
|
| + * @param errorCode the error code of the error to be reported
|
| + * @param node the node specifying the location of the error
|
| + * @param arguments the arguments to the error, used to compose the error message
|
| + */
|
| + void _reportErrorForNode(ParserErrorCode errorCode, AstNode node, List<Object> arguments) {
|
| + _reportError(new AnalysisError.con2(_source, node.offset, node.length, errorCode, arguments));
|
| + }
|
| +
|
| + /**
|
| + * Report an error with the given error code and arguments.
|
| + *
|
| + * @param errorCode the error code of the error to be reported
|
| + * @param token the token specifying the location of the error
|
| + * @param arguments the arguments to the error, used to compose the error message
|
| + */
|
| + void _reportErrorForToken(ParserErrorCode errorCode, Token token, List<Object> arguments) {
|
| + if (token.type == TokenType.EOF) {
|
| + token = token.previous;
|
| + }
|
| + _reportError(new AnalysisError.con2(_source, token.offset, Math.max(token.length, 1), errorCode, arguments));
|
| + }
|
| +
|
| + /**
|
| + * Skips a block with all containing blocks.
|
| + */
|
| + void _skipBlock() {
|
| + Token endToken = (_currentToken as BeginToken).endToken;
|
| + if (endToken == null) {
|
| + endToken = _currentToken.next;
|
| + while (!identical(endToken, _currentToken)) {
|
| + _currentToken = endToken;
|
| + endToken = _currentToken.next;
|
| + }
|
| + _reportErrorForToken(ParserErrorCode.EXPECTED_TOKEN, _currentToken.previous, ["}"]);
|
| + } else {
|
| + _currentToken = endToken.next;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse the 'final', 'const', 'var' or type preceding a variable declaration, starting at the
|
| + * given token, without actually creating a type or changing the current token. Return the token
|
| + * following the type that was parsed, or `null` if the given token is not the first token
|
| + * in a valid type.
|
| + *
|
| + * <pre>
|
| + * finalConstVarOrType ::=
|
| + * | 'final' type?
|
| + * | 'const' type?
|
| + * | 'var'
|
| + * | type
|
| + * </pre>
|
| + *
|
| + * @param startToken the token at which parsing is to begin
|
| + * @return the token following the type that was parsed
|
| + */
|
| + Token _skipFinalConstVarOrType(Token startToken) {
|
| + if (_tokenMatchesKeyword(startToken, Keyword.FINAL) || _tokenMatchesKeyword(startToken, Keyword.CONST)) {
|
| + Token next = startToken.next;
|
| + if (_tokenMatchesIdentifier(next)) {
|
| + Token next2 = next.next;
|
| + // "Type parameter" or "Type<" or "prefix.Type"
|
| + if (_tokenMatchesIdentifier(next2) || _tokenMatches(next2, TokenType.LT) || _tokenMatches(next2, TokenType.PERIOD)) {
|
| + return _skipTypeName(next);
|
| + }
|
| + // "parameter"
|
| + return next;
|
| + }
|
| + } else if (_tokenMatchesKeyword(startToken, Keyword.VAR)) {
|
| + return startToken.next;
|
| + } else if (_tokenMatchesIdentifier(startToken)) {
|
| + Token next = startToken.next;
|
| + if (_tokenMatchesIdentifier(next) || _tokenMatches(next, TokenType.LT) || _tokenMatchesKeyword(next, Keyword.THIS) || (_tokenMatches(next, TokenType.PERIOD) && _tokenMatchesIdentifier(next.next) && (_tokenMatchesIdentifier(next.next.next) || _tokenMatches(next.next.next, TokenType.LT) || _tokenMatchesKeyword(next.next.next, Keyword.THIS)))) {
|
| + return _skipReturnType(startToken);
|
| + }
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * Parse a list of formal parameters, starting at the given token, without actually creating a
|
| + * formal parameter list or changing the current token. Return the token following the formal
|
| + * parameter list that was parsed, or `null` if the given token is not the first token in a
|
| + * valid list of formal parameter.
|
| + *
|
| + * Note that unlike other skip methods, this method uses a heuristic. In the worst case, the
|
| + * parameters could be prefixed by metadata, which would require us to be able to skip arbitrary
|
| + * expressions. Rather than duplicate the logic of most of the parse methods we simply look for
|
| + * something that is likely to be a list of parameters and then skip to returning the token after
|
| + * the closing parenthesis.
|
| + *
|
| + * This method must be kept in sync with [parseFormalParameterList].
|
| + *
|
| + * <pre>
|
| + * formalParameterList ::=
|
| + * '(' ')'
|
| + * | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
|
| + * | '(' optionalFormalParameters ')'
|
| + *
|
| + * normalFormalParameters ::=
|
| + * normalFormalParameter (',' normalFormalParameter)*
|
| + *
|
| + * optionalFormalParameters ::=
|
| + * optionalPositionalFormalParameters
|
| + * | namedFormalParameters
|
| + *
|
| + * optionalPositionalFormalParameters ::=
|
| + * '[' defaultFormalParameter (',' defaultFormalParameter)* ']'
|
| + *
|
| + * namedFormalParameters ::=
|
| + * '{' defaultNamedParameter (',' defaultNamedParameter)* '}'
|
| + * </pre>
|
| + *
|
| + * @param startToken the token at which parsing is to begin
|
| + * @return the token following the formal parameter list that was parsed
|
| + */
|
| + Token _skipFormalParameterList(Token startToken) {
|
| + if (!_tokenMatches(startToken, TokenType.OPEN_PAREN)) {
|
| + return null;
|
| + }
|
| + Token next = startToken.next;
|
| + if (_tokenMatches(next, TokenType.CLOSE_PAREN)) {
|
| + return next.next;
|
| + }
|
| + //
|
| + // Look to see whether the token after the open parenthesis is something that should only occur
|
| + // at the beginning of a parameter list.
|
| + //
|
| + if (next.matchesAny([
|
| + TokenType.AT,
|
| + TokenType.OPEN_SQUARE_BRACKET,
|
| + TokenType.OPEN_CURLY_BRACKET]) || _tokenMatchesKeyword(next, Keyword.VOID) || (_tokenMatchesIdentifier(next) && (next.next.matchesAny([TokenType.COMMA, TokenType.CLOSE_PAREN])))) {
|
| + return _skipPastMatchingToken(startToken);
|
| + }
|
| + //
|
| + // Look to see whether the first parameter is a function typed parameter without a return type.
|
| + //
|
| + if (_tokenMatchesIdentifier(next) && _tokenMatches(next.next, TokenType.OPEN_PAREN)) {
|
| + Token afterParameters = _skipFormalParameterList(next.next);
|
| + if (afterParameters != null && (afterParameters.matchesAny([TokenType.COMMA, TokenType.CLOSE_PAREN]))) {
|
| + return _skipPastMatchingToken(startToken);
|
| + }
|
| + }
|
| + //
|
| + // Look to see whether the first parameter has a type or is a function typed parameter with a
|
| + // return type.
|
| + //
|
| + Token afterType = _skipFinalConstVarOrType(next);
|
| + if (afterType == null) {
|
| + return null;
|
| + }
|
| + if (_skipSimpleIdentifier(afterType) == null) {
|
| + return null;
|
| + }
|
| + return _skipPastMatchingToken(startToken);
|
| + }
|
| +
|
| + /**
|
| + * If the given token is a begin token with an associated end token, then return the token
|
| + * following the end token. Otherwise, return `null`.
|
| + *
|
| + * @param startToken the token that is assumed to be a being token
|
| + * @return the token following the matching end token
|
| + */
|
| + Token _skipPastMatchingToken(Token startToken) {
|
| + if (startToken is! BeginToken) {
|
| + return null;
|
| + }
|
| + Token closeParen = (startToken as BeginToken).endToken;
|
| + if (closeParen == null) {
|
| + return null;
|
| + }
|
| + return closeParen.next;
|
| + }
|
| +
|
| + /**
|
| + * Parse a prefixed identifier, starting at the given token, without actually creating a prefixed
|
| + * identifier or changing the current token. Return the token following the prefixed identifier
|
| + * that was parsed, or `null` if the given token is not the first token in a valid prefixed
|
| + * identifier.
|
| + *
|
| + * This method must be kept in sync with [parsePrefixedIdentifier].
|
| + *
|
| + * <pre>
|
| + * prefixedIdentifier ::=
|
| + * identifier ('.' identifier)?
|
| + * </pre>
|
| + *
|
| + * @param startToken the token at which parsing is to begin
|
| + * @return the token following the prefixed identifier that was parsed
|
| + */
|
| + Token _skipPrefixedIdentifier(Token startToken) {
|
| + Token token = _skipSimpleIdentifier(startToken);
|
| + if (token == null) {
|
| + return null;
|
| + } else if (!_tokenMatches(token, TokenType.PERIOD)) {
|
| + return token;
|
| + }
|
| + return _skipSimpleIdentifier(token.next);
|
| + }
|
| +
|
| + /**
|
| + * Parse a return type, starting at the given token, without actually creating a return type or
|
| + * changing the current token. Return the token following the return type that was parsed, or
|
| + * `null` if the given token is not the first token in a valid return type.
|
| + *
|
| + * This method must be kept in sync with [parseReturnType].
|
| + *
|
| + * <pre>
|
| + * returnType ::=
|
| + * 'void'
|
| + * | type
|
| + * </pre>
|
| + *
|
| + * @param startToken the token at which parsing is to begin
|
| + * @return the token following the return type that was parsed
|
| + */
|
| + Token _skipReturnType(Token startToken) {
|
| + if (_tokenMatchesKeyword(startToken, Keyword.VOID)) {
|
| + return startToken.next;
|
| + } else {
|
| + return _skipTypeName(startToken);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Parse a simple identifier, starting at the given token, without actually creating a simple
|
| + * identifier or changing the current token. Return the token following the simple identifier that
|
| + * was parsed, or `null` if the given token is not the first token in a valid simple
|
| + * identifier.
|
| + *
|
| + * This method must be kept in sync with [parseSimpleIdentifier].
|
| + *
|
| + * <pre>
|
| + * identifier ::=
|
| + * IDENTIFIER
|
| + * </pre>
|
| + *
|
| + * @param startToken the token at which parsing is to begin
|
| + * @return the token following the simple identifier that was parsed
|
| + */
|
| + Token _skipSimpleIdentifier(Token startToken) {
|
| + if (_tokenMatches(startToken, TokenType.IDENTIFIER) || (_tokenMatches(startToken, TokenType.KEYWORD) && (startToken as KeywordToken).keyword.isPseudoKeyword)) {
|
| + return startToken.next;
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * Parse a string literal that contains interpolations, starting at the given token, without
|
| + * actually creating a string literal or changing the current token. Return the token following
|
| + * the string literal that was parsed, or `null` if the given token is not the first token
|
| + * in a valid string literal.
|
| + *
|
| + * This method must be kept in sync with [parseStringInterpolation].
|
| + *
|
| + * @param startToken the token at which parsing is to begin
|
| + * @return the string literal that was parsed
|
| + */
|
| + Token _skipStringInterpolation(Token startToken) {
|
| + Token token = startToken;
|
| + TokenType type = token.type;
|
| + while (type == TokenType.STRING_INTERPOLATION_EXPRESSION || type == TokenType.STRING_INTERPOLATION_IDENTIFIER) {
|
| + if (type == TokenType.STRING_INTERPOLATION_EXPRESSION) {
|
| + token = token.next;
|
| + type = token.type;
|
| + //
|
| + // Rather than verify that the following tokens represent a valid expression, we simply skip
|
| + // tokens until we reach the end of the interpolation, being careful to handle nested string
|
| + // literals.
|
| + //
|
| + int bracketNestingLevel = 1;
|
| + while (bracketNestingLevel > 0) {
|
| + if (type == TokenType.EOF) {
|
| + return null;
|
| + } else if (type == TokenType.OPEN_CURLY_BRACKET) {
|
| + bracketNestingLevel++;
|
| + } else if (type == TokenType.CLOSE_CURLY_BRACKET) {
|
| + bracketNestingLevel--;
|
| + } else if (type == TokenType.STRING) {
|
| + token = _skipStringLiteral(token);
|
| + if (token == null) {
|
| + return null;
|
| + }
|
| + } else {
|
| + token = token.next;
|
| + }
|
| + type = token.type;
|
| + }
|
| + token = token.next;
|
| + type = token.type;
|
| + } else {
|
| + token = token.next;
|
| + if (token.type != TokenType.IDENTIFIER) {
|
| + return null;
|
| + }
|
| + token = token.next;
|
| + }
|
| + type = token.type;
|
| + if (type == TokenType.STRING) {
|
| + token = token.next;
|
| + type = token.type;
|
| + }
|
| + }
|
| + return token;
|
| + }
|
| +
|
| + /**
|
| + * Parse a string literal, starting at the given token, without actually creating a string literal
|
| + * or changing the current token. Return the token following the string literal that was parsed,
|
| + * or `null` if the given token is not the first token in a valid string literal.
|
| + *
|
| + * This method must be kept in sync with [parseStringLiteral].
|
| + *
|
| + * <pre>
|
| + * stringLiteral ::=
|
| + * MULTI_LINE_STRING+
|
| + * | SINGLE_LINE_STRING+
|
| + * </pre>
|
| + *
|
| + * @param startToken the token at which parsing is to begin
|
| + * @return the token following the string literal that was parsed
|
| + */
|
| + Token _skipStringLiteral(Token startToken) {
|
| + Token token = startToken;
|
| + while (token != null && _tokenMatches(token, TokenType.STRING)) {
|
| + token = token.next;
|
| + TokenType type = token.type;
|
| + if (type == TokenType.STRING_INTERPOLATION_EXPRESSION || type == TokenType.STRING_INTERPOLATION_IDENTIFIER) {
|
| + token = _skipStringInterpolation(token);
|
| + }
|
| + }
|
| + if (identical(token, startToken)) {
|
| + return null;
|
| + }
|
| + return token;
|
| + }
|
| +
|
| + /**
|
| + * Parse a list of type arguments, starting at the given token, without actually creating a type argument list
|
| + * or changing the current token. Return the token following the type argument list that was parsed,
|
| + * or `null` if the given token is not the first token in a valid type argument list.
|
| + *
|
| + * This method must be kept in sync with [parseTypeArgumentList].
|
| + *
|
| + * <pre>
|
| + * typeArguments ::=
|
| + * '<' typeList '>'
|
| + *
|
| + * typeList ::=
|
| + * type (',' type)*
|
| + * </pre>
|
| + *
|
| + * @param startToken the token at which parsing is to begin
|
| + * @return the token following the type argument list that was parsed
|
| + */
|
| + Token _skipTypeArgumentList(Token startToken) {
|
| + Token token = startToken;
|
| + if (!_tokenMatches(token, TokenType.LT)) {
|
| + return null;
|
| + }
|
| + token = _skipTypeName(token.next);
|
| + if (token == null) {
|
| + return null;
|
| + }
|
| + while (_tokenMatches(token, TokenType.COMMA)) {
|
| + token = _skipTypeName(token.next);
|
| + if (token == null) {
|
| + return null;
|
| + }
|
| + }
|
| + if (token.type == TokenType.GT) {
|
| + return token.next;
|
| + } else if (token.type == TokenType.GT_GT) {
|
| + Token second = new Token(TokenType.GT, token.offset + 1);
|
| + second.setNextWithoutSettingPrevious(token.next);
|
| + return second;
|
| + }
|
| + return null;
|
| + }
|
| +
|
| + /**
|
| + * Parse a type name, starting at the given token, without actually creating a type name or
|
| + * changing the current token. Return the token following the type name that was parsed, or
|
| + * `null` if the given token is not the first token in a valid type name.
|
| + *
|
| + * This method must be kept in sync with [parseTypeName].
|
| + *
|
| + * <pre>
|
| + * type ::=
|
| + * qualified typeArguments?
|
| + * </pre>
|
| + *
|
| + * @param startToken the token at which parsing is to begin
|
| + * @return the token following the type name that was parsed
|
| + */
|
| + Token _skipTypeName(Token startToken) {
|
| + Token token = _skipPrefixedIdentifier(startToken);
|
| + if (token == null) {
|
| + return null;
|
| + }
|
| + if (_tokenMatches(token, TokenType.LT)) {
|
| + token = _skipTypeArgumentList(token);
|
| + }
|
| + return token;
|
| + }
|
| +
|
| + /**
|
| + * Parse a list of type parameters, starting at the given token, without actually creating a type
|
| + * parameter list or changing the current token. Return the token following the type parameter
|
| + * list that was parsed, or `null` if the given token is not the first token in a valid type
|
| + * parameter list.
|
| + *
|
| + * This method must be kept in sync with [parseTypeParameterList].
|
| + *
|
| + * <pre>
|
| + * typeParameterList ::=
|
| + * '<' typeParameter (',' typeParameter)* '>'
|
| + * </pre>
|
| + *
|
| + * @param startToken the token at which parsing is to begin
|
| + * @return the token following the type parameter list that was parsed
|
| + */
|
| + Token _skipTypeParameterList(Token startToken) {
|
| + if (!_tokenMatches(startToken, TokenType.LT)) {
|
| + return null;
|
| + }
|
| + //
|
| + // We can't skip a type parameter because it can be preceeded by metadata, so we just assume
|
| + // that everything before the matching end token is valid.
|
| + //
|
| + int depth = 1;
|
| + Token next = startToken.next;
|
| + while (depth > 0) {
|
| + if (_tokenMatches(next, TokenType.EOF)) {
|
| + return null;
|
| + } else if (_tokenMatches(next, TokenType.LT)) {
|
| + depth++;
|
| + } else if (_tokenMatches(next, TokenType.GT)) {
|
| + depth--;
|
| + } else if (_tokenMatches(next, TokenType.GT_EQ)) {
|
| + if (depth == 1) {
|
| + Token fakeEquals = new Token(TokenType.EQ, next.offset + 2);
|
| + fakeEquals.setNextWithoutSettingPrevious(next.next);
|
| + return fakeEquals;
|
| + }
|
| + depth--;
|
| + } else if (_tokenMatches(next, TokenType.GT_GT)) {
|
| + depth -= 2;
|
| + } else if (_tokenMatches(next, TokenType.GT_GT_EQ)) {
|
| + if (depth < 2) {
|
| + return null;
|
| + } else if (depth == 2) {
|
| + Token fakeEquals = new Token(TokenType.EQ, next.offset + 2);
|
| + fakeEquals.setNextWithoutSettingPrevious(next.next);
|
| + return fakeEquals;
|
| + }
|
| + depth -= 2;
|
| + }
|
| + next = next.next;
|
| + }
|
| + return next;
|
| + }
|
| +
|
| + /**
|
| + * Return `true` if the given token has the given type.
|
| + *
|
| + * @param token the token being tested
|
| + * @param type the type of token that is being tested for
|
| + * @return `true` if the given token has the given type
|
| + */
|
| + bool _tokenMatches(Token token, TokenType type) => token.type == type;
|
| +
|
| + /**
|
| + * Return `true` if the given token is a valid identifier. Valid identifiers include
|
| + * built-in identifiers (pseudo-keywords).
|
| + *
|
| + * @return `true` if the given token is a valid identifier
|
| + */
|
| + bool _tokenMatchesIdentifier(Token token) => _tokenMatches(token, TokenType.IDENTIFIER) || (_tokenMatches(token, TokenType.KEYWORD) && (token as KeywordToken).keyword.isPseudoKeyword);
|
| +
|
| + /**
|
| + * Return `true` if the given token matches the given keyword.
|
| + *
|
| + * @param token the token being tested
|
| + * @param keyword the keyword that is being tested for
|
| + * @return `true` if the given token matches the given keyword
|
| + */
|
| + bool _tokenMatchesKeyword(Token token, Keyword keyword) => token.type == TokenType.KEYWORD && (token as KeywordToken).keyword == keyword;
|
| +
|
| + /**
|
| + * Return `true` if the given token matches the given identifier.
|
| + *
|
| + * @param token the token being tested
|
| + * @param identifier the identifier that can optionally appear in the current location
|
| + * @return `true` if the current token matches the given identifier
|
| + */
|
| + bool _tokenMatchesString(Token token, String identifier) => token.type == TokenType.IDENTIFIER && token.lexeme == identifier;
|
| +
|
| + /**
|
| + * Translate the characters at the given index in the given string, appending the translated
|
| + * character to the given builder. The index is assumed to be valid.
|
| + *
|
| + * @param builder the builder to which the translated character is to be appended
|
| + * @param lexeme the string containing the character(s) to be translated
|
| + * @param index the index of the character to be translated
|
| + * @return the index of the next character to be translated
|
| + */
|
| + int _translateCharacter(JavaStringBuilder builder, String lexeme, int index) {
|
| + int currentChar = lexeme.codeUnitAt(index);
|
| + if (currentChar != 0x5C) {
|
| + builder.appendChar(currentChar);
|
| + return index + 1;
|
| + }
|
| + //
|
| + // We have found an escape sequence, so we parse the string to determine what kind of escape
|
| + // sequence and what character to add to the builder.
|
| + //
|
| + int length = lexeme.length;
|
| + int currentIndex = index + 1;
|
| + if (currentIndex >= length) {
|
| + // Illegal escape sequence: no char after escape
|
| + // This cannot actually happen because it would require the escape character to be the last
|
| + // character in the string, but if it were it would escape the closing quote, leaving the
|
| + // string unclosed.
|
| + // reportError(ParserErrorCode.MISSING_CHAR_IN_ESCAPE_SEQUENCE);
|
| + return length;
|
| + }
|
| + currentChar = lexeme.codeUnitAt(currentIndex);
|
| + if (currentChar == 0x6E) {
|
| + builder.appendChar(0xA);
|
| + } else if (currentChar == 0x72) {
|
| + builder.appendChar(0xD);
|
| + } else if (currentChar == 0x66) {
|
| + builder.appendChar(0xC);
|
| + } else if (currentChar == 0x62) {
|
| + builder.appendChar(0x8);
|
| + } else if (currentChar == 0x74) {
|
| + builder.appendChar(0x9);
|
| + } else if (currentChar == 0x76) {
|
| + builder.appendChar(0xB);
|
| + } else if (currentChar == 0x78) {
|
| + if (currentIndex + 2 >= length) {
|
| + // Illegal escape sequence: not enough hex digits
|
| + _reportErrorForCurrentToken(ParserErrorCode.INVALID_HEX_ESCAPE, []);
|
| + return length;
|
| + }
|
| + int firstDigit = lexeme.codeUnitAt(currentIndex + 1);
|
| + int secondDigit = lexeme.codeUnitAt(currentIndex + 2);
|
| + if (!_isHexDigit(firstDigit) || !_isHexDigit(secondDigit)) {
|
| + // Illegal escape sequence: invalid hex digit
|
| + _reportErrorForCurrentToken(ParserErrorCode.INVALID_HEX_ESCAPE, []);
|
| + } else {
|
| + builder.appendChar(((Character.digit(firstDigit, 16) << 4) + Character.digit(secondDigit, 16)));
|
| + }
|
| + return currentIndex + 3;
|
| + } else if (currentChar == 0x75) {
|
| + currentIndex++;
|
| + if (currentIndex >= length) {
|
| + // Illegal escape sequence: not enough hex digits
|
| + _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
|
| + return length;
|
| + }
|
| + currentChar = lexeme.codeUnitAt(currentIndex);
|
| + if (currentChar == 0x7B) {
|
| + currentIndex++;
|
| + if (currentIndex >= length) {
|
| + // Illegal escape sequence: incomplete escape
|
| + _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
|
| + return length;
|
| + }
|
| + currentChar = lexeme.codeUnitAt(currentIndex);
|
| + int digitCount = 0;
|
| + int value = 0;
|
| + while (currentChar != 0x7D) {
|
| + if (!_isHexDigit(currentChar)) {
|
| + // Illegal escape sequence: invalid hex digit
|
| + _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
|
| + currentIndex++;
|
| + while (currentIndex < length && lexeme.codeUnitAt(currentIndex) != 0x7D) {
|
| + currentIndex++;
|
| + }
|
| + return currentIndex + 1;
|
| + }
|
| + digitCount++;
|
| + value = (value << 4) + Character.digit(currentChar, 16);
|
| + currentIndex++;
|
| + if (currentIndex >= length) {
|
| + // Illegal escape sequence: incomplete escape
|
| + _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
|
| + return length;
|
| + }
|
| + currentChar = lexeme.codeUnitAt(currentIndex);
|
| + }
|
| + if (digitCount < 1 || digitCount > 6) {
|
| + // Illegal escape sequence: not enough or too many hex digits
|
| + _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
|
| + }
|
| + _appendScalarValue(builder, lexeme.substring(index, currentIndex + 1), value, index, currentIndex);
|
| + return currentIndex + 1;
|
| + } else {
|
| + if (currentIndex + 3 >= length) {
|
| + // Illegal escape sequence: not enough hex digits
|
| + _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
|
| + return length;
|
| + }
|
| + int firstDigit = currentChar;
|
| + int secondDigit = lexeme.codeUnitAt(currentIndex + 1);
|
| + int thirdDigit = lexeme.codeUnitAt(currentIndex + 2);
|
| + int fourthDigit = lexeme.codeUnitAt(currentIndex + 3);
|
| + if (!_isHexDigit(firstDigit) || !_isHexDigit(secondDigit) || !_isHexDigit(thirdDigit) || !_isHexDigit(fourthDigit)) {
|
| + // Illegal escape sequence: invalid hex digits
|
| + _reportErrorForCurrentToken(ParserErrorCode.INVALID_UNICODE_ESCAPE, []);
|
| + } else {
|
| + _appendScalarValue(builder, lexeme.substring(index, currentIndex + 1), (((((Character.digit(firstDigit, 16) << 4) + Character.digit(secondDigit, 16)) << 4) + Character.digit(thirdDigit, 16)) << 4) + Character.digit(fourthDigit, 16), index, currentIndex + 3);
|
| + }
|
| + return currentIndex + 4;
|
| + }
|
| + } else {
|
| + builder.appendChar(currentChar);
|
| + }
|
| + return currentIndex + 1;
|
| + }
|
| +
|
| + /**
|
| + * Decrements the error reporting lock level. If level is more than `0`, then
|
| + * [reportError] wont report any error.
|
| + */
|
| + void _unlockErrorListener() {
|
| + if (_errorListenerLock == 0) {
|
| + throw new IllegalStateException("Attempt to unlock not locked error listener.");
|
| + }
|
| + _errorListenerLock--;
|
| + }
|
| +
|
| + /**
|
| + * Validate that the given parameter list does not contain any field initializers.
|
| + *
|
| + * @param parameterList the parameter list to be validated
|
| + */
|
| + void _validateFormalParameterList(FormalParameterList parameterList) {
|
| + for (FormalParameter parameter in parameterList.parameters) {
|
| + if (parameter is FieldFormalParameter) {
|
| + _reportErrorForNode(ParserErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR, parameter.identifier, []);
|
| + }
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Validate that the given set of modifiers is appropriate for a class and return the 'abstract'
|
| + * keyword if there is one.
|
| + *
|
| + * @param modifiers the modifiers being validated
|
| + */
|
| + Token _validateModifiersForClass(Modifiers modifiers) {
|
| + _validateModifiersForTopLevelDeclaration(modifiers);
|
| + if (modifiers.constKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.CONST_CLASS, modifiers.constKeyword, []);
|
| + }
|
| + if (modifiers.externalKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.EXTERNAL_CLASS, modifiers.externalKeyword, []);
|
| + }
|
| + if (modifiers.finalKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.FINAL_CLASS, modifiers.finalKeyword, []);
|
| + }
|
| + if (modifiers.varKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.VAR_CLASS, modifiers.varKeyword, []);
|
| + }
|
| + return modifiers.abstractKeyword;
|
| + }
|
| +
|
| + /**
|
| + * Validate that the given set of modifiers is appropriate for a constructor and return the
|
| + * 'const' keyword if there is one.
|
| + *
|
| + * @param modifiers the modifiers being validated
|
| + * @return the 'const' or 'final' keyword associated with the constructor
|
| + */
|
| + Token _validateModifiersForConstructor(Modifiers modifiers) {
|
| + if (modifiers.abstractKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.ABSTRACT_CLASS_MEMBER, modifiers.abstractKeyword, []);
|
| + }
|
| + if (modifiers.finalKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.FINAL_CONSTRUCTOR, modifiers.finalKeyword, []);
|
| + }
|
| + if (modifiers.staticKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.STATIC_CONSTRUCTOR, modifiers.staticKeyword, []);
|
| + }
|
| + if (modifiers.varKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.CONSTRUCTOR_WITH_RETURN_TYPE, modifiers.varKeyword, []);
|
| + }
|
| + Token externalKeyword = modifiers.externalKeyword;
|
| + Token constKeyword = modifiers.constKeyword;
|
| + Token factoryKeyword = modifiers.factoryKeyword;
|
| + if (externalKeyword != null && constKeyword != null && constKeyword.offset < externalKeyword.offset) {
|
| + _reportErrorForToken(ParserErrorCode.EXTERNAL_AFTER_CONST, externalKeyword, []);
|
| + }
|
| + if (externalKeyword != null && factoryKeyword != null && factoryKeyword.offset < externalKeyword.offset) {
|
| + _reportErrorForToken(ParserErrorCode.EXTERNAL_AFTER_FACTORY, externalKeyword, []);
|
| + }
|
| + return constKeyword;
|
| + }
|
| +
|
| + /**
|
| + * Validate that the given set of modifiers is appropriate for a class and return the 'abstract'
|
| + * keyword if there is one.
|
| + *
|
| + * @param modifiers the modifiers being validated
|
| + */
|
| + void _validateModifiersForEnum(Modifiers modifiers) {
|
| + _validateModifiersForTopLevelDeclaration(modifiers);
|
| + if (modifiers.abstractKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.ABSTRACT_ENUM, modifiers.abstractKeyword, []);
|
| + }
|
| + if (modifiers.constKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.CONST_ENUM, modifiers.constKeyword, []);
|
| + }
|
| + if (modifiers.externalKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.EXTERNAL_ENUM, modifiers.externalKeyword, []);
|
| + }
|
| + if (modifiers.finalKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.FINAL_ENUM, modifiers.finalKeyword, []);
|
| + }
|
| + if (modifiers.varKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.VAR_ENUM, modifiers.varKeyword, []);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Validate that the given set of modifiers is appropriate for a field and return the 'final',
|
| + * 'const' or 'var' keyword if there is one.
|
| + *
|
| + * @param modifiers the modifiers being validated
|
| + * @return the 'final', 'const' or 'var' keyword associated with the field
|
| + */
|
| + Token _validateModifiersForField(Modifiers modifiers) {
|
| + if (modifiers.abstractKeyword != null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []);
|
| + }
|
| + if (modifiers.externalKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.EXTERNAL_FIELD, modifiers.externalKeyword, []);
|
| + }
|
| + if (modifiers.factoryKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKeyword, []);
|
| + }
|
| + Token staticKeyword = modifiers.staticKeyword;
|
| + Token constKeyword = modifiers.constKeyword;
|
| + Token finalKeyword = modifiers.finalKeyword;
|
| + Token varKeyword = modifiers.varKeyword;
|
| + if (constKeyword != null) {
|
| + if (finalKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.CONST_AND_FINAL, finalKeyword, []);
|
| + }
|
| + if (varKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.CONST_AND_VAR, varKeyword, []);
|
| + }
|
| + if (staticKeyword != null && constKeyword.offset < staticKeyword.offset) {
|
| + _reportErrorForToken(ParserErrorCode.STATIC_AFTER_CONST, staticKeyword, []);
|
| + }
|
| + } else if (finalKeyword != null) {
|
| + if (varKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.FINAL_AND_VAR, varKeyword, []);
|
| + }
|
| + if (staticKeyword != null && finalKeyword.offset < staticKeyword.offset) {
|
| + _reportErrorForToken(ParserErrorCode.STATIC_AFTER_FINAL, staticKeyword, []);
|
| + }
|
| + } else if (varKeyword != null && staticKeyword != null && varKeyword.offset < staticKeyword.offset) {
|
| + _reportErrorForToken(ParserErrorCode.STATIC_AFTER_VAR, staticKeyword, []);
|
| + }
|
| + return _lexicallyFirst([constKeyword, finalKeyword, varKeyword]);
|
| + }
|
| +
|
| + /**
|
| + * Validate that the given set of modifiers is appropriate for a local function.
|
| + *
|
| + * @param modifiers the modifiers being validated
|
| + */
|
| + void _validateModifiersForFunctionDeclarationStatement(Modifiers modifiers) {
|
| + if (modifiers.abstractKeyword != null || modifiers.constKeyword != null || modifiers.externalKeyword != null || modifiers.factoryKeyword != null || modifiers.finalKeyword != null || modifiers.staticKeyword != null || modifiers.varKeyword != null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.LOCAL_FUNCTION_DECLARATION_MODIFIER, []);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Validate that the given set of modifiers is appropriate for a getter, setter, or method.
|
| + *
|
| + * @param modifiers the modifiers being validated
|
| + */
|
| + void _validateModifiersForGetterOrSetterOrMethod(Modifiers modifiers) {
|
| + if (modifiers.abstractKeyword != null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []);
|
| + }
|
| + if (modifiers.constKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.CONST_METHOD, modifiers.constKeyword, []);
|
| + }
|
| + if (modifiers.factoryKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKeyword, []);
|
| + }
|
| + if (modifiers.finalKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.FINAL_METHOD, modifiers.finalKeyword, []);
|
| + }
|
| + if (modifiers.varKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword, []);
|
| + }
|
| + Token externalKeyword = modifiers.externalKeyword;
|
| + Token staticKeyword = modifiers.staticKeyword;
|
| + if (externalKeyword != null && staticKeyword != null && staticKeyword.offset < externalKeyword.offset) {
|
| + _reportErrorForToken(ParserErrorCode.EXTERNAL_AFTER_STATIC, externalKeyword, []);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Validate that the given set of modifiers is appropriate for a getter, setter, or method.
|
| + *
|
| + * @param modifiers the modifiers being validated
|
| + */
|
| + void _validateModifiersForOperator(Modifiers modifiers) {
|
| + if (modifiers.abstractKeyword != null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.ABSTRACT_CLASS_MEMBER, []);
|
| + }
|
| + if (modifiers.constKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.CONST_METHOD, modifiers.constKeyword, []);
|
| + }
|
| + if (modifiers.factoryKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.NON_CONSTRUCTOR_FACTORY, modifiers.factoryKeyword, []);
|
| + }
|
| + if (modifiers.finalKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.FINAL_METHOD, modifiers.finalKeyword, []);
|
| + }
|
| + if (modifiers.staticKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.STATIC_OPERATOR, modifiers.staticKeyword, []);
|
| + }
|
| + if (modifiers.varKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword, []);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Validate that the given set of modifiers is appropriate for a top-level declaration.
|
| + *
|
| + * @param modifiers the modifiers being validated
|
| + */
|
| + void _validateModifiersForTopLevelDeclaration(Modifiers modifiers) {
|
| + if (modifiers.factoryKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.FACTORY_TOP_LEVEL_DECLARATION, modifiers.factoryKeyword, []);
|
| + }
|
| + if (modifiers.staticKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.STATIC_TOP_LEVEL_DECLARATION, modifiers.staticKeyword, []);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Validate that the given set of modifiers is appropriate for a top-level function.
|
| + *
|
| + * @param modifiers the modifiers being validated
|
| + */
|
| + void _validateModifiersForTopLevelFunction(Modifiers modifiers) {
|
| + _validateModifiersForTopLevelDeclaration(modifiers);
|
| + if (modifiers.abstractKeyword != null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.ABSTRACT_TOP_LEVEL_FUNCTION, []);
|
| + }
|
| + if (modifiers.constKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.CONST_CLASS, modifiers.constKeyword, []);
|
| + }
|
| + if (modifiers.finalKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.FINAL_CLASS, modifiers.finalKeyword, []);
|
| + }
|
| + if (modifiers.varKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.VAR_RETURN_TYPE, modifiers.varKeyword, []);
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Validate that the given set of modifiers is appropriate for a field and return the 'final',
|
| + * 'const' or 'var' keyword if there is one.
|
| + *
|
| + * @param modifiers the modifiers being validated
|
| + * @return the 'final', 'const' or 'var' keyword associated with the field
|
| + */
|
| + Token _validateModifiersForTopLevelVariable(Modifiers modifiers) {
|
| + _validateModifiersForTopLevelDeclaration(modifiers);
|
| + if (modifiers.abstractKeyword != null) {
|
| + _reportErrorForCurrentToken(ParserErrorCode.ABSTRACT_TOP_LEVEL_VARIABLE, []);
|
| + }
|
| + if (modifiers.externalKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.EXTERNAL_FIELD, modifiers.externalKeyword, []);
|
| + }
|
| + Token constKeyword = modifiers.constKeyword;
|
| + Token finalKeyword = modifiers.finalKeyword;
|
| + Token varKeyword = modifiers.varKeyword;
|
| + if (constKeyword != null) {
|
| + if (finalKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.CONST_AND_FINAL, finalKeyword, []);
|
| + }
|
| + if (varKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.CONST_AND_VAR, varKeyword, []);
|
| + }
|
| + } else if (finalKeyword != null) {
|
| + if (varKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.FINAL_AND_VAR, varKeyword, []);
|
| + }
|
| + }
|
| + return _lexicallyFirst([constKeyword, finalKeyword, varKeyword]);
|
| + }
|
| +
|
| + /**
|
| + * Validate that the given set of modifiers is appropriate for a class and return the 'abstract'
|
| + * keyword if there is one.
|
| + *
|
| + * @param modifiers the modifiers being validated
|
| + */
|
| + void _validateModifiersForTypedef(Modifiers modifiers) {
|
| + _validateModifiersForTopLevelDeclaration(modifiers);
|
| + if (modifiers.abstractKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.ABSTRACT_TYPEDEF, modifiers.abstractKeyword, []);
|
| + }
|
| + if (modifiers.constKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.CONST_TYPEDEF, modifiers.constKeyword, []);
|
| + }
|
| + if (modifiers.externalKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.EXTERNAL_TYPEDEF, modifiers.externalKeyword, []);
|
| + }
|
| + if (modifiers.finalKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.FINAL_TYPEDEF, modifiers.finalKeyword, []);
|
| + }
|
| + if (modifiers.varKeyword != null) {
|
| + _reportErrorForToken(ParserErrorCode.VAR_TYPEDEF, modifiers.varKeyword, []);
|
| + }
|
| + }
|
| +}
|
| +
|
| +/**
|
| + * The enumeration `ParserErrorCode` defines the error codes used for errors detected by the
|
| + * parser. The convention for this class is for the name of the error code to indicate the problem
|
| + * that caused the error to be generated and for the error message to explain what is wrong and,
|
| + * when appropriate, how the problem can be corrected.
|
| + */
|
| +class ParserErrorCode extends Enum<ParserErrorCode> implements ErrorCode {
|
| + static const ParserErrorCode ABSTRACT_CLASS_MEMBER = const ParserErrorCode.con3('ABSTRACT_CLASS_MEMBER', 0, "Members of classes cannot be declared to be 'abstract'");
|
| +
|
| + static const ParserErrorCode ABSTRACT_ENUM = const ParserErrorCode.con3('ABSTRACT_ENUM', 1, "Enums cannot be declared to be 'abstract'");
|
| +
|
| + static const ParserErrorCode ABSTRACT_STATIC_METHOD = const ParserErrorCode.con3('ABSTRACT_STATIC_METHOD', 2, "Static methods cannot be declared to be 'abstract'");
|
| +
|
| + static const ParserErrorCode ABSTRACT_TOP_LEVEL_FUNCTION = const ParserErrorCode.con3('ABSTRACT_TOP_LEVEL_FUNCTION', 3, "Top-level functions cannot be declared to be 'abstract'");
|
| +
|
| + static const ParserErrorCode ABSTRACT_TOP_LEVEL_VARIABLE = const ParserErrorCode.con3('ABSTRACT_TOP_LEVEL_VARIABLE', 4, "Top-level variables cannot be declared to be 'abstract'");
|
| +
|
| + static const ParserErrorCode ABSTRACT_TYPEDEF = const ParserErrorCode.con3('ABSTRACT_TYPEDEF', 5, "Type aliases cannot be declared to be 'abstract'");
|
| +
|
| + static const ParserErrorCode ASSERT_DOES_NOT_TAKE_ASSIGNMENT = const ParserErrorCode.con3('ASSERT_DOES_NOT_TAKE_ASSIGNMENT', 6, "Assert cannot be called on an assignment");
|
| +
|
| + static const ParserErrorCode ASSERT_DOES_NOT_TAKE_CASCADE = const ParserErrorCode.con3('ASSERT_DOES_NOT_TAKE_CASCADE', 7, "Assert cannot be called on cascade");
|
| +
|
| + static const ParserErrorCode ASSERT_DOES_NOT_TAKE_THROW = const ParserErrorCode.con3('ASSERT_DOES_NOT_TAKE_THROW', 8, "Assert cannot be called on throws");
|
| +
|
| + static const ParserErrorCode ASSERT_DOES_NOT_TAKE_RETHROW = const ParserErrorCode.con3('ASSERT_DOES_NOT_TAKE_RETHROW', 9, "Assert cannot be called on rethrows");
|
| +
|
| + static const ParserErrorCode BREAK_OUTSIDE_OF_LOOP = const ParserErrorCode.con3('BREAK_OUTSIDE_OF_LOOP', 10, "A break statement cannot be used outside of a loop or switch statement");
|
| +
|
| + static const ParserErrorCode CONST_AND_FINAL = const ParserErrorCode.con3('CONST_AND_FINAL', 11, "Members cannot be declared to be both 'const' and 'final'");
|
| +
|
| + static const ParserErrorCode CONST_AND_VAR = const ParserErrorCode.con3('CONST_AND_VAR', 12, "Members cannot be declared to be both 'const' and 'var'");
|
| +
|
| + static const ParserErrorCode CONST_CLASS = const ParserErrorCode.con3('CONST_CLASS', 13, "Classes cannot be declared to be 'const'");
|
| +
|
| + static const ParserErrorCode CONST_CONSTRUCTOR_WITH_BODY = const ParserErrorCode.con3('CONST_CONSTRUCTOR_WITH_BODY', 14, "'const' constructors cannot have a body");
|
| +
|
| + static const ParserErrorCode CONST_ENUM = const ParserErrorCode.con3('CONST_ENUM', 15, "Enums cannot be declared to be 'const'");
|
| +
|
| + static const ParserErrorCode CONST_FACTORY = const ParserErrorCode.con3('CONST_FACTORY', 16, "Only redirecting factory constructors can be declared to be 'const'");
|
| +
|
| + static const ParserErrorCode CONST_METHOD = const ParserErrorCode.con3('CONST_METHOD', 17, "Getters, setters and methods cannot be declared to be 'const'");
|
| +
|
| + static const ParserErrorCode CONST_TYPEDEF = const ParserErrorCode.con3('CONST_TYPEDEF', 18, "Type aliases cannot be declared to be 'const'");
|
| +
|
| + static const ParserErrorCode CONSTRUCTOR_WITH_RETURN_TYPE = const ParserErrorCode.con3('CONSTRUCTOR_WITH_RETURN_TYPE', 19, "Constructors cannot have a return type");
|
| +
|
| + static const ParserErrorCode CONTINUE_OUTSIDE_OF_LOOP = const ParserErrorCode.con3('CONTINUE_OUTSIDE_OF_LOOP', 20, "A continue statement cannot be used outside of a loop or switch statement");
|
| +
|
| + static const ParserErrorCode CONTINUE_WITHOUT_LABEL_IN_CASE = const ParserErrorCode.con3('CONTINUE_WITHOUT_LABEL_IN_CASE', 21, "A continue statement in a switch statement must have a label as a target");
|
| +
|
| + static const ParserErrorCode DEFERRED_IMPORTS_NOT_SUPPORTED = const ParserErrorCode.con3('DEFERRED_IMPORTS_NOT_SUPPORTED', 22, "Deferred imports are not supported by default");
|
| +
|
| + static const ParserErrorCode DEPRECATED_CLASS_TYPE_ALIAS = const ParserErrorCode.con3('DEPRECATED_CLASS_TYPE_ALIAS', 23, "The 'typedef' mixin application was replaced with 'class'");
|
| +
|
| + static const ParserErrorCode DIRECTIVE_AFTER_DECLARATION = const ParserErrorCode.con3('DIRECTIVE_AFTER_DECLARATION', 24, "Directives must appear before any declarations");
|
| +
|
| + static const ParserErrorCode DUPLICATE_LABEL_IN_SWITCH_STATEMENT = const ParserErrorCode.con3('DUPLICATE_LABEL_IN_SWITCH_STATEMENT', 25, "The label {0} was already used in this switch statement");
|
| +
|
| + static const ParserErrorCode DUPLICATED_MODIFIER = const ParserErrorCode.con3('DUPLICATED_MODIFIER', 26, "The modifier '{0}' was already specified.");
|
| +
|
| + static const ParserErrorCode EMPTY_ENUM_BODY = const ParserErrorCode.con3('EMPTY_ENUM_BODY', 27, "An enum must declare at least one constant name");
|
| +
|
| + static const ParserErrorCode EQUALITY_CANNOT_BE_EQUALITY_OPERAND = const ParserErrorCode.con3('EQUALITY_CANNOT_BE_EQUALITY_OPERAND', 28, "Equality expression cannot be operand of another equality expression.");
|
| +
|
| + static const ParserErrorCode EXPECTED_CASE_OR_DEFAULT = const ParserErrorCode.con3('EXPECTED_CASE_OR_DEFAULT', 29, "Expected 'case' or 'default'");
|
| +
|
| + static const ParserErrorCode EXPECTED_CLASS_MEMBER = const ParserErrorCode.con3('EXPECTED_CLASS_MEMBER', 30, "Expected a class member");
|
| +
|
| + static const ParserErrorCode EXPECTED_EXECUTABLE = const ParserErrorCode.con3('EXPECTED_EXECUTABLE', 31, "Expected a method, getter, setter or operator declaration");
|
| +
|
| + static const ParserErrorCode EXPECTED_LIST_OR_MAP_LITERAL = const ParserErrorCode.con3('EXPECTED_LIST_OR_MAP_LITERAL', 32, "Expected a list or map literal");
|
| +
|
| + static const ParserErrorCode EXPECTED_STRING_LITERAL = const ParserErrorCode.con3('EXPECTED_STRING_LITERAL', 33, "Expected a string literal");
|
| +
|
| + static const ParserErrorCode EXPECTED_TOKEN = const ParserErrorCode.con3('EXPECTED_TOKEN', 34, "Expected to find '{0}'");
|
| +
|
| + static const ParserErrorCode EXPECTED_TYPE_NAME = const ParserErrorCode.con3('EXPECTED_TYPE_NAME', 35, "Expected a type name");
|
| +
|
| + static const ParserErrorCode EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE = const ParserErrorCode.con3('EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE', 36, "Export directives must preceed part directives");
|
| +
|
| + static const ParserErrorCode EXTERNAL_AFTER_CONST = const ParserErrorCode.con3('EXTERNAL_AFTER_CONST', 37, "The modifier 'external' should be before the modifier 'const'");
|
| +
|
| + static const ParserErrorCode EXTERNAL_AFTER_FACTORY = const ParserErrorCode.con3('EXTERNAL_AFTER_FACTORY', 38, "The modifier 'external' should be before the modifier 'factory'");
|
| +
|
| + static const ParserErrorCode EXTERNAL_AFTER_STATIC = const ParserErrorCode.con3('EXTERNAL_AFTER_STATIC', 39, "The modifier 'external' should be before the modifier 'static'");
|
| +
|
| + static const ParserErrorCode EXTERNAL_CLASS = const ParserErrorCode.con3('EXTERNAL_CLASS', 40, "Classes cannot be declared to be 'external'");
|
| +
|
| + static const ParserErrorCode EXTERNAL_CONSTRUCTOR_WITH_BODY = const ParserErrorCode.con3('EXTERNAL_CONSTRUCTOR_WITH_BODY', 41, "External constructors cannot have a body");
|
| +
|
| + static const ParserErrorCode EXTERNAL_ENUM = const ParserErrorCode.con3('EXTERNAL_ENUM', 42, "Enums cannot be declared to be 'external'");
|
| +
|
| + static const ParserErrorCode EXTERNAL_FIELD = const ParserErrorCode.con3('EXTERNAL_FIELD', 43, "Fields cannot be declared to be 'external'");
|
| +
|
| + static const ParserErrorCode EXTERNAL_GETTER_WITH_BODY = const ParserErrorCode.con3('EXTERNAL_GETTER_WITH_BODY', 44, "External getters cannot have a body");
|
| +
|
| + static const ParserErrorCode EXTERNAL_METHOD_WITH_BODY = const ParserErrorCode.con3('EXTERNAL_METHOD_WITH_BODY', 45, "External methods cannot have a body");
|
| +
|
| + static const ParserErrorCode EXTERNAL_OPERATOR_WITH_BODY = const ParserErrorCode.con3('EXTERNAL_OPERATOR_WITH_BODY', 46, "External operators cannot have a body");
|
| +
|
| + static const ParserErrorCode EXTERNAL_SETTER_WITH_BODY = const ParserErrorCode.con3('EXTERNAL_SETTER_WITH_BODY', 47, "External setters cannot have a body");
|
| +
|
| + static const ParserErrorCode EXTERNAL_TYPEDEF = const ParserErrorCode.con3('EXTERNAL_TYPEDEF', 48, "Type aliases cannot be declared to be 'external'");
|
| +
|
| + static const ParserErrorCode FACTORY_TOP_LEVEL_DECLARATION = const ParserErrorCode.con3('FACTORY_TOP_LEVEL_DECLARATION', 49, "Top-level declarations cannot be declared to be 'factory'");
|
| +
|
| + static const ParserErrorCode FACTORY_WITHOUT_BODY = const ParserErrorCode.con3('FACTORY_WITHOUT_BODY', 50, "A non-redirecting 'factory' constructor must have a body");
|
| +
|
| + static const ParserErrorCode FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR = const ParserErrorCode.con3('FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR', 51, "Field initializers can only be used in a constructor");
|
| +
|
| + static const ParserErrorCode FINAL_AND_VAR = const ParserErrorCode.con3('FINAL_AND_VAR', 52, "Members cannot be declared to be both 'final' and 'var'");
|
| +
|
| + static const ParserErrorCode FINAL_CLASS = const ParserErrorCode.con3('FINAL_CLASS', 53, "Classes cannot be declared to be 'final'");
|
| +
|
| + static const ParserErrorCode FINAL_CONSTRUCTOR = const ParserErrorCode.con3('FINAL_CONSTRUCTOR', 54, "A constructor cannot be declared to be 'final'");
|
| +
|
| + static const ParserErrorCode FINAL_ENUM = const ParserErrorCode.con3('FINAL_ENUM', 55, "Enums cannot be declared to be 'final'");
|
| +
|
| + static const ParserErrorCode FINAL_METHOD = const ParserErrorCode.con3('FINAL_METHOD', 56, "Getters, setters and methods cannot be declared to be 'final'");
|
| +
|
| + static const ParserErrorCode FINAL_TYPEDEF = const ParserErrorCode.con3('FINAL_TYPEDEF', 57, "Type aliases cannot be declared to be 'final'");
|
| +
|
| + static const ParserErrorCode FUNCTION_TYPED_PARAMETER_VAR = const ParserErrorCode.con3('FUNCTION_TYPED_PARAMETER_VAR', 58, "Function typed parameters cannot specify 'const', 'final' or 'var' instead of return type");
|
| +
|
| + static const ParserErrorCode GETTER_IN_FUNCTION = const ParserErrorCode.con3('GETTER_IN_FUNCTION', 59, "Getters cannot be defined within methods or functions");
|
| +
|
| + static const ParserErrorCode GETTER_WITH_PARAMETERS = const ParserErrorCode.con3('GETTER_WITH_PARAMETERS', 60, "Getter should be declared without a parameter list");
|
| +
|
| + static const ParserErrorCode ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE = const ParserErrorCode.con3('ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE', 61, "Illegal assignment to non-assignable expression");
|
| +
|
| + static const ParserErrorCode IMPLEMENTS_BEFORE_EXTENDS = const ParserErrorCode.con3('IMPLEMENTS_BEFORE_EXTENDS', 62, "The extends clause must be before the implements clause");
|
| +
|
| + static const ParserErrorCode IMPLEMENTS_BEFORE_WITH = const ParserErrorCode.con3('IMPLEMENTS_BEFORE_WITH', 63, "The with clause must be before the implements clause");
|
| +
|
| + static const ParserErrorCode IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE = const ParserErrorCode.con3('IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE', 64, "Import directives must preceed part directives");
|
| +
|
| + static const ParserErrorCode INITIALIZED_VARIABLE_IN_FOR_EACH = const ParserErrorCode.con3('INITIALIZED_VARIABLE_IN_FOR_EACH', 65, "The loop variable in a for-each loop cannot be initialized");
|
| +
|
| + static const ParserErrorCode INVALID_AWAIT_IN_FOR = const ParserErrorCode.con4('INVALID_AWAIT_IN_FOR', 66, "The modifier 'await' is not allowed for a normal 'for' statement", "Remove the keyword or use a for-each statement.");
|
| +
|
| + static const ParserErrorCode INVALID_CODE_POINT = const ParserErrorCode.con3('INVALID_CODE_POINT', 67, "The escape sequence '{0}' is not a valid code point");
|
| +
|
| + static const ParserErrorCode INVALID_COMMENT_REFERENCE = const ParserErrorCode.con3('INVALID_COMMENT_REFERENCE', 68, "Comment references should contain a possibly prefixed identifier and can start with 'new', but should not contain anything else");
|
| +
|
| + static const ParserErrorCode INVALID_HEX_ESCAPE = const ParserErrorCode.con3('INVALID_HEX_ESCAPE', 69, "An escape sequence starting with '\\x' must be followed by 2 hexidecimal digits");
|
| +
|
| + static const ParserErrorCode INVALID_OPERATOR = const ParserErrorCode.con3('INVALID_OPERATOR', 70, "The string '{0}' is not a valid operator");
|
| +
|
| + static const ParserErrorCode INVALID_OPERATOR_FOR_SUPER = const ParserErrorCode.con3('INVALID_OPERATOR_FOR_SUPER', 71, "The operator '{0}' cannot be used with 'super'");
|
| +
|
| + static const ParserErrorCode INVALID_STAR_AFTER_ASYNC = const ParserErrorCode.con4('INVALID_STAR_AFTER_ASYNC', 72, "The modifier 'async*' is not allowed for an expression function body", "Convert the body to a block.");
|
| +
|
| + static const ParserErrorCode INVALID_SYNC = const ParserErrorCode.con4('INVALID_SYNC', 73, "The modifier 'sync' is not allowed for an exrpression function body", "Convert the body to a block.");
|
| +
|
| + static const ParserErrorCode INVALID_UNICODE_ESCAPE = const ParserErrorCode.con3('INVALID_UNICODE_ESCAPE', 74, "An escape sequence starting with '\\u' must be followed by 4 hexidecimal digits or from 1 to 6 digits between '{' and '}'");
|
| +
|
| + static const ParserErrorCode LIBRARY_DIRECTIVE_NOT_FIRST = const ParserErrorCode.con3('LIBRARY_DIRECTIVE_NOT_FIRST', 75, "The library directive must appear before all other directives");
|
| +
|
| + static const ParserErrorCode LOCAL_FUNCTION_DECLARATION_MODIFIER = const ParserErrorCode.con3('LOCAL_FUNCTION_DECLARATION_MODIFIER', 76, "Local function declarations cannot specify any modifier");
|
| +
|
| + static const ParserErrorCode MISSING_ASSIGNABLE_SELECTOR = const ParserErrorCode.con3('MISSING_ASSIGNABLE_SELECTOR', 77, "Missing selector such as \".<identifier>\" or \"[0]\"");
|
| +
|
| + static const ParserErrorCode MISSING_CATCH_OR_FINALLY = const ParserErrorCode.con3('MISSING_CATCH_OR_FINALLY', 78, "A try statement must have either a catch or finally clause");
|
| +
|
| + static const ParserErrorCode MISSING_CLASS_BODY = const ParserErrorCode.con3('MISSING_CLASS_BODY', 79, "A class definition must have a body, even if it is empty");
|
| +
|
| + static const ParserErrorCode MISSING_CLOSING_PARENTHESIS = const ParserErrorCode.con3('MISSING_CLOSING_PARENTHESIS', 80, "The closing parenthesis is missing");
|
| +
|
| + static const ParserErrorCode MISSING_CONST_FINAL_VAR_OR_TYPE = const ParserErrorCode.con3('MISSING_CONST_FINAL_VAR_OR_TYPE', 81, "Variables must be declared using the keywords 'const', 'final', 'var' or a type name");
|
| +
|
| + static const ParserErrorCode MISSING_ENUM_BODY = const ParserErrorCode.con3('MISSING_ENUM_BODY', 82, "An enum definition must have a body with at least one constant name");
|
| +
|
| + static const ParserErrorCode MISSING_EXPRESSION_IN_THROW = const ParserErrorCode.con3('MISSING_EXPRESSION_IN_THROW', 83, "Throw expressions must compute the object to be thrown");
|
| +
|
| + static const ParserErrorCode MISSING_FUNCTION_BODY = const ParserErrorCode.con3('MISSING_FUNCTION_BODY', 84, "A function body must be provided");
|
| +
|
| + static const ParserErrorCode MISSING_FUNCTION_PARAMETERS = const ParserErrorCode.con3('MISSING_FUNCTION_PARAMETERS', 85, "Functions must have an explicit list of parameters");
|
| +
|
| + static const ParserErrorCode MISSING_GET = const ParserErrorCode.con3('MISSING_GET', 86, "Getters must have the keyword 'get' before the getter name");
|
| +
|
| + static const ParserErrorCode MISSING_IDENTIFIER = const ParserErrorCode.con3('MISSING_IDENTIFIER', 87, "Expected an identifier");
|
| +
|
| + static const ParserErrorCode MISSING_KEYWORD_OPERATOR = const ParserErrorCode.con3('MISSING_KEYWORD_OPERATOR', 88, "Operator declarations must be preceeded by the keyword 'operator'");
|
| +
|
| + static const ParserErrorCode MISSING_NAME_IN_LIBRARY_DIRECTIVE = const ParserErrorCode.con3('MISSING_NAME_IN_LIBRARY_DIRECTIVE', 89, "Library directives must include a library name");
|
| +
|
| + static const ParserErrorCode MISSING_NAME_IN_PART_OF_DIRECTIVE = const ParserErrorCode.con3('MISSING_NAME_IN_PART_OF_DIRECTIVE', 90, "Library directives must include a library name");
|
| +
|
| + static const ParserErrorCode MISSING_PREFIX_IN_DEFERRED_IMPORT = const ParserErrorCode.con3('MISSING_PREFIX_IN_DEFERRED_IMPORT', 91, "Deferred imports must have a prefix");
|
| +
|
| + static const ParserErrorCode MISSING_STAR_AFTER_SYNC = const ParserErrorCode.con4('MISSING_STAR_AFTER_SYNC', 92, "The modifier 'sync' must be followed by a star ('*')", "Remove the modifier or add a star.");
|
| +
|
| + static const ParserErrorCode MISSING_STATEMENT = const ParserErrorCode.con3('MISSING_STATEMENT', 93, "Expected a statement");
|
| +
|
| + static const ParserErrorCode MISSING_TERMINATOR_FOR_PARAMETER_GROUP = const ParserErrorCode.con3('MISSING_TERMINATOR_FOR_PARAMETER_GROUP', 94, "There is no '{0}' to close the parameter group");
|
| +
|
| + static const ParserErrorCode MISSING_TYPEDEF_PARAMETERS = const ParserErrorCode.con3('MISSING_TYPEDEF_PARAMETERS', 95, "Type aliases for functions must have an explicit list of parameters");
|
| +
|
| + static const ParserErrorCode MISSING_VARIABLE_IN_FOR_EACH = const ParserErrorCode.con3('MISSING_VARIABLE_IN_FOR_EACH', 96, "A loop variable must be declared in a for-each loop before the 'in', but none were found");
|
| +
|
| + static const ParserErrorCode MIXED_PARAMETER_GROUPS = const ParserErrorCode.con3('MIXED_PARAMETER_GROUPS', 97, "Cannot have both positional and named parameters in a single parameter list");
|
| +
|
| + static const ParserErrorCode MULTIPLE_EXTENDS_CLAUSES = const ParserErrorCode.con3('MULTIPLE_EXTENDS_CLAUSES', 98, "Each class definition can have at most one extends clause");
|
| +
|
| + static const ParserErrorCode MULTIPLE_IMPLEMENTS_CLAUSES = const ParserErrorCode.con3('MULTIPLE_IMPLEMENTS_CLAUSES', 99, "Each class definition can have at most one implements clause");
|
| +
|
| + static const ParserErrorCode MULTIPLE_LIBRARY_DIRECTIVES = const ParserErrorCode.con3('MULTIPLE_LIBRARY_DIRECTIVES', 100, "Only one library directive may be declared in a file");
|
| +
|
| + static const ParserErrorCode MULTIPLE_NAMED_PARAMETER_GROUPS = const ParserErrorCode.con3('MULTIPLE_NAMED_PARAMETER_GROUPS', 101, "Cannot have multiple groups of named parameters in a single parameter list");
|
| +
|
| + static const ParserErrorCode MULTIPLE_PART_OF_DIRECTIVES = const ParserErrorCode.con3('MULTIPLE_PART_OF_DIRECTIVES', 102, "Only one part-of directive may be declared in a file");
|
| +
|
| + static const ParserErrorCode MULTIPLE_POSITIONAL_PARAMETER_GROUPS = const ParserErrorCode.con3('MULTIPLE_POSITIONAL_PARAMETER_GROUPS', 103, "Cannot have multiple groups of positional parameters in a single parameter list");
|
| +
|
| + static const ParserErrorCode MULTIPLE_VARIABLES_IN_FOR_EACH = const ParserErrorCode.con3('MULTIPLE_VARIABLES_IN_FOR_EACH', 104, "A single loop variable must be declared in a for-each loop before the 'in', but {0} were found");
|
| +
|
| + static const ParserErrorCode MULTIPLE_WITH_CLAUSES = const ParserErrorCode.con3('MULTIPLE_WITH_CLAUSES', 105, "Each class definition can have at most one with clause");
|
| +
|
| + static const ParserErrorCode NAMED_FUNCTION_EXPRESSION = const ParserErrorCode.con3('NAMED_FUNCTION_EXPRESSION', 106, "Function expressions cannot be named");
|
| +
|
| + static const ParserErrorCode NAMED_PARAMETER_OUTSIDE_GROUP = const ParserErrorCode.con3('NAMED_PARAMETER_OUTSIDE_GROUP', 107, "Named parameters must be enclosed in curly braces ('{' and '}')");
|
| +
|
| + static const ParserErrorCode NATIVE_CLAUSE_IN_NON_SDK_CODE = const ParserErrorCode.con3('NATIVE_CLAUSE_IN_NON_SDK_CODE', 108, "Native clause can only be used in the SDK and code that is loaded through native extensions");
|
| +
|
| + static const ParserErrorCode NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE = const ParserErrorCode.con3('NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE', 109, "Native functions can only be declared in the SDK and code that is loaded through native extensions");
|
| +
|
| + static const ParserErrorCode NON_CONSTRUCTOR_FACTORY = const ParserErrorCode.con3('NON_CONSTRUCTOR_FACTORY', 110, "Only constructors can be declared to be a 'factory'");
|
| +
|
| + static const ParserErrorCode NON_IDENTIFIER_LIBRARY_NAME = const ParserErrorCode.con3('NON_IDENTIFIER_LIBRARY_NAME', 111, "The name of a library must be an identifier");
|
| +
|
| + static const ParserErrorCode NON_PART_OF_DIRECTIVE_IN_PART = const ParserErrorCode.con3('NON_PART_OF_DIRECTIVE_IN_PART', 112, "The part-of directive must be the only directive in a part");
|
| +
|
| + static const ParserErrorCode NON_USER_DEFINABLE_OPERATOR = const ParserErrorCode.con3('NON_USER_DEFINABLE_OPERATOR', 113, "The operator '{0}' is not user definable");
|
| +
|
| + static const ParserErrorCode NORMAL_BEFORE_OPTIONAL_PARAMETERS = const ParserErrorCode.con3('NORMAL_BEFORE_OPTIONAL_PARAMETERS', 114, "Normal parameters must occur before optional parameters");
|
| +
|
| + static const ParserErrorCode POSITIONAL_AFTER_NAMED_ARGUMENT = const ParserErrorCode.con3('POSITIONAL_AFTER_NAMED_ARGUMENT', 115, "Positional arguments must occur before named arguments");
|
| +
|
| + static const ParserErrorCode POSITIONAL_PARAMETER_OUTSIDE_GROUP = const ParserErrorCode.con3('POSITIONAL_PARAMETER_OUTSIDE_GROUP', 116, "Positional parameters must be enclosed in square brackets ('[' and ']')");
|
| +
|
| + static const ParserErrorCode REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR = const ParserErrorCode.con3('REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR', 117, "Only factory constructor can specify '=' redirection.");
|
| +
|
| + static const ParserErrorCode SETTER_IN_FUNCTION = const ParserErrorCode.con3('SETTER_IN_FUNCTION', 118, "Setters cannot be defined within methods or functions");
|
| +
|
| + static const ParserErrorCode STATIC_AFTER_CONST = const ParserErrorCode.con3('STATIC_AFTER_CONST', 119, "The modifier 'static' should be before the modifier 'const'");
|
| +
|
| + static const ParserErrorCode STATIC_AFTER_FINAL = const ParserErrorCode.con3('STATIC_AFTER_FINAL', 120, "The modifier 'static' should be before the modifier 'final'");
|
| +
|
| + static const ParserErrorCode STATIC_AFTER_VAR = const ParserErrorCode.con3('STATIC_AFTER_VAR', 121, "The modifier 'static' should be before the modifier 'var'");
|
| +
|
| + static const ParserErrorCode STATIC_CONSTRUCTOR = const ParserErrorCode.con3('STATIC_CONSTRUCTOR', 122, "Constructors cannot be static");
|
| +
|
| + static const ParserErrorCode STATIC_GETTER_WITHOUT_BODY = const ParserErrorCode.con3('STATIC_GETTER_WITHOUT_BODY', 123, "A 'static' getter must have a body");
|
| +
|
| + static const ParserErrorCode STATIC_OPERATOR = const ParserErrorCode.con3('STATIC_OPERATOR', 124, "Operators cannot be static");
|
| +
|
| + static const ParserErrorCode STATIC_SETTER_WITHOUT_BODY = const ParserErrorCode.con3('STATIC_SETTER_WITHOUT_BODY', 125, "A 'static' setter must have a body");
|
| +
|
| + static const ParserErrorCode STATIC_TOP_LEVEL_DECLARATION = const ParserErrorCode.con3('STATIC_TOP_LEVEL_DECLARATION', 126, "Top-level declarations cannot be declared to be 'static'");
|
| +
|
| + static const ParserErrorCode SWITCH_HAS_CASE_AFTER_DEFAULT_CASE = const ParserErrorCode.con3('SWITCH_HAS_CASE_AFTER_DEFAULT_CASE', 127, "The 'default' case should be the last case in a switch statement");
|
| +
|
| + static const ParserErrorCode SWITCH_HAS_MULTIPLE_DEFAULT_CASES = const ParserErrorCode.con3('SWITCH_HAS_MULTIPLE_DEFAULT_CASES', 128, "The 'default' case can only be declared once");
|
| +
|
| + static const ParserErrorCode TOP_LEVEL_OPERATOR = const ParserErrorCode.con3('TOP_LEVEL_OPERATOR', 129, "Operators must be declared within a class");
|
| +
|
| + static const ParserErrorCode UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP = const ParserErrorCode.con3('UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP', 130, "There is no '{0}' to open a parameter group");
|
| +
|
| + static const ParserErrorCode UNEXPECTED_TOKEN = const ParserErrorCode.con3('UNEXPECTED_TOKEN', 131, "Unexpected token '{0}'");
|
| +
|
| + static const ParserErrorCode WITH_BEFORE_EXTENDS = const ParserErrorCode.con3('WITH_BEFORE_EXTENDS', 132, "The extends clause must be before the with clause");
|
| +
|
| + static const ParserErrorCode WITH_WITHOUT_EXTENDS = const ParserErrorCode.con3('WITH_WITHOUT_EXTENDS', 133, "The with clause cannot be used without an extends clause");
|
| +
|
| + static const ParserErrorCode WRONG_SEPARATOR_FOR_NAMED_PARAMETER = const ParserErrorCode.con3('WRONG_SEPARATOR_FOR_NAMED_PARAMETER', 134, "The default value of a named parameter should be preceeded by ':'");
|
| +
|
| + static const ParserErrorCode WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER = const ParserErrorCode.con3('WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER', 135, "The default value of a positional parameter should be preceeded by '='");
|
| +
|
| + static const ParserErrorCode WRONG_TERMINATOR_FOR_PARAMETER_GROUP = const ParserErrorCode.con3('WRONG_TERMINATOR_FOR_PARAMETER_GROUP', 136, "Expected '{0}' to close parameter group");
|
| +
|
| + static const ParserErrorCode VAR_AND_TYPE = const ParserErrorCode.con3('VAR_AND_TYPE', 137, "Variables cannot be declared using both 'var' and a type name; remove the 'var'");
|
| +
|
| + static const ParserErrorCode VAR_AS_TYPE_NAME = const ParserErrorCode.con3('VAR_AS_TYPE_NAME', 138, "The keyword 'var' cannot be used as a type name");
|
| +
|
| + static const ParserErrorCode VAR_CLASS = const ParserErrorCode.con3('VAR_CLASS', 139, "Classes cannot be declared to be 'var'");
|
| +
|
| + static const ParserErrorCode VAR_ENUM = const ParserErrorCode.con3('VAR_ENUM', 140, "Enums cannot be declared to be 'var'");
|
| +
|
| + static const ParserErrorCode VAR_RETURN_TYPE = const ParserErrorCode.con3('VAR_RETURN_TYPE', 141, "The return type cannot be 'var'");
|
| +
|
| + static const ParserErrorCode VAR_TYPEDEF = const ParserErrorCode.con3('VAR_TYPEDEF', 142, "Type aliases cannot be declared to be 'var'");
|
| +
|
| + static const ParserErrorCode VOID_PARAMETER = const ParserErrorCode.con3('VOID_PARAMETER', 143, "Parameters cannot have a type of 'void'");
|
| +
|
| + static const ParserErrorCode VOID_VARIABLE = const ParserErrorCode.con3('VOID_VARIABLE', 144, "Variables cannot have a type of 'void'");
|
| +
|
| + static const List<ParserErrorCode> values = const [
|
| + ABSTRACT_CLASS_MEMBER,
|
| + ABSTRACT_ENUM,
|
| + ABSTRACT_STATIC_METHOD,
|
| + ABSTRACT_TOP_LEVEL_FUNCTION,
|
| + ABSTRACT_TOP_LEVEL_VARIABLE,
|
| + ABSTRACT_TYPEDEF,
|
| + ASSERT_DOES_NOT_TAKE_ASSIGNMENT,
|
| + ASSERT_DOES_NOT_TAKE_CASCADE,
|
| + ASSERT_DOES_NOT_TAKE_THROW,
|
| + ASSERT_DOES_NOT_TAKE_RETHROW,
|
| + BREAK_OUTSIDE_OF_LOOP,
|
| + CONST_AND_FINAL,
|
| + CONST_AND_VAR,
|
| + CONST_CLASS,
|
| + CONST_CONSTRUCTOR_WITH_BODY,
|
| + CONST_ENUM,
|
| + CONST_FACTORY,
|
| + CONST_METHOD,
|
| + CONST_TYPEDEF,
|
| + CONSTRUCTOR_WITH_RETURN_TYPE,
|
| + CONTINUE_OUTSIDE_OF_LOOP,
|
| + CONTINUE_WITHOUT_LABEL_IN_CASE,
|
| + DEFERRED_IMPORTS_NOT_SUPPORTED,
|
| + DEPRECATED_CLASS_TYPE_ALIAS,
|
| + DIRECTIVE_AFTER_DECLARATION,
|
| + DUPLICATE_LABEL_IN_SWITCH_STATEMENT,
|
| + DUPLICATED_MODIFIER,
|
| + EMPTY_ENUM_BODY,
|
| + EQUALITY_CANNOT_BE_EQUALITY_OPERAND,
|
| + EXPECTED_CASE_OR_DEFAULT,
|
| + EXPECTED_CLASS_MEMBER,
|
| + EXPECTED_EXECUTABLE,
|
| + EXPECTED_LIST_OR_MAP_LITERAL,
|
| + EXPECTED_STRING_LITERAL,
|
| + EXPECTED_TOKEN,
|
| + EXPECTED_TYPE_NAME,
|
| + EXPORT_DIRECTIVE_AFTER_PART_DIRECTIVE,
|
| + EXTERNAL_AFTER_CONST,
|
| + EXTERNAL_AFTER_FACTORY,
|
| + EXTERNAL_AFTER_STATIC,
|
| + EXTERNAL_CLASS,
|
| + EXTERNAL_CONSTRUCTOR_WITH_BODY,
|
| + EXTERNAL_ENUM,
|
| + EXTERNAL_FIELD,
|
| + EXTERNAL_GETTER_WITH_BODY,
|
| + EXTERNAL_METHOD_WITH_BODY,
|
| + EXTERNAL_OPERATOR_WITH_BODY,
|
| + EXTERNAL_SETTER_WITH_BODY,
|
| + EXTERNAL_TYPEDEF,
|
| + FACTORY_TOP_LEVEL_DECLARATION,
|
| + FACTORY_WITHOUT_BODY,
|
| + FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR,
|
| + FINAL_AND_VAR,
|
| + FINAL_CLASS,
|
| + FINAL_CONSTRUCTOR,
|
| + FINAL_ENUM,
|
| + FINAL_METHOD,
|
| + FINAL_TYPEDEF,
|
| + FUNCTION_TYPED_PARAMETER_VAR,
|
| + GETTER_IN_FUNCTION,
|
| + GETTER_WITH_PARAMETERS,
|
| + ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE,
|
| + IMPLEMENTS_BEFORE_EXTENDS,
|
| + IMPLEMENTS_BEFORE_WITH,
|
| + IMPORT_DIRECTIVE_AFTER_PART_DIRECTIVE,
|
| + INITIALIZED_VARIABLE_IN_FOR_EACH,
|
| + INVALID_AWAIT_IN_FOR,
|
| + INVALID_CODE_POINT,
|
| + INVALID_COMMENT_REFERENCE,
|
| + INVALID_HEX_ESCAPE,
|
| + INVALID_OPERATOR,
|
| + INVALID_OPERATOR_FOR_SUPER,
|
| + INVALID_STAR_AFTER_ASYNC,
|
| + INVALID_SYNC,
|
| + INVALID_UNICODE_ESCAPE,
|
| + LIBRARY_DIRECTIVE_NOT_FIRST,
|
| + LOCAL_FUNCTION_DECLARATION_MODIFIER,
|
| + MISSING_ASSIGNABLE_SELECTOR,
|
| + MISSING_CATCH_OR_FINALLY,
|
| + MISSING_CLASS_BODY,
|
| + MISSING_CLOSING_PARENTHESIS,
|
| + MISSING_CONST_FINAL_VAR_OR_TYPE,
|
| + MISSING_ENUM_BODY,
|
| + MISSING_EXPRESSION_IN_THROW,
|
| + MISSING_FUNCTION_BODY,
|
| + MISSING_FUNCTION_PARAMETERS,
|
| + MISSING_GET,
|
| + MISSING_IDENTIFIER,
|
| + MISSING_KEYWORD_OPERATOR,
|
| + MISSING_NAME_IN_LIBRARY_DIRECTIVE,
|
| + MISSING_NAME_IN_PART_OF_DIRECTIVE,
|
| + MISSING_PREFIX_IN_DEFERRED_IMPORT,
|
| + MISSING_STAR_AFTER_SYNC,
|
| + MISSING_STATEMENT,
|
| + MISSING_TERMINATOR_FOR_PARAMETER_GROUP,
|
| + MISSING_TYPEDEF_PARAMETERS,
|
| + MISSING_VARIABLE_IN_FOR_EACH,
|
| + MIXED_PARAMETER_GROUPS,
|
| + MULTIPLE_EXTENDS_CLAUSES,
|
| + MULTIPLE_IMPLEMENTS_CLAUSES,
|
| + MULTIPLE_LIBRARY_DIRECTIVES,
|
| + MULTIPLE_NAMED_PARAMETER_GROUPS,
|
| + MULTIPLE_PART_OF_DIRECTIVES,
|
| + MULTIPLE_POSITIONAL_PARAMETER_GROUPS,
|
| + MULTIPLE_VARIABLES_IN_FOR_EACH,
|
| + MULTIPLE_WITH_CLAUSES,
|
| + NAMED_FUNCTION_EXPRESSION,
|
| + NAMED_PARAMETER_OUTSIDE_GROUP,
|
| + NATIVE_CLAUSE_IN_NON_SDK_CODE,
|
| + NATIVE_FUNCTION_BODY_IN_NON_SDK_CODE,
|
| + NON_CONSTRUCTOR_FACTORY,
|
| + NON_IDENTIFIER_LIBRARY_NAME,
|
| + NON_PART_OF_DIRECTIVE_IN_PART,
|
| + NON_USER_DEFINABLE_OPERATOR,
|
| + NORMAL_BEFORE_OPTIONAL_PARAMETERS,
|
| + POSITIONAL_AFTER_NAMED_ARGUMENT,
|
| + POSITIONAL_PARAMETER_OUTSIDE_GROUP,
|
| + REDIRECTION_IN_NON_FACTORY_CONSTRUCTOR,
|
| + SETTER_IN_FUNCTION,
|
| + STATIC_AFTER_CONST,
|
| + STATIC_AFTER_FINAL,
|
| + STATIC_AFTER_VAR,
|
| + STATIC_CONSTRUCTOR,
|
| + STATIC_GETTER_WITHOUT_BODY,
|
| + STATIC_OPERATOR,
|
| + STATIC_SETTER_WITHOUT_BODY,
|
| + STATIC_TOP_LEVEL_DECLARATION,
|
| + SWITCH_HAS_CASE_AFTER_DEFAULT_CASE,
|
| + SWITCH_HAS_MULTIPLE_DEFAULT_CASES,
|
| + TOP_LEVEL_OPERATOR,
|
| + UNEXPECTED_TERMINATOR_FOR_PARAMETER_GROUP,
|
| + UNEXPECTED_TOKEN,
|
| + WITH_BEFORE_EXTENDS,
|
| + WITH_WITHOUT_EXTENDS,
|
| + WRONG_SEPARATOR_FOR_NAMED_PARAMETER,
|
| + WRONG_SEPARATOR_FOR_POSITIONAL_PARAMETER,
|
| + WRONG_TERMINATOR_FOR_PARAMETER_GROUP,
|
| + VAR_AND_TYPE,
|
| + VAR_AS_TYPE_NAME,
|
| + VAR_CLASS,
|
| + VAR_ENUM,
|
| + VAR_RETURN_TYPE,
|
| + VAR_TYPEDEF,
|
| + VOID_PARAMETER,
|
| + VOID_VARIABLE];
|
| +
|
| + /**
|
| + * The severity of this error.
|
| + */
|
| + final ErrorSeverity errorSeverity;
|
| +
|
| + /**
|
| + * The template used to create the message to be displayed for this error.
|
| + */
|
| + final String message;
|
| +
|
| + /**
|
| + * The template used to create the correction to be displayed for this error, or `null` if
|
| + * there is no correction information for this error.
|
| + */
|
| + final String correction;
|
| +
|
| + /**
|
| + * Initialize a newly created error code to have the given severity and message.
|
| + *
|
| + * @param errorSeverity the severity of the error
|
| + * @param message the message template used to create the message to be displayed for the error
|
| + */
|
| + const ParserErrorCode.con1(String name, int ordinal, ErrorSeverity errorSeverity, String message) : this.con2(name, ordinal, errorSeverity, message, null);
|
| +
|
| + /**
|
| + * Initialize a newly created error code to have the given severity, message and correction.
|
| + *
|
| + * @param errorSeverity the severity of the error
|
| + * @param message the template used to create the message to be displayed for the error
|
| + * @param correction the template used to create the correction to be displayed for the error
|
| + */
|
| + const ParserErrorCode.con2(String name, int ordinal, this.errorSeverity, this.message, this.correction) : super(name, ordinal);
|
| +
|
| + /**
|
| + * Initialize a newly created error code to have the given message and a severity of ERROR.
|
| + *
|
| + * @param message the message template used to create the message to be displayed for the error
|
| + */
|
| + const ParserErrorCode.con3(String name, int ordinal, String message) : this.con2(name, ordinal, ErrorSeverity.ERROR, message, null);
|
| +
|
| + /**
|
| + * Initialize a newly created error code to have the given message and a severity of ERROR.
|
| + *
|
| + * @param message the message template used to create the message to be displayed for the error
|
| + * @param correction the template used to create the correction to be displayed for the error
|
| + */
|
| + const ParserErrorCode.con4(String name, int ordinal, String message, String correction) : this.con2(name, ordinal, ErrorSeverity.ERROR, message, correction);
|
| +
|
| + @override
|
| + ErrorType get type => ErrorType.SYNTACTIC_ERROR;
|
| +
|
| + @override
|
| + String get uniqueName => "${runtimeType.toString()}.${name}";
|
| +}
|
| +
|
| +/**
|
| + * Instances of the class `SyntheticKeywordToken` implement a synthetic keyword token.
|
| + */
|
| +class Parser_SyntheticKeywordToken extends KeywordToken {
|
| + /**
|
| + * Initialize a newly created token to represent the given keyword.
|
| + *
|
| + * @param keyword the keyword being represented by this token
|
| + * @param offset the offset from the beginning of the file to the first character in the token
|
| + */
|
| + Parser_SyntheticKeywordToken(Keyword keyword, int offset) : super(keyword, offset);
|
| +
|
| + @override
|
| + Token copy() => new Parser_SyntheticKeywordToken(keyword, offset);
|
| +
|
| + @override
|
| + int get length => 0;
|
| +}
|
| +
|
| +/**
|
| + * Instances of the class `ResolutionCopier` copies resolution information from one AST
|
| + * structure to another as long as the structures of the corresponding children of a pair of nodes
|
| + * are the same.
|
| + */
|
| +class ResolutionCopier implements AstVisitor<bool> {
|
| + /**
|
| + * Copy resolution data from one node to another.
|
| + *
|
| + * @param fromNode the node from which resolution information will be copied
|
| + * @param toNode the node to which resolution information will be copied
|
| + */
|
| + static void copyResolutionData(AstNode fromNode, AstNode toNode) {
|
| + ResolutionCopier copier = new ResolutionCopier();
|
| + copier._isEqualNodes(fromNode, toNode);
|
| + }
|
| +
|
| + /**
|
| + * The AST node with which the node being visited is to be compared. This is only valid at the
|
| + * beginning of each visit method (until [isEqualNodes] is invoked).
|
| + */
|
| + AstNode _toNode;
|
| +
|
| + @override
|
| + bool visitAdjacentStrings(AdjacentStrings node) {
|
| + AdjacentStrings toNode = this._toNode as AdjacentStrings;
|
| + return _isEqualNodeLists(node.strings, toNode.strings);
|
| + }
|
| +
|
| + @override
|
| + bool visitAnnotation(Annotation node) {
|
| + Annotation toNode = this._toNode as Annotation;
|
| + if (javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.atSign, toNode.atSign), _isEqualNodes(node.name, toNode.name)), _isEqualTokens(node.period, toNode.period)), _isEqualNodes(node.constructorName, toNode.constructorName)), _isEqualNodes(node.arguments, toNode.arguments))) {
|
| + toNode.element = node.element;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitArgumentList(ArgumentList node) {
|
| + ArgumentList toNode = this._toNode as ArgumentList;
|
| + return javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), _isEqualNodeLists(node.arguments, toNode.arguments)), _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis));
|
| + }
|
| +
|
| + @override
|
| + bool visitAsExpression(AsExpression node) {
|
| + AsExpression toNode = this._toNode as AsExpression;
|
| + if (javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.expression, toNode.expression), _isEqualTokens(node.asOperator, toNode.asOperator)), _isEqualNodes(node.type, toNode.type))) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitAssertStatement(AssertStatement node) {
|
| + AssertStatement toNode = this._toNode as AssertStatement;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.keyword, toNode.keyword), _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis)), _isEqualNodes(node.condition, toNode.condition)), _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis)), _isEqualTokens(node.semicolon, toNode.semicolon));
|
| + }
|
| +
|
| + @override
|
| + bool visitAssignmentExpression(AssignmentExpression node) {
|
| + AssignmentExpression toNode = this._toNode as AssignmentExpression;
|
| + if (javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.leftHandSide, toNode.leftHandSide), _isEqualTokens(node.operator, toNode.operator)), _isEqualNodes(node.rightHandSide, toNode.rightHandSide))) {
|
| + toNode.propagatedElement = node.propagatedElement;
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticElement = node.staticElement;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitAwaitExpression(AwaitExpression node) {
|
| + AwaitExpression toNode = this._toNode as AwaitExpression;
|
| + return javaBooleanAnd(_isEqualTokens(node.awaitKeyword, toNode.awaitKeyword), _isEqualNodes(node.expression, toNode.expression));
|
| + }
|
| +
|
| + @override
|
| + bool visitBinaryExpression(BinaryExpression node) {
|
| + BinaryExpression toNode = this._toNode as BinaryExpression;
|
| + if (javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.leftOperand, toNode.leftOperand), _isEqualTokens(node.operator, toNode.operator)), _isEqualNodes(node.rightOperand, toNode.rightOperand))) {
|
| + toNode.propagatedElement = node.propagatedElement;
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticElement = node.staticElement;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitBlock(Block node) {
|
| + Block toNode = this._toNode as Block;
|
| + return javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.leftBracket, toNode.leftBracket), _isEqualNodeLists(node.statements, toNode.statements)), _isEqualTokens(node.rightBracket, toNode.rightBracket));
|
| + }
|
| +
|
| + @override
|
| + bool visitBlockFunctionBody(BlockFunctionBody node) {
|
| + BlockFunctionBody toNode = this._toNode as BlockFunctionBody;
|
| + return _isEqualNodes(node.block, toNode.block);
|
| + }
|
| +
|
| + @override
|
| + bool visitBooleanLiteral(BooleanLiteral node) {
|
| + BooleanLiteral toNode = this._toNode as BooleanLiteral;
|
| + if (javaBooleanAnd(_isEqualTokens(node.literal, toNode.literal), node.value == toNode.value)) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitBreakStatement(BreakStatement node) {
|
| + BreakStatement toNode = this._toNode as BreakStatement;
|
| + return javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.keyword, toNode.keyword), _isEqualNodes(node.label, toNode.label)), _isEqualTokens(node.semicolon, toNode.semicolon));
|
| + }
|
| +
|
| + @override
|
| + bool visitCascadeExpression(CascadeExpression node) {
|
| + CascadeExpression toNode = this._toNode as CascadeExpression;
|
| + if (javaBooleanAnd(_isEqualNodes(node.target, toNode.target), _isEqualNodeLists(node.cascadeSections, toNode.cascadeSections))) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitCatchClause(CatchClause node) {
|
| + CatchClause toNode = this._toNode as CatchClause;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.onKeyword, toNode.onKeyword), _isEqualNodes(node.exceptionType, toNode.exceptionType)), _isEqualTokens(node.catchKeyword, toNode.catchKeyword)), _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis)), _isEqualNodes(node.exceptionParameter, toNode.exceptionParameter)), _isEqualTokens(node.comma, toNode.comma)), _isEqualNodes(node.stackTraceParameter, toNode.stackTraceParameter)), _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis)), _isEqualNodes(node.body, toNode.body));
|
| + }
|
| +
|
| + @override
|
| + bool visitClassDeclaration(ClassDeclaration node) {
|
| + ClassDeclaration toNode = this._toNode as ClassDeclaration;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualTokens(node.abstractKeyword, toNode.abstractKeyword)), _isEqualTokens(node.classKeyword, toNode.classKeyword)), _isEqualNodes(node.name, toNode.name)), _isEqualNodes(node.typeParameters, toNode.typeParameters)), _isEqualNodes(node.extendsClause, toNode.extendsClause)), _isEqualNodes(node.withClause, toNode.withClause)), _isEqualNodes(node.implementsClause, toNode.implementsClause)), _isEqualTokens(node.leftBracket, toNode.leftBracket)), _isEqualNodeLists(node.members, toNode.members)), _isEqualTokens(node.rightBracket, toNode.rightBracket));
|
| + }
|
| +
|
| + @override
|
| + bool visitClassTypeAlias(ClassTypeAlias node) {
|
| + ClassTypeAlias toNode = this._toNode as ClassTypeAlias;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualTokens(node.keyword, toNode.keyword)), _isEqualNodes(node.name, toNode.name)), _isEqualNodes(node.typeParameters, toNode.typeParameters)), _isEqualTokens(node.equals, toNode.equals)), _isEqualTokens(node.abstractKeyword, toNode.abstractKeyword)), _isEqualNodes(node.superclass, toNode.superclass)), _isEqualNodes(node.withClause, toNode.withClause)), _isEqualNodes(node.implementsClause, toNode.implementsClause)), _isEqualTokens(node.semicolon, toNode.semicolon));
|
| + }
|
| +
|
| + @override
|
| + bool visitComment(Comment node) {
|
| + Comment toNode = this._toNode as Comment;
|
| + return _isEqualNodeLists(node.references, toNode.references);
|
| + }
|
| +
|
| + @override
|
| + bool visitCommentReference(CommentReference node) {
|
| + CommentReference toNode = this._toNode as CommentReference;
|
| + return javaBooleanAnd(_isEqualTokens(node.newKeyword, toNode.newKeyword), _isEqualNodes(node.identifier, toNode.identifier));
|
| + }
|
| +
|
| + @override
|
| + bool visitCompilationUnit(CompilationUnit node) {
|
| + CompilationUnit toNode = this._toNode as CompilationUnit;
|
| + if (javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.beginToken, toNode.beginToken), _isEqualNodes(node.scriptTag, toNode.scriptTag)), _isEqualNodeLists(node.directives, toNode.directives)), _isEqualNodeLists(node.declarations, toNode.declarations)), _isEqualTokens(node.endToken, toNode.endToken))) {
|
| + toNode.element = node.element;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitConditionalExpression(ConditionalExpression node) {
|
| + ConditionalExpression toNode = this._toNode as ConditionalExpression;
|
| + if (javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.condition, toNode.condition), _isEqualTokens(node.question, toNode.question)), _isEqualNodes(node.thenExpression, toNode.thenExpression)), _isEqualTokens(node.colon, toNode.colon)), _isEqualNodes(node.elseExpression, toNode.elseExpression))) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitConstructorDeclaration(ConstructorDeclaration node) {
|
| + ConstructorDeclaration toNode = this._toNode as ConstructorDeclaration;
|
| + if (javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualTokens(node.externalKeyword, toNode.externalKeyword)), _isEqualTokens(node.constKeyword, toNode.constKeyword)), _isEqualTokens(node.factoryKeyword, toNode.factoryKeyword)), _isEqualNodes(node.returnType, toNode.returnType)), _isEqualTokens(node.period, toNode.period)), _isEqualNodes(node.name, toNode.name)), _isEqualNodes(node.parameters, toNode.parameters)), _isEqualTokens(node.separator, toNode.separator)), _isEqualNodeLists(node.initializers, toNode.initializers)), _isEqualNodes(node.redirectedConstructor, toNode.redirectedConstructor)), _isEqualNodes(node.body, toNode.body))) {
|
| + toNode.element = node.element;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitConstructorFieldInitializer(ConstructorFieldInitializer node) {
|
| + ConstructorFieldInitializer toNode = this._toNode as ConstructorFieldInitializer;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.keyword, toNode.keyword), _isEqualTokens(node.period, toNode.period)), _isEqualNodes(node.fieldName, toNode.fieldName)), _isEqualTokens(node.equals, toNode.equals)), _isEqualNodes(node.expression, toNode.expression));
|
| + }
|
| +
|
| + @override
|
| + bool visitConstructorName(ConstructorName node) {
|
| + ConstructorName toNode = this._toNode as ConstructorName;
|
| + if (javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.type, toNode.type), _isEqualTokens(node.period, toNode.period)), _isEqualNodes(node.name, toNode.name))) {
|
| + toNode.staticElement = node.staticElement;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitContinueStatement(ContinueStatement node) {
|
| + ContinueStatement toNode = this._toNode as ContinueStatement;
|
| + return javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.keyword, toNode.keyword), _isEqualNodes(node.label, toNode.label)), _isEqualTokens(node.semicolon, toNode.semicolon));
|
| + }
|
| +
|
| + @override
|
| + bool visitDeclaredIdentifier(DeclaredIdentifier node) {
|
| + DeclaredIdentifier toNode = this._toNode as DeclaredIdentifier;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualTokens(node.keyword, toNode.keyword)), _isEqualNodes(node.type, toNode.type)), _isEqualNodes(node.identifier, toNode.identifier));
|
| + }
|
| +
|
| + @override
|
| + bool visitDefaultFormalParameter(DefaultFormalParameter node) {
|
| + DefaultFormalParameter toNode = this._toNode as DefaultFormalParameter;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.parameter, toNode.parameter), node.kind == toNode.kind), _isEqualTokens(node.separator, toNode.separator)), _isEqualNodes(node.defaultValue, toNode.defaultValue));
|
| + }
|
| +
|
| + @override
|
| + bool visitDoStatement(DoStatement node) {
|
| + DoStatement toNode = this._toNode as DoStatement;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.doKeyword, toNode.doKeyword), _isEqualNodes(node.body, toNode.body)), _isEqualTokens(node.whileKeyword, toNode.whileKeyword)), _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis)), _isEqualNodes(node.condition, toNode.condition)), _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis)), _isEqualTokens(node.semicolon, toNode.semicolon));
|
| + }
|
| +
|
| + @override
|
| + bool visitDoubleLiteral(DoubleLiteral node) {
|
| + DoubleLiteral toNode = this._toNode as DoubleLiteral;
|
| + if (javaBooleanAnd(_isEqualTokens(node.literal, toNode.literal), node.value == toNode.value)) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitEmptyFunctionBody(EmptyFunctionBody node) {
|
| + EmptyFunctionBody toNode = this._toNode as EmptyFunctionBody;
|
| + return _isEqualTokens(node.semicolon, toNode.semicolon);
|
| + }
|
| +
|
| + @override
|
| + bool visitEmptyStatement(EmptyStatement node) {
|
| + EmptyStatement toNode = this._toNode as EmptyStatement;
|
| + return _isEqualTokens(node.semicolon, toNode.semicolon);
|
| + }
|
| +
|
| + @override
|
| + bool visitEnumConstantDeclaration(EnumConstantDeclaration node) {
|
| + EnumConstantDeclaration toNode = this._toNode as EnumConstantDeclaration;
|
| + return javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualNodes(node.name, toNode.name));
|
| + }
|
| +
|
| + @override
|
| + bool visitEnumDeclaration(EnumDeclaration node) {
|
| + EnumDeclaration toNode = this._toNode as EnumDeclaration;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualTokens(node.keyword, toNode.keyword)), _isEqualNodes(node.name, toNode.name)), _isEqualTokens(node.leftBracket, toNode.leftBracket)), _isEqualNodeLists(node.constants, toNode.constants)), _isEqualTokens(node.rightBracket, toNode.rightBracket));
|
| + }
|
| +
|
| + @override
|
| + bool visitExportDirective(ExportDirective node) {
|
| + ExportDirective toNode = this._toNode as ExportDirective;
|
| + if (javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualTokens(node.keyword, toNode.keyword)), _isEqualNodes(node.uri, toNode.uri)), _isEqualNodeLists(node.combinators, toNode.combinators)), _isEqualTokens(node.semicolon, toNode.semicolon))) {
|
| + toNode.element = node.element;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitExpressionFunctionBody(ExpressionFunctionBody node) {
|
| + ExpressionFunctionBody toNode = this._toNode as ExpressionFunctionBody;
|
| + return javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.functionDefinition, toNode.functionDefinition), _isEqualNodes(node.expression, toNode.expression)), _isEqualTokens(node.semicolon, toNode.semicolon));
|
| + }
|
| +
|
| + @override
|
| + bool visitExpressionStatement(ExpressionStatement node) {
|
| + ExpressionStatement toNode = this._toNode as ExpressionStatement;
|
| + return javaBooleanAnd(_isEqualNodes(node.expression, toNode.expression), _isEqualTokens(node.semicolon, toNode.semicolon));
|
| + }
|
| +
|
| + @override
|
| + bool visitExtendsClause(ExtendsClause node) {
|
| + ExtendsClause toNode = this._toNode as ExtendsClause;
|
| + return javaBooleanAnd(_isEqualTokens(node.keyword, toNode.keyword), _isEqualNodes(node.superclass, toNode.superclass));
|
| + }
|
| +
|
| + @override
|
| + bool visitFieldDeclaration(FieldDeclaration node) {
|
| + FieldDeclaration toNode = this._toNode as FieldDeclaration;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualTokens(node.staticKeyword, toNode.staticKeyword)), _isEqualNodes(node.fields, toNode.fields)), _isEqualTokens(node.semicolon, toNode.semicolon));
|
| + }
|
| +
|
| + @override
|
| + bool visitFieldFormalParameter(FieldFormalParameter node) {
|
| + FieldFormalParameter toNode = this._toNode as FieldFormalParameter;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualTokens(node.keyword, toNode.keyword)), _isEqualNodes(node.type, toNode.type)), _isEqualTokens(node.thisToken, toNode.thisToken)), _isEqualTokens(node.period, toNode.period)), _isEqualNodes(node.identifier, toNode.identifier));
|
| + }
|
| +
|
| + @override
|
| + bool visitForEachStatement(ForEachStatement node) {
|
| + ForEachStatement toNode = this._toNode as ForEachStatement;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.forKeyword, toNode.forKeyword), _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis)), _isEqualNodes(node.loopVariable, toNode.loopVariable)), _isEqualTokens(node.inKeyword, toNode.inKeyword)), _isEqualNodes(node.iterator, toNode.iterator)), _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis)), _isEqualNodes(node.body, toNode.body));
|
| + }
|
| +
|
| + @override
|
| + bool visitFormalParameterList(FormalParameterList node) {
|
| + FormalParameterList toNode = this._toNode as FormalParameterList;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), _isEqualNodeLists(node.parameters, toNode.parameters)), _isEqualTokens(node.leftDelimiter, toNode.leftDelimiter)), _isEqualTokens(node.rightDelimiter, toNode.rightDelimiter)), _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis));
|
| + }
|
| +
|
| + @override
|
| + bool visitForStatement(ForStatement node) {
|
| + ForStatement toNode = this._toNode as ForStatement;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.forKeyword, toNode.forKeyword), _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis)), _isEqualNodes(node.variables, toNode.variables)), _isEqualNodes(node.initialization, toNode.initialization)), _isEqualTokens(node.leftSeparator, toNode.leftSeparator)), _isEqualNodes(node.condition, toNode.condition)), _isEqualTokens(node.rightSeparator, toNode.rightSeparator)), _isEqualNodeLists(node.updaters, toNode.updaters)), _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis)), _isEqualNodes(node.body, toNode.body));
|
| + }
|
| +
|
| + @override
|
| + bool visitFunctionDeclaration(FunctionDeclaration node) {
|
| + FunctionDeclaration toNode = this._toNode as FunctionDeclaration;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualTokens(node.externalKeyword, toNode.externalKeyword)), _isEqualNodes(node.returnType, toNode.returnType)), _isEqualTokens(node.propertyKeyword, toNode.propertyKeyword)), _isEqualNodes(node.name, toNode.name)), _isEqualNodes(node.functionExpression, toNode.functionExpression));
|
| + }
|
| +
|
| + @override
|
| + bool visitFunctionDeclarationStatement(FunctionDeclarationStatement node) {
|
| + FunctionDeclarationStatement toNode = this._toNode as FunctionDeclarationStatement;
|
| + return _isEqualNodes(node.functionDeclaration, toNode.functionDeclaration);
|
| + }
|
| +
|
| + @override
|
| + bool visitFunctionExpression(FunctionExpression node) {
|
| + FunctionExpression toNode = this._toNode as FunctionExpression;
|
| + if (javaBooleanAnd(_isEqualNodes(node.parameters, toNode.parameters), _isEqualNodes(node.body, toNode.body))) {
|
| + toNode.element = node.element;
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
|
| + FunctionExpressionInvocation toNode = this._toNode as FunctionExpressionInvocation;
|
| + if (javaBooleanAnd(_isEqualNodes(node.function, toNode.function), _isEqualNodes(node.argumentList, toNode.argumentList))) {
|
| + toNode.propagatedElement = node.propagatedElement;
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticElement = node.staticElement;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitFunctionTypeAlias(FunctionTypeAlias node) {
|
| + FunctionTypeAlias toNode = this._toNode as FunctionTypeAlias;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualTokens(node.keyword, toNode.keyword)), _isEqualNodes(node.returnType, toNode.returnType)), _isEqualNodes(node.name, toNode.name)), _isEqualNodes(node.typeParameters, toNode.typeParameters)), _isEqualNodes(node.parameters, toNode.parameters)), _isEqualTokens(node.semicolon, toNode.semicolon));
|
| + }
|
| +
|
| + @override
|
| + bool visitFunctionTypedFormalParameter(FunctionTypedFormalParameter node) {
|
| + FunctionTypedFormalParameter toNode = this._toNode as FunctionTypedFormalParameter;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualNodes(node.returnType, toNode.returnType)), _isEqualNodes(node.identifier, toNode.identifier)), _isEqualNodes(node.parameters, toNode.parameters));
|
| + }
|
| +
|
| + @override
|
| + bool visitHideCombinator(HideCombinator node) {
|
| + HideCombinator toNode = this._toNode as HideCombinator;
|
| + return javaBooleanAnd(_isEqualTokens(node.keyword, toNode.keyword), _isEqualNodeLists(node.hiddenNames, toNode.hiddenNames));
|
| + }
|
| +
|
| + @override
|
| + bool visitIfStatement(IfStatement node) {
|
| + IfStatement toNode = this._toNode as IfStatement;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.ifKeyword, toNode.ifKeyword), _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis)), _isEqualNodes(node.condition, toNode.condition)), _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis)), _isEqualNodes(node.thenStatement, toNode.thenStatement)), _isEqualTokens(node.elseKeyword, toNode.elseKeyword)), _isEqualNodes(node.elseStatement, toNode.elseStatement));
|
| + }
|
| +
|
| + @override
|
| + bool visitImplementsClause(ImplementsClause node) {
|
| + ImplementsClause toNode = this._toNode as ImplementsClause;
|
| + return javaBooleanAnd(_isEqualTokens(node.keyword, toNode.keyword), _isEqualNodeLists(node.interfaces, toNode.interfaces));
|
| + }
|
| +
|
| + @override
|
| + bool visitImportDirective(ImportDirective node) {
|
| + ImportDirective toNode = this._toNode as ImportDirective;
|
| + if (javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualTokens(node.keyword, toNode.keyword)), _isEqualNodes(node.uri, toNode.uri)), _isEqualTokens(node.asToken, toNode.asToken)), _isEqualNodes(node.prefix, toNode.prefix)), _isEqualNodeLists(node.combinators, toNode.combinators)), _isEqualTokens(node.semicolon, toNode.semicolon))) {
|
| + toNode.element = node.element;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitIndexExpression(IndexExpression node) {
|
| + IndexExpression toNode = this._toNode as IndexExpression;
|
| + if (javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.target, toNode.target), _isEqualTokens(node.leftBracket, toNode.leftBracket)), _isEqualNodes(node.index, toNode.index)), _isEqualTokens(node.rightBracket, toNode.rightBracket))) {
|
| + toNode.auxiliaryElements = node.auxiliaryElements;
|
| + toNode.propagatedElement = node.propagatedElement;
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticElement = node.staticElement;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitInstanceCreationExpression(InstanceCreationExpression node) {
|
| + InstanceCreationExpression toNode = this._toNode as InstanceCreationExpression;
|
| + if (javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.keyword, toNode.keyword), _isEqualNodes(node.constructorName, toNode.constructorName)), _isEqualNodes(node.argumentList, toNode.argumentList))) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticElement = node.staticElement;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitIntegerLiteral(IntegerLiteral node) {
|
| + IntegerLiteral toNode = this._toNode as IntegerLiteral;
|
| + if (javaBooleanAnd(_isEqualTokens(node.literal, toNode.literal), identical(node.value, toNode.value))) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitInterpolationExpression(InterpolationExpression node) {
|
| + InterpolationExpression toNode = this._toNode as InterpolationExpression;
|
| + return javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.leftBracket, toNode.leftBracket), _isEqualNodes(node.expression, toNode.expression)), _isEqualTokens(node.rightBracket, toNode.rightBracket));
|
| + }
|
| +
|
| + @override
|
| + bool visitInterpolationString(InterpolationString node) {
|
| + InterpolationString toNode = this._toNode as InterpolationString;
|
| + return javaBooleanAnd(_isEqualTokens(node.contents, toNode.contents), node.value == toNode.value);
|
| + }
|
| +
|
| + @override
|
| + bool visitIsExpression(IsExpression node) {
|
| + IsExpression toNode = this._toNode as IsExpression;
|
| + if (javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.expression, toNode.expression), _isEqualTokens(node.isOperator, toNode.isOperator)), _isEqualTokens(node.notOperator, toNode.notOperator)), _isEqualNodes(node.type, toNode.type))) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitLabel(Label node) {
|
| + Label toNode = this._toNode as Label;
|
| + return javaBooleanAnd(_isEqualNodes(node.label, toNode.label), _isEqualTokens(node.colon, toNode.colon));
|
| + }
|
| +
|
| + @override
|
| + bool visitLabeledStatement(LabeledStatement node) {
|
| + LabeledStatement toNode = this._toNode as LabeledStatement;
|
| + return javaBooleanAnd(_isEqualNodeLists(node.labels, toNode.labels), _isEqualNodes(node.statement, toNode.statement));
|
| + }
|
| +
|
| + @override
|
| + bool visitLibraryDirective(LibraryDirective node) {
|
| + LibraryDirective toNode = this._toNode as LibraryDirective;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualTokens(node.libraryToken, toNode.libraryToken)), _isEqualNodes(node.name, toNode.name)), _isEqualTokens(node.semicolon, toNode.semicolon));
|
| + }
|
| +
|
| + @override
|
| + bool visitLibraryIdentifier(LibraryIdentifier node) {
|
| + LibraryIdentifier toNode = this._toNode as LibraryIdentifier;
|
| + if (_isEqualNodeLists(node.components, toNode.components)) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitListLiteral(ListLiteral node) {
|
| + ListLiteral toNode = this._toNode as ListLiteral;
|
| + if (javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.constKeyword, toNode.constKeyword), _isEqualNodes(node.typeArguments, toNode.typeArguments)), _isEqualTokens(node.leftBracket, toNode.leftBracket)), _isEqualNodeLists(node.elements, toNode.elements)), _isEqualTokens(node.rightBracket, toNode.rightBracket))) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitMapLiteral(MapLiteral node) {
|
| + MapLiteral toNode = this._toNode as MapLiteral;
|
| + if (javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.constKeyword, toNode.constKeyword), _isEqualNodes(node.typeArguments, toNode.typeArguments)), _isEqualTokens(node.leftBracket, toNode.leftBracket)), _isEqualNodeLists(node.entries, toNode.entries)), _isEqualTokens(node.rightBracket, toNode.rightBracket))) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitMapLiteralEntry(MapLiteralEntry node) {
|
| + MapLiteralEntry toNode = this._toNode as MapLiteralEntry;
|
| + return javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.key, toNode.key), _isEqualTokens(node.separator, toNode.separator)), _isEqualNodes(node.value, toNode.value));
|
| + }
|
| +
|
| + @override
|
| + bool visitMethodDeclaration(MethodDeclaration node) {
|
| + MethodDeclaration toNode = this._toNode as MethodDeclaration;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualTokens(node.externalKeyword, toNode.externalKeyword)), _isEqualTokens(node.modifierKeyword, toNode.modifierKeyword)), _isEqualNodes(node.returnType, toNode.returnType)), _isEqualTokens(node.propertyKeyword, toNode.propertyKeyword)), _isEqualTokens(node.propertyKeyword, toNode.propertyKeyword)), _isEqualNodes(node.name, toNode.name)), _isEqualNodes(node.parameters, toNode.parameters)), _isEqualNodes(node.body, toNode.body));
|
| + }
|
| +
|
| + @override
|
| + bool visitMethodInvocation(MethodInvocation node) {
|
| + MethodInvocation toNode = this._toNode as MethodInvocation;
|
| + if (javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.target, toNode.target), _isEqualTokens(node.period, toNode.period)), _isEqualNodes(node.methodName, toNode.methodName)), _isEqualNodes(node.argumentList, toNode.argumentList))) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitNamedExpression(NamedExpression node) {
|
| + NamedExpression toNode = this._toNode as NamedExpression;
|
| + if (javaBooleanAnd(_isEqualNodes(node.name, toNode.name), _isEqualNodes(node.expression, toNode.expression))) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitNativeClause(NativeClause node) {
|
| + NativeClause toNode = this._toNode as NativeClause;
|
| + return javaBooleanAnd(_isEqualTokens(node.keyword, toNode.keyword), _isEqualNodes(node.name, toNode.name));
|
| + }
|
| +
|
| + @override
|
| + bool visitNativeFunctionBody(NativeFunctionBody node) {
|
| + NativeFunctionBody toNode = this._toNode as NativeFunctionBody;
|
| + return javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.nativeToken, toNode.nativeToken), _isEqualNodes(node.stringLiteral, toNode.stringLiteral)), _isEqualTokens(node.semicolon, toNode.semicolon));
|
| + }
|
| +
|
| + @override
|
| + bool visitNullLiteral(NullLiteral node) {
|
| + NullLiteral toNode = this._toNode as NullLiteral;
|
| + if (_isEqualTokens(node.literal, toNode.literal)) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitParenthesizedExpression(ParenthesizedExpression node) {
|
| + ParenthesizedExpression toNode = this._toNode as ParenthesizedExpression;
|
| + if (javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.leftParenthesis, toNode.leftParenthesis), _isEqualNodes(node.expression, toNode.expression)), _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis))) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitPartDirective(PartDirective node) {
|
| + PartDirective toNode = this._toNode as PartDirective;
|
| + if (javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualTokens(node.partToken, toNode.partToken)), _isEqualNodes(node.uri, toNode.uri)), _isEqualTokens(node.semicolon, toNode.semicolon))) {
|
| + toNode.element = node.element;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitPartOfDirective(PartOfDirective node) {
|
| + PartOfDirective toNode = this._toNode as PartOfDirective;
|
| + if (javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualTokens(node.partToken, toNode.partToken)), _isEqualTokens(node.ofToken, toNode.ofToken)), _isEqualNodes(node.libraryName, toNode.libraryName)), _isEqualTokens(node.semicolon, toNode.semicolon))) {
|
| + toNode.element = node.element;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitPostfixExpression(PostfixExpression node) {
|
| + PostfixExpression toNode = this._toNode as PostfixExpression;
|
| + if (javaBooleanAnd(_isEqualNodes(node.operand, toNode.operand), _isEqualTokens(node.operator, toNode.operator))) {
|
| + toNode.propagatedElement = node.propagatedElement;
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticElement = node.staticElement;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitPrefixedIdentifier(PrefixedIdentifier node) {
|
| + PrefixedIdentifier toNode = this._toNode as PrefixedIdentifier;
|
| + if (javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.prefix, toNode.prefix), _isEqualTokens(node.period, toNode.period)), _isEqualNodes(node.identifier, toNode.identifier))) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitPrefixExpression(PrefixExpression node) {
|
| + PrefixExpression toNode = this._toNode as PrefixExpression;
|
| + if (javaBooleanAnd(_isEqualTokens(node.operator, toNode.operator), _isEqualNodes(node.operand, toNode.operand))) {
|
| + toNode.propagatedElement = node.propagatedElement;
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticElement = node.staticElement;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitPropertyAccess(PropertyAccess node) {
|
| + PropertyAccess toNode = this._toNode as PropertyAccess;
|
| + if (javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.target, toNode.target), _isEqualTokens(node.operator, toNode.operator)), _isEqualNodes(node.propertyName, toNode.propertyName))) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitRedirectingConstructorInvocation(RedirectingConstructorInvocation node) {
|
| + RedirectingConstructorInvocation toNode = this._toNode as RedirectingConstructorInvocation;
|
| + if (javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.keyword, toNode.keyword), _isEqualTokens(node.period, toNode.period)), _isEqualNodes(node.constructorName, toNode.constructorName)), _isEqualNodes(node.argumentList, toNode.argumentList))) {
|
| + toNode.staticElement = node.staticElement;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitRethrowExpression(RethrowExpression node) {
|
| + RethrowExpression toNode = this._toNode as RethrowExpression;
|
| + if (_isEqualTokens(node.keyword, toNode.keyword)) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitReturnStatement(ReturnStatement node) {
|
| + ReturnStatement toNode = this._toNode as ReturnStatement;
|
| + return javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.keyword, toNode.keyword), _isEqualNodes(node.expression, toNode.expression)), _isEqualTokens(node.semicolon, toNode.semicolon));
|
| + }
|
| +
|
| + @override
|
| + bool visitScriptTag(ScriptTag node) {
|
| + ScriptTag toNode = this._toNode as ScriptTag;
|
| + return _isEqualTokens(node.scriptTag, toNode.scriptTag);
|
| + }
|
| +
|
| + @override
|
| + bool visitShowCombinator(ShowCombinator node) {
|
| + ShowCombinator toNode = this._toNode as ShowCombinator;
|
| + return javaBooleanAnd(_isEqualTokens(node.keyword, toNode.keyword), _isEqualNodeLists(node.shownNames, toNode.shownNames));
|
| + }
|
| +
|
| + @override
|
| + bool visitSimpleFormalParameter(SimpleFormalParameter node) {
|
| + SimpleFormalParameter toNode = this._toNode as SimpleFormalParameter;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualTokens(node.keyword, toNode.keyword)), _isEqualNodes(node.type, toNode.type)), _isEqualNodes(node.identifier, toNode.identifier));
|
| + }
|
| +
|
| + @override
|
| + bool visitSimpleIdentifier(SimpleIdentifier node) {
|
| + SimpleIdentifier toNode = this._toNode as SimpleIdentifier;
|
| + if (_isEqualTokens(node.token, toNode.token)) {
|
| + toNode.staticElement = node.staticElement;
|
| + toNode.staticType = node.staticType;
|
| + toNode.propagatedElement = node.propagatedElement;
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.auxiliaryElements = node.auxiliaryElements;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitSimpleStringLiteral(SimpleStringLiteral node) {
|
| + SimpleStringLiteral toNode = this._toNode as SimpleStringLiteral;
|
| + if (javaBooleanAnd(_isEqualTokens(node.literal, toNode.literal), identical(node.value, toNode.value))) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitStringInterpolation(StringInterpolation node) {
|
| + StringInterpolation toNode = this._toNode as StringInterpolation;
|
| + if (_isEqualNodeLists(node.elements, toNode.elements)) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitSuperConstructorInvocation(SuperConstructorInvocation node) {
|
| + SuperConstructorInvocation toNode = this._toNode as SuperConstructorInvocation;
|
| + if (javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.keyword, toNode.keyword), _isEqualTokens(node.period, toNode.period)), _isEqualNodes(node.constructorName, toNode.constructorName)), _isEqualNodes(node.argumentList, toNode.argumentList))) {
|
| + toNode.staticElement = node.staticElement;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitSuperExpression(SuperExpression node) {
|
| + SuperExpression toNode = this._toNode as SuperExpression;
|
| + if (_isEqualTokens(node.keyword, toNode.keyword)) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitSwitchCase(SwitchCase node) {
|
| + SwitchCase toNode = this._toNode as SwitchCase;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodeLists(node.labels, toNode.labels), _isEqualTokens(node.keyword, toNode.keyword)), _isEqualNodes(node.expression, toNode.expression)), _isEqualTokens(node.colon, toNode.colon)), _isEqualNodeLists(node.statements, toNode.statements));
|
| + }
|
| +
|
| + @override
|
| + bool visitSwitchDefault(SwitchDefault node) {
|
| + SwitchDefault toNode = this._toNode as SwitchDefault;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodeLists(node.labels, toNode.labels), _isEqualTokens(node.keyword, toNode.keyword)), _isEqualTokens(node.colon, toNode.colon)), _isEqualNodeLists(node.statements, toNode.statements));
|
| + }
|
| +
|
| + @override
|
| + bool visitSwitchStatement(SwitchStatement node) {
|
| + SwitchStatement toNode = this._toNode as SwitchStatement;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.keyword, toNode.keyword), _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis)), _isEqualNodes(node.expression, toNode.expression)), _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis)), _isEqualTokens(node.leftBracket, toNode.leftBracket)), _isEqualNodeLists(node.members, toNode.members)), _isEqualTokens(node.rightBracket, toNode.rightBracket));
|
| + }
|
| +
|
| + @override
|
| + bool visitSymbolLiteral(SymbolLiteral node) {
|
| + SymbolLiteral toNode = this._toNode as SymbolLiteral;
|
| + if (javaBooleanAnd(_isEqualTokens(node.poundSign, toNode.poundSign), _isEqualTokenLists(node.components, toNode.components))) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitThisExpression(ThisExpression node) {
|
| + ThisExpression toNode = this._toNode as ThisExpression;
|
| + if (_isEqualTokens(node.keyword, toNode.keyword)) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitThrowExpression(ThrowExpression node) {
|
| + ThrowExpression toNode = this._toNode as ThrowExpression;
|
| + if (javaBooleanAnd(_isEqualTokens(node.keyword, toNode.keyword), _isEqualNodes(node.expression, toNode.expression))) {
|
| + toNode.propagatedType = node.propagatedType;
|
| + toNode.staticType = node.staticType;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitTopLevelVariableDeclaration(TopLevelVariableDeclaration node) {
|
| + TopLevelVariableDeclaration toNode = this._toNode as TopLevelVariableDeclaration;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualNodes(node.variables, toNode.variables)), _isEqualTokens(node.semicolon, toNode.semicolon));
|
| + }
|
| +
|
| + @override
|
| + bool visitTryStatement(TryStatement node) {
|
| + TryStatement toNode = this._toNode as TryStatement;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.tryKeyword, toNode.tryKeyword), _isEqualNodes(node.body, toNode.body)), _isEqualNodeLists(node.catchClauses, toNode.catchClauses)), _isEqualTokens(node.finallyKeyword, toNode.finallyKeyword)), _isEqualNodes(node.finallyBlock, toNode.finallyBlock));
|
| + }
|
| +
|
| + @override
|
| + bool visitTypeArgumentList(TypeArgumentList node) {
|
| + TypeArgumentList toNode = this._toNode as TypeArgumentList;
|
| + return javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.leftBracket, toNode.leftBracket), _isEqualNodeLists(node.arguments, toNode.arguments)), _isEqualTokens(node.rightBracket, toNode.rightBracket));
|
| + }
|
| +
|
| + @override
|
| + bool visitTypeName(TypeName node) {
|
| + TypeName toNode = this._toNode as TypeName;
|
| + if (javaBooleanAnd(_isEqualNodes(node.name, toNode.name), _isEqualNodes(node.typeArguments, toNode.typeArguments))) {
|
| + toNode.type = node.type;
|
| + return true;
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + @override
|
| + bool visitTypeParameter(TypeParameter node) {
|
| + TypeParameter toNode = this._toNode as TypeParameter;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualNodes(node.name, toNode.name)), _isEqualTokens(node.keyword, toNode.keyword)), _isEqualNodes(node.bound, toNode.bound));
|
| + }
|
| +
|
| + @override
|
| + bool visitTypeParameterList(TypeParameterList node) {
|
| + TypeParameterList toNode = this._toNode as TypeParameterList;
|
| + return javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.leftBracket, toNode.leftBracket), _isEqualNodeLists(node.typeParameters, toNode.typeParameters)), _isEqualTokens(node.rightBracket, toNode.rightBracket));
|
| + }
|
| +
|
| + @override
|
| + bool visitVariableDeclaration(VariableDeclaration node) {
|
| + VariableDeclaration toNode = this._toNode as VariableDeclaration;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualNodes(node.name, toNode.name)), _isEqualTokens(node.equals, toNode.equals)), _isEqualNodes(node.initializer, toNode.initializer));
|
| + }
|
| +
|
| + @override
|
| + bool visitVariableDeclarationList(VariableDeclarationList node) {
|
| + VariableDeclarationList toNode = this._toNode as VariableDeclarationList;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualNodes(node.documentationComment, toNode.documentationComment), _isEqualNodeLists(node.metadata, toNode.metadata)), _isEqualTokens(node.keyword, toNode.keyword)), _isEqualNodes(node.type, toNode.type)), _isEqualNodeLists(node.variables, toNode.variables));
|
| + }
|
| +
|
| + @override
|
| + bool visitVariableDeclarationStatement(VariableDeclarationStatement node) {
|
| + VariableDeclarationStatement toNode = this._toNode as VariableDeclarationStatement;
|
| + return javaBooleanAnd(_isEqualNodes(node.variables, toNode.variables), _isEqualTokens(node.semicolon, toNode.semicolon));
|
| + }
|
| +
|
| + @override
|
| + bool visitWhileStatement(WhileStatement node) {
|
| + WhileStatement toNode = this._toNode as WhileStatement;
|
| + return javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.keyword, toNode.keyword), _isEqualTokens(node.leftParenthesis, toNode.leftParenthesis)), _isEqualNodes(node.condition, toNode.condition)), _isEqualTokens(node.rightParenthesis, toNode.rightParenthesis)), _isEqualNodes(node.body, toNode.body));
|
| + }
|
| +
|
| + @override
|
| + bool visitWithClause(WithClause node) {
|
| + WithClause toNode = this._toNode as WithClause;
|
| + return javaBooleanAnd(_isEqualTokens(node.withKeyword, toNode.withKeyword), _isEqualNodeLists(node.mixinTypes, toNode.mixinTypes));
|
| + }
|
| +
|
| + @override
|
| + bool visitYieldStatement(YieldStatement node) {
|
| + YieldStatement toNode = this._toNode as YieldStatement;
|
| + return javaBooleanAnd(javaBooleanAnd(_isEqualTokens(node.yieldKeyword, toNode.yieldKeyword), _isEqualNodes(node.expression, toNode.expression)), _isEqualTokens(node.semicolon, toNode.semicolon));
|
| + }
|
| +
|
| + /**
|
| + * Return `true` if the given lists of AST nodes have the same size and corresponding
|
| + * elements are equal.
|
| + *
|
| + * @param first the first node being compared
|
| + * @param second the second node being compared
|
| + * @return `true` if the given AST nodes have the same size and corresponding elements are
|
| + * equal
|
| + */
|
| + bool _isEqualNodeLists(NodeList first, NodeList second) {
|
| + if (first == null) {
|
| + return second == null;
|
| + } else if (second == null) {
|
| + return false;
|
| + }
|
| + int size = first.length;
|
| + if (second.length != size) {
|
| + return false;
|
| + }
|
| + bool equal = true;
|
| + for (int i = 0; i < size; i++) {
|
| + if (!_isEqualNodes(first[i], second[i])) {
|
| + equal = false;
|
| + }
|
| + }
|
| + return equal;
|
| + }
|
| +
|
| + /**
|
| + * Return `true` if the given AST nodes have the same structure. As a side-effect, if the
|
| + * nodes do have the same structure, any resolution data from the first node will be copied to the
|
| + * second node.
|
| + *
|
| + * @param fromNode the node from which resolution information will be copied
|
| + * @param toNode the node to which resolution information will be copied
|
| + * @return `true` if the given AST nodes have the same structure
|
| + */
|
| + bool _isEqualNodes(AstNode fromNode, AstNode toNode) {
|
| + if (fromNode == null) {
|
| + return toNode == null;
|
| + } else if (toNode == null) {
|
| + return false;
|
| + } else if (fromNode.runtimeType == toNode.runtimeType) {
|
| + this._toNode = toNode;
|
| + return fromNode.accept(this);
|
| + }
|
| + //
|
| + // Check for a simple transformation caused by entering a period.
|
| + //
|
| + if (toNode is PrefixedIdentifier) {
|
| + SimpleIdentifier prefix = toNode.prefix;
|
| + if (fromNode.runtimeType == prefix.runtimeType) {
|
| + this._toNode = prefix;
|
| + return fromNode.accept(this);
|
| + }
|
| + } else if (toNode is PropertyAccess) {
|
| + Expression target = toNode.target;
|
| + if (fromNode.runtimeType == target.runtimeType) {
|
| + this._toNode = target;
|
| + return fromNode.accept(this);
|
| + }
|
| + }
|
| + return false;
|
| + }
|
| +
|
| + /**
|
| + * Return `true` if the given arrays of tokens have the same length and corresponding
|
| + * elements are equal.
|
| + *
|
| + * @param first the first node being compared
|
| + * @param second the second node being compared
|
| + * @return `true` if the given arrays of tokens have the same length and corresponding
|
| + * elements are equal
|
| + */
|
| + bool _isEqualTokenLists(List<Token> first, List<Token> second) {
|
| + int length = first.length;
|
| + if (second.length != length) {
|
| + return false;
|
| + }
|
| + for (int i = 0; i < length; i++) {
|
| + if (!_isEqualTokens(first[i], second[i])) {
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| + }
|
| +
|
| + /**
|
| + * Return `true` if the given tokens have the same structure.
|
| + *
|
| + * @param first the first node being compared
|
| + * @param second the second node being compared
|
| + * @return `true` if the given tokens have the same structure
|
| + */
|
| + bool _isEqualTokens(Token first, Token second) {
|
| + if (first == null) {
|
| + return second == null;
|
| + } else if (second == null) {
|
| + return false;
|
| + }
|
| + return first.lexeme == second.lexeme;
|
| + }
|
| +}
|
| +Map<String, MethodTrampoline> methodTable_Parser = <String, MethodTrampoline> {
|
| + 'parseCompilationUnit_1': new MethodTrampoline(1, (Parser target, arg0) => target.parseCompilationUnit(arg0)),
|
| + 'parseDirectives_1': new MethodTrampoline(1, (Parser target, arg0) => target.parseDirectives(arg0)),
|
| + 'parseExpression_1': new MethodTrampoline(1, (Parser target, arg0) => target.parseExpression(arg0)),
|
| + 'parseStatement_1': new MethodTrampoline(1, (Parser target, arg0) => target.parseStatement(arg0)),
|
| + 'parseStatements_1': new MethodTrampoline(1, (Parser target, arg0) => target.parseStatements(arg0)),
|
| + 'parseAnnotation_0': new MethodTrampoline(0, (Parser target) => target.parseAnnotation()),
|
| + 'parseArgument_0': new MethodTrampoline(0, (Parser target) => target.parseArgument()),
|
| + 'parseArgumentList_0': new MethodTrampoline(0, (Parser target) => target.parseArgumentList()),
|
| + 'parseBitwiseOrExpression_0': new MethodTrampoline(0, (Parser target) => target.parseBitwiseOrExpression()),
|
| + 'parseBlock_0': new MethodTrampoline(0, (Parser target) => target.parseBlock()),
|
| + 'parseClassMember_1': new MethodTrampoline(1, (Parser target, arg0) => target.parseClassMember(arg0)),
|
| + 'parseCompilationUnit_0': new MethodTrampoline(0, (Parser target) => target.parseCompilationUnit2()),
|
| + 'parseConditionalExpression_0': new MethodTrampoline(0, (Parser target) => target.parseConditionalExpression()),
|
| + 'parseConstructorName_0': new MethodTrampoline(0, (Parser target) => target.parseConstructorName()),
|
| + 'parseExpression_0': new MethodTrampoline(0, (Parser target) => target.parseExpression2()),
|
| + 'parseExpressionWithoutCascade_0': new MethodTrampoline(0, (Parser target) => target.parseExpressionWithoutCascade()),
|
| + 'parseExtendsClause_0': new MethodTrampoline(0, (Parser target) => target.parseExtendsClause()),
|
| + 'parseFormalParameterList_0': new MethodTrampoline(0, (Parser target) => target.parseFormalParameterList()),
|
| + 'parseFunctionExpression_0': new MethodTrampoline(0, (Parser target) => target.parseFunctionExpression()),
|
| + 'parseImplementsClause_0': new MethodTrampoline(0, (Parser target) => target.parseImplementsClause()),
|
| + 'parseLabel_0': new MethodTrampoline(0, (Parser target) => target.parseLabel()),
|
| + 'parseLibraryIdentifier_0': new MethodTrampoline(0, (Parser target) => target.parseLibraryIdentifier()),
|
| + 'parseLogicalOrExpression_0': new MethodTrampoline(0, (Parser target) => target.parseLogicalOrExpression()),
|
| + 'parseMapLiteralEntry_0': new MethodTrampoline(0, (Parser target) => target.parseMapLiteralEntry()),
|
| + 'parseNormalFormalParameter_0': new MethodTrampoline(0, (Parser target) => target.parseNormalFormalParameter()),
|
| + 'parsePrefixedIdentifier_0': new MethodTrampoline(0, (Parser target) => target.parsePrefixedIdentifier()),
|
| + 'parseReturnType_0': new MethodTrampoline(0, (Parser target) => target.parseReturnType()),
|
| + 'parseSimpleIdentifier_0': new MethodTrampoline(0, (Parser target) => target.parseSimpleIdentifier()),
|
| + 'parseStatement_0': new MethodTrampoline(0, (Parser target) => target.parseStatement2()),
|
| + 'parseStringLiteral_0': new MethodTrampoline(0, (Parser target) => target.parseStringLiteral()),
|
| + 'parseTypeArgumentList_0': new MethodTrampoline(0, (Parser target) => target.parseTypeArgumentList()),
|
| + 'parseTypeName_0': new MethodTrampoline(0, (Parser target) => target.parseTypeName()),
|
| + 'parseTypeParameter_0': new MethodTrampoline(0, (Parser target) => target.parseTypeParameter()),
|
| + 'parseTypeParameterList_0': new MethodTrampoline(0, (Parser target) => target.parseTypeParameterList()),
|
| + 'parseWithClause_0': new MethodTrampoline(0, (Parser target) => target.parseWithClause()),
|
| + 'advance_0': new MethodTrampoline(0, (Parser target) => target._advance()),
|
| + 'appendScalarValue_5': new MethodTrampoline(5, (Parser target, arg0, arg1, arg2, arg3, arg4) => target._appendScalarValue(arg0, arg1, arg2, arg3, arg4)),
|
| + 'computeStringValue_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target._computeStringValue(arg0, arg1, arg2)),
|
| + 'convertToFunctionDeclaration_1': new MethodTrampoline(1, (Parser target, arg0) => target._convertToFunctionDeclaration(arg0)),
|
| + 'couldBeStartOfCompilationUnitMember_0': new MethodTrampoline(0, (Parser target) => target._couldBeStartOfCompilationUnitMember()),
|
| + 'createSyntheticIdentifier_0': new MethodTrampoline(0, (Parser target) => target._createSyntheticIdentifier()),
|
| + 'createSyntheticKeyword_1': new MethodTrampoline(1, (Parser target, arg0) => target._createSyntheticKeyword(arg0)),
|
| + 'createSyntheticStringLiteral_0': new MethodTrampoline(0, (Parser target) => target._createSyntheticStringLiteral()),
|
| + 'createSyntheticToken_1': new MethodTrampoline(1, (Parser target, arg0) => target._createSyntheticToken(arg0)),
|
| + 'ensureAssignable_1': new MethodTrampoline(1, (Parser target, arg0) => target._ensureAssignable(arg0)),
|
| + 'expect_1': new MethodTrampoline(1, (Parser target, arg0) => target._expect(arg0)),
|
| + 'expectGt_0': new MethodTrampoline(0, (Parser target) => target._expectGt()),
|
| + 'expectKeyword_1': new MethodTrampoline(1, (Parser target, arg0) => target._expectKeyword(arg0)),
|
| + 'expectSemicolon_0': new MethodTrampoline(0, (Parser target) => target._expectSemicolon()),
|
| + 'findRange_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._findRange(arg0, arg1)),
|
| + 'getCodeBlockRanges_1': new MethodTrampoline(1, (Parser target, arg0) => target._getCodeBlockRanges(arg0)),
|
| + 'getEndToken_1': new MethodTrampoline(1, (Parser target, arg0) => target._getEndToken(arg0)),
|
| + 'injectToken_1': new MethodTrampoline(1, (Parser target, arg0) => target._injectToken(arg0)),
|
| + 'isFunctionDeclaration_0': new MethodTrampoline(0, (Parser target) => target._isFunctionDeclaration()),
|
| + 'isFunctionExpression_1': new MethodTrampoline(1, (Parser target, arg0) => target._isFunctionExpression(arg0)),
|
| + 'isHexDigit_1': new MethodTrampoline(1, (Parser target, arg0) => target._isHexDigit(arg0)),
|
| + 'isInitializedVariableDeclaration_0': new MethodTrampoline(0, (Parser target) => target._isInitializedVariableDeclaration()),
|
| + 'isLinkText_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._isLinkText(arg0, arg1)),
|
| + 'isOperator_1': new MethodTrampoline(1, (Parser target, arg0) => target._isOperator(arg0)),
|
| + 'isSwitchMember_0': new MethodTrampoline(0, (Parser target) => target._isSwitchMember()),
|
| + 'isTypedIdentifier_1': new MethodTrampoline(1, (Parser target, arg0) => target._isTypedIdentifier(arg0)),
|
| + 'lexicallyFirst_1': new MethodTrampoline(1, (Parser target, arg0) => target._lexicallyFirst(arg0)),
|
| + 'lockErrorListener_0': new MethodTrampoline(0, (Parser target) => target._lockErrorListener()),
|
| + 'matches_1': new MethodTrampoline(1, (Parser target, arg0) => target._matches(arg0)),
|
| + 'matchesGt_0': new MethodTrampoline(0, (Parser target) => target._matchesGt()),
|
| + 'matchesIdentifier_0': new MethodTrampoline(0, (Parser target) => target._matchesIdentifier()),
|
| + 'matchesKeyword_1': new MethodTrampoline(1, (Parser target, arg0) => target._matchesKeyword(arg0)),
|
| + 'matchesString_1': new MethodTrampoline(1, (Parser target, arg0) => target._matchesString(arg0)),
|
| + 'optional_1': new MethodTrampoline(1, (Parser target, arg0) => target._optional(arg0)),
|
| + 'parseAdditiveExpression_0': new MethodTrampoline(0, (Parser target) => target._parseAdditiveExpression()),
|
| + 'parseAssertStatement_0': new MethodTrampoline(0, (Parser target) => target._parseAssertStatement()),
|
| + 'parseAssignableExpression_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseAssignableExpression(arg0)),
|
| + 'parseAssignableSelector_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._parseAssignableSelector(arg0, arg1)),
|
| + 'parseAwaitExpression_0': new MethodTrampoline(0, (Parser target) => target._parseAwaitExpression()),
|
| + 'parseBitwiseAndExpression_0': new MethodTrampoline(0, (Parser target) => target._parseBitwiseAndExpression()),
|
| + 'parseBitwiseXorExpression_0': new MethodTrampoline(0, (Parser target) => target._parseBitwiseXorExpression()),
|
| + 'parseBreakStatement_0': new MethodTrampoline(0, (Parser target) => target._parseBreakStatement()),
|
| + 'parseCascadeSection_0': new MethodTrampoline(0, (Parser target) => target._parseCascadeSection()),
|
| + 'parseClassDeclaration_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._parseClassDeclaration(arg0, arg1)),
|
| + 'parseClassMembers_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._parseClassMembers(arg0, arg1)),
|
| + 'parseClassTypeAlias_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target._parseClassTypeAlias(arg0, arg1, arg2)),
|
| + 'parseCombinators_0': new MethodTrampoline(0, (Parser target) => target._parseCombinators()),
|
| + 'parseCommentAndMetadata_0': new MethodTrampoline(0, (Parser target) => target._parseCommentAndMetadata()),
|
| + 'parseCommentReference_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._parseCommentReference(arg0, arg1)),
|
| + 'parseCommentReferences_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseCommentReferences(arg0)),
|
| + 'parseCompilationUnitMember_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseCompilationUnitMember(arg0)),
|
| + 'parseConstExpression_0': new MethodTrampoline(0, (Parser target) => target._parseConstExpression()),
|
| + 'parseConstructor_8': new MethodTrampoline(8, (Parser target, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) => target._parseConstructor(arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7)),
|
| + 'parseConstructorFieldInitializer_0': new MethodTrampoline(0, (Parser target) => target._parseConstructorFieldInitializer()),
|
| + 'parseContinueStatement_0': new MethodTrampoline(0, (Parser target) => target._parseContinueStatement()),
|
| + 'parseDirective_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseDirective(arg0)),
|
| + 'parseDirectives_0': new MethodTrampoline(0, (Parser target) => target._parseDirectives()),
|
| + 'parseDocumentationComment_0': new MethodTrampoline(0, (Parser target) => target._parseDocumentationComment()),
|
| + 'parseDoStatement_0': new MethodTrampoline(0, (Parser target) => target._parseDoStatement()),
|
| + 'parseEmptyStatement_0': new MethodTrampoline(0, (Parser target) => target._parseEmptyStatement()),
|
| + 'parseEnumConstantDeclaration_0': new MethodTrampoline(0, (Parser target) => target._parseEnumConstantDeclaration()),
|
| + 'parseEnumDeclaration_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseEnumDeclaration(arg0)),
|
| + 'parseEqualityExpression_0': new MethodTrampoline(0, (Parser target) => target._parseEqualityExpression()),
|
| + 'parseExportDirective_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseExportDirective(arg0)),
|
| + 'parseExpressionList_0': new MethodTrampoline(0, (Parser target) => target._parseExpressionList()),
|
| + 'parseFinalConstVarOrType_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseFinalConstVarOrType(arg0)),
|
| + 'parseFormalParameter_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseFormalParameter(arg0)),
|
| + 'parseForStatement_0': new MethodTrampoline(0, (Parser target) => target._parseForStatement()),
|
| + 'parseFunctionBody_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target._parseFunctionBody(arg0, arg1, arg2)),
|
| + 'parseFunctionDeclaration_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target._parseFunctionDeclaration(arg0, arg1, arg2)),
|
| + 'parseFunctionDeclarationStatement_0': new MethodTrampoline(0, (Parser target) => target._parseFunctionDeclarationStatement()),
|
| + 'parseFunctionDeclarationStatementAfterReturnType_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._parseFunctionDeclarationStatementAfterReturnType(arg0, arg1)),
|
| + 'parseFunctionTypeAlias_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._parseFunctionTypeAlias(arg0, arg1)),
|
| + 'parseGetter_4': new MethodTrampoline(4, (Parser target, arg0, arg1, arg2, arg3) => target._parseGetter(arg0, arg1, arg2, arg3)),
|
| + 'parseIdentifierList_0': new MethodTrampoline(0, (Parser target) => target._parseIdentifierList()),
|
| + 'parseIfStatement_0': new MethodTrampoline(0, (Parser target) => target._parseIfStatement()),
|
| + 'parseImportDirective_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseImportDirective(arg0)),
|
| + 'parseInitializedIdentifierList_4': new MethodTrampoline(4, (Parser target, arg0, arg1, arg2, arg3) => target._parseInitializedIdentifierList(arg0, arg1, arg2, arg3)),
|
| + 'parseInstanceCreationExpression_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseInstanceCreationExpression(arg0)),
|
| + 'parseLibraryDirective_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseLibraryDirective(arg0)),
|
| + 'parseLibraryName_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._parseLibraryName(arg0, arg1)),
|
| + 'parseListLiteral_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._parseListLiteral(arg0, arg1)),
|
| + 'parseListOrMapLiteral_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseListOrMapLiteral(arg0)),
|
| + 'parseLogicalAndExpression_0': new MethodTrampoline(0, (Parser target) => target._parseLogicalAndExpression()),
|
| + 'parseMapLiteral_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._parseMapLiteral(arg0, arg1)),
|
| + 'parseMethodDeclarationAfterParameters_6': new MethodTrampoline(6, (Parser target, arg0, arg1, arg2, arg3, arg4, arg5) => target._parseMethodDeclarationAfterParameters(arg0, arg1, arg2, arg3, arg4, arg5)),
|
| + 'parseMethodDeclarationAfterReturnType_4': new MethodTrampoline(4, (Parser target, arg0, arg1, arg2, arg3) => target._parseMethodDeclarationAfterReturnType(arg0, arg1, arg2, arg3)),
|
| + 'parseModifiers_0': new MethodTrampoline(0, (Parser target) => target._parseModifiers()),
|
| + 'parseMultiplicativeExpression_0': new MethodTrampoline(0, (Parser target) => target._parseMultiplicativeExpression()),
|
| + 'parseNativeClause_0': new MethodTrampoline(0, (Parser target) => target._parseNativeClause()),
|
| + 'parseNewExpression_0': new MethodTrampoline(0, (Parser target) => target._parseNewExpression()),
|
| + 'parseNonLabeledStatement_0': new MethodTrampoline(0, (Parser target) => target._parseNonLabeledStatement()),
|
| + 'parseOperator_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target._parseOperator(arg0, arg1, arg2)),
|
| + 'parseOptionalReturnType_0': new MethodTrampoline(0, (Parser target) => target._parseOptionalReturnType()),
|
| + 'parsePartDirective_1': new MethodTrampoline(1, (Parser target, arg0) => target._parsePartDirective(arg0)),
|
| + 'parsePostfixExpression_0': new MethodTrampoline(0, (Parser target) => target._parsePostfixExpression()),
|
| + 'parsePrimaryExpression_0': new MethodTrampoline(0, (Parser target) => target._parsePrimaryExpression()),
|
| + 'parseRedirectingConstructorInvocation_0': new MethodTrampoline(0, (Parser target) => target._parseRedirectingConstructorInvocation()),
|
| + 'parseRelationalExpression_0': new MethodTrampoline(0, (Parser target) => target._parseRelationalExpression()),
|
| + 'parseRethrowExpression_0': new MethodTrampoline(0, (Parser target) => target._parseRethrowExpression()),
|
| + 'parseReturnStatement_0': new MethodTrampoline(0, (Parser target) => target._parseReturnStatement()),
|
| + 'parseSetter_4': new MethodTrampoline(4, (Parser target, arg0, arg1, arg2, arg3) => target._parseSetter(arg0, arg1, arg2, arg3)),
|
| + 'parseShiftExpression_0': new MethodTrampoline(0, (Parser target) => target._parseShiftExpression()),
|
| + 'parseStatementList_0': new MethodTrampoline(0, (Parser target) => target._parseStatementList()),
|
| + 'parseStringInterpolation_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseStringInterpolation(arg0)),
|
| + 'parseSuperConstructorInvocation_0': new MethodTrampoline(0, (Parser target) => target._parseSuperConstructorInvocation()),
|
| + 'parseSwitchStatement_0': new MethodTrampoline(0, (Parser target) => target._parseSwitchStatement()),
|
| + 'parseSymbolLiteral_0': new MethodTrampoline(0, (Parser target) => target._parseSymbolLiteral()),
|
| + 'parseThrowExpression_0': new MethodTrampoline(0, (Parser target) => target._parseThrowExpression()),
|
| + 'parseThrowExpressionWithoutCascade_0': new MethodTrampoline(0, (Parser target) => target._parseThrowExpressionWithoutCascade()),
|
| + 'parseTryStatement_0': new MethodTrampoline(0, (Parser target) => target._parseTryStatement()),
|
| + 'parseTypeAlias_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseTypeAlias(arg0)),
|
| + 'parseUnaryExpression_0': new MethodTrampoline(0, (Parser target) => target._parseUnaryExpression()),
|
| + 'parseVariableDeclaration_0': new MethodTrampoline(0, (Parser target) => target._parseVariableDeclaration()),
|
| + 'parseVariableDeclarationListAfterMetadata_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseVariableDeclarationListAfterMetadata(arg0)),
|
| + 'parseVariableDeclarationListAfterType_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target._parseVariableDeclarationListAfterType(arg0, arg1, arg2)),
|
| + 'parseVariableDeclarationStatementAfterMetadata_1': new MethodTrampoline(1, (Parser target, arg0) => target._parseVariableDeclarationStatementAfterMetadata(arg0)),
|
| + 'parseVariableDeclarationStatementAfterType_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target._parseVariableDeclarationStatementAfterType(arg0, arg1, arg2)),
|
| + 'parseWhileStatement_0': new MethodTrampoline(0, (Parser target) => target._parseWhileStatement()),
|
| + 'parseYieldStatement_0': new MethodTrampoline(0, (Parser target) => target._parseYieldStatement()),
|
| + 'peek_0': new MethodTrampoline(0, (Parser target) => target._peek()),
|
| + 'peekAt_1': new MethodTrampoline(1, (Parser target, arg0) => target._peekAt(arg0)),
|
| + 'reportError_1': new MethodTrampoline(1, (Parser target, arg0) => target._reportError(arg0)),
|
| + 'reportErrorForCurrentToken_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._reportErrorForCurrentToken(arg0, arg1)),
|
| + 'reportErrorForNode_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target._reportErrorForNode(arg0, arg1, arg2)),
|
| + 'reportErrorForToken_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target._reportErrorForToken(arg0, arg1, arg2)),
|
| + 'skipBlock_0': new MethodTrampoline(0, (Parser target) => target._skipBlock()),
|
| + 'skipFinalConstVarOrType_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipFinalConstVarOrType(arg0)),
|
| + 'skipFormalParameterList_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipFormalParameterList(arg0)),
|
| + 'skipPastMatchingToken_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipPastMatchingToken(arg0)),
|
| + 'skipPrefixedIdentifier_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipPrefixedIdentifier(arg0)),
|
| + 'skipReturnType_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipReturnType(arg0)),
|
| + 'skipSimpleIdentifier_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipSimpleIdentifier(arg0)),
|
| + 'skipStringInterpolation_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipStringInterpolation(arg0)),
|
| + 'skipStringLiteral_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipStringLiteral(arg0)),
|
| + 'skipTypeArgumentList_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipTypeArgumentList(arg0)),
|
| + 'skipTypeName_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipTypeName(arg0)),
|
| + 'skipTypeParameterList_1': new MethodTrampoline(1, (Parser target, arg0) => target._skipTypeParameterList(arg0)),
|
| + 'tokenMatches_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._tokenMatches(arg0, arg1)),
|
| + 'tokenMatchesIdentifier_1': new MethodTrampoline(1, (Parser target, arg0) => target._tokenMatchesIdentifier(arg0)),
|
| + 'tokenMatchesKeyword_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._tokenMatchesKeyword(arg0, arg1)),
|
| + 'tokenMatchesString_2': new MethodTrampoline(2, (Parser target, arg0, arg1) => target._tokenMatchesString(arg0, arg1)),
|
| + 'translateCharacter_3': new MethodTrampoline(3, (Parser target, arg0, arg1, arg2) => target._translateCharacter(arg0, arg1, arg2)),
|
| + 'unlockErrorListener_0': new MethodTrampoline(0, (Parser target) => target._unlockErrorListener()),
|
| + 'validateFormalParameterList_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateFormalParameterList(arg0)),
|
| + 'validateModifiersForClass_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateModifiersForClass(arg0)),
|
| + 'validateModifiersForConstructor_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateModifiersForConstructor(arg0)),
|
| + 'validateModifiersForEnum_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateModifiersForEnum(arg0)),
|
| + 'validateModifiersForField_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateModifiersForField(arg0)),
|
| + 'validateModifiersForFunctionDeclarationStatement_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateModifiersForFunctionDeclarationStatement(arg0)),
|
| + 'validateModifiersForGetterOrSetterOrMethod_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateModifiersForGetterOrSetterOrMethod(arg0)),
|
| + 'validateModifiersForOperator_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateModifiersForOperator(arg0)),
|
| + 'validateModifiersForTopLevelDeclaration_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateModifiersForTopLevelDeclaration(arg0)),
|
| + 'validateModifiersForTopLevelFunction_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateModifiersForTopLevelFunction(arg0)),
|
| + 'validateModifiersForTopLevelVariable_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateModifiersForTopLevelVariable(arg0)),
|
| + 'validateModifiersForTypedef_1': new MethodTrampoline(1, (Parser target, arg0) => target._validateModifiersForTypedef(arg0)),};
|
| +
|
| +
|
| +Object invokeParserMethodImpl(Parser parser, String methodName, List<Object> objects, Token tokenStream) {
|
| + parser.currentToken = tokenStream;
|
| + MethodTrampoline method = methodTable_Parser['${methodName}_${objects.length}'];
|
| + return method.invoke(parser, objects);
|
| +}
|
| +
|
| +
|
| +/**
|
| + * Wrapper around [Function] which should be called with "target" and "arguments".
|
| + */
|
| +class MethodTrampoline {
|
| + int parameterCount;
|
| + Function trampoline;
|
| + MethodTrampoline(this.parameterCount, this.trampoline);
|
| + Object invoke(target, List arguments) {
|
| + if (arguments.length != parameterCount) {
|
| + throw new IllegalArgumentException("${arguments.length} != $parameterCount");
|
| + }
|
| + switch (parameterCount) {
|
| + case 0:
|
| + return trampoline(target);
|
| + case 1:
|
| + return trampoline(target, arguments[0]);
|
| + case 2:
|
| + return trampoline(target, arguments[0], arguments[1]);
|
| + case 3:
|
| + return trampoline(target, arguments[0], arguments[1], arguments[2]);
|
| + case 4:
|
| + return trampoline(target, arguments[0], arguments[1], arguments[2], arguments[3]);
|
| + default:
|
| + throw new IllegalArgumentException("Not implemented for > 4 arguments");
|
| + }
|
| + }
|
| +}
|
|
|