Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(555)

Unified Diff: dart/compiler/java/com/google/dart/compiler/parser/DartParser.java

Issue 20722006: Removed compiler/ directory from repository (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge
Patch Set: Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: dart/compiler/java/com/google/dart/compiler/parser/DartParser.java
diff --git a/dart/compiler/java/com/google/dart/compiler/parser/DartParser.java b/dart/compiler/java/com/google/dart/compiler/parser/DartParser.java
deleted file mode 100644
index cd5728ae4c43aa689e2e1bd76813179a201ddf93..0000000000000000000000000000000000000000
--- a/dart/compiler/java/com/google/dart/compiler/parser/DartParser.java
+++ /dev/null
@@ -1,5688 +0,0 @@
-// Copyright (c) 2012, 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.
-
-package com.google.dart.compiler.parser;
-
-import com.google.common.annotations.VisibleForTesting;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.io.CharStreams;
-import com.google.dart.compiler.DartCompilationError;
-import com.google.dart.compiler.DartCompilerListener;
-import com.google.dart.compiler.DartSource;
-import com.google.dart.compiler.ErrorCode;
-import com.google.dart.compiler.ErrorSeverity;
-import com.google.dart.compiler.InternalCompilerException;
-import com.google.dart.compiler.LibrarySource;
-import com.google.dart.compiler.PackageLibraryManager;
-import com.google.dart.compiler.Source;
-import com.google.dart.compiler.ast.DartAnnotation;
-import com.google.dart.compiler.ast.DartArrayAccess;
-import com.google.dart.compiler.ast.DartArrayLiteral;
-import com.google.dart.compiler.ast.DartAssertStatement;
-import com.google.dart.compiler.ast.DartBinaryExpression;
-import com.google.dart.compiler.ast.DartBlock;
-import com.google.dart.compiler.ast.DartBooleanLiteral;
-import com.google.dart.compiler.ast.DartBreakStatement;
-import com.google.dart.compiler.ast.DartCascadeExpression;
-import com.google.dart.compiler.ast.DartCase;
-import com.google.dart.compiler.ast.DartCatchBlock;
-import com.google.dart.compiler.ast.DartClass;
-import com.google.dart.compiler.ast.DartClassTypeAlias;
-import com.google.dart.compiler.ast.DartConditional;
-import com.google.dart.compiler.ast.DartContinueStatement;
-import com.google.dart.compiler.ast.DartDeclaration;
-import com.google.dart.compiler.ast.DartDefault;
-import com.google.dart.compiler.ast.DartDirective;
-import com.google.dart.compiler.ast.DartDoWhileStatement;
-import com.google.dart.compiler.ast.DartDoubleLiteral;
-import com.google.dart.compiler.ast.DartEmptyStatement;
-import com.google.dart.compiler.ast.DartExportDirective;
-import com.google.dart.compiler.ast.DartExprStmt;
-import com.google.dart.compiler.ast.DartExpression;
-import com.google.dart.compiler.ast.DartField;
-import com.google.dart.compiler.ast.DartFieldDefinition;
-import com.google.dart.compiler.ast.DartForInStatement;
-import com.google.dart.compiler.ast.DartForStatement;
-import com.google.dart.compiler.ast.DartFunction;
-import com.google.dart.compiler.ast.DartFunctionExpression;
-import com.google.dart.compiler.ast.DartFunctionObjectInvocation;
-import com.google.dart.compiler.ast.DartFunctionTypeAlias;
-import com.google.dart.compiler.ast.DartIdentifier;
-import com.google.dart.compiler.ast.DartIfStatement;
-import com.google.dart.compiler.ast.DartImportDirective;
-import com.google.dart.compiler.ast.DartInitializer;
-import com.google.dart.compiler.ast.DartIntegerLiteral;
-import com.google.dart.compiler.ast.DartLabel;
-import com.google.dart.compiler.ast.DartLibraryDirective;
-import com.google.dart.compiler.ast.DartMapLiteral;
-import com.google.dart.compiler.ast.DartMapLiteralEntry;
-import com.google.dart.compiler.ast.DartMethodDefinition;
-import com.google.dart.compiler.ast.DartMethodInvocation;
-import com.google.dart.compiler.ast.DartNamedExpression;
-import com.google.dart.compiler.ast.DartNativeBlock;
-import com.google.dart.compiler.ast.DartNativeDirective;
-import com.google.dart.compiler.ast.DartNewExpression;
-import com.google.dart.compiler.ast.DartNode;
-import com.google.dart.compiler.ast.DartNodeWithMetadata;
-import com.google.dart.compiler.ast.DartNullLiteral;
-import com.google.dart.compiler.ast.DartParameter;
-import com.google.dart.compiler.ast.DartParameterizedTypeNode;
-import com.google.dart.compiler.ast.DartParenthesizedExpression;
-import com.google.dart.compiler.ast.DartPartOfDirective;
-import com.google.dart.compiler.ast.DartPropertyAccess;
-import com.google.dart.compiler.ast.DartRedirectConstructorInvocation;
-import com.google.dart.compiler.ast.DartReturnBlock;
-import com.google.dart.compiler.ast.DartReturnStatement;
-import com.google.dart.compiler.ast.DartSourceDirective;
-import com.google.dart.compiler.ast.DartStatement;
-import com.google.dart.compiler.ast.DartStringInterpolation;
-import com.google.dart.compiler.ast.DartStringLiteral;
-import com.google.dart.compiler.ast.DartSuperConstructorInvocation;
-import com.google.dart.compiler.ast.DartSuperExpression;
-import com.google.dart.compiler.ast.DartSwitchMember;
-import com.google.dart.compiler.ast.DartSwitchStatement;
-import com.google.dart.compiler.ast.DartSyntheticErrorExpression;
-import com.google.dart.compiler.ast.DartSyntheticErrorIdentifier;
-import com.google.dart.compiler.ast.DartSyntheticErrorStatement;
-import com.google.dart.compiler.ast.DartThisExpression;
-import com.google.dart.compiler.ast.DartThrowExpression;
-import com.google.dart.compiler.ast.DartTryStatement;
-import com.google.dart.compiler.ast.DartTypeExpression;
-import com.google.dart.compiler.ast.DartTypeNode;
-import com.google.dart.compiler.ast.DartTypeParameter;
-import com.google.dart.compiler.ast.DartUnaryExpression;
-import com.google.dart.compiler.ast.DartUnit;
-import com.google.dart.compiler.ast.DartUnqualifiedInvocation;
-import com.google.dart.compiler.ast.DartVariable;
-import com.google.dart.compiler.ast.DartVariableStatement;
-import com.google.dart.compiler.ast.DartWhileStatement;
-import com.google.dart.compiler.ast.HasObsoleteMetadata;
-import com.google.dart.compiler.ast.ImportCombinator;
-import com.google.dart.compiler.ast.ImportHideCombinator;
-import com.google.dart.compiler.ast.ImportShowCombinator;
-import com.google.dart.compiler.ast.LibraryNode;
-import com.google.dart.compiler.ast.LibraryUnit;
-import com.google.dart.compiler.ast.Modifiers;
-import com.google.dart.compiler.metrics.CompilerMetrics;
-import com.google.dart.compiler.parser.DartScanner.Location;
-import com.google.dart.compiler.resolver.Elements;
-import com.google.dart.compiler.util.Lists;
-import com.google.dart.compiler.util.apache.StringUtils;
-
-import java.io.IOException;
-import java.io.Reader;
-import java.math.BigInteger;
-import java.text.Normalizer;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-/**
- * The Dart parser. Parses a single compilation unit and produces a {@link DartUnit}.
- * The grammar rules are taken from Dart.g revision 557.
- */
-public class DartParser extends CompletionHooksParserBase {
-
- private final Source source;
- private final String sourceCode;
- private final boolean isDietParse;
- private final Set<String> prefixes;
- private boolean allowNativeKeyword;
- private final Set<Integer> errorHistory = new HashSet<Integer>();
- private boolean isParsingInterface;
- private boolean isTopLevelAbstract;
- private int topLevelAbstractModifierPosition;
- private boolean isParsingClass;
- private int errorCount = 0;
-
- /**
- * Determines the maximum number of errors before terminating the parser. See
- * {@link #reportError(int, ErrorCode, Object...)}.
- */
- final int MAX_DEFAULT_ERRORS = Short.MAX_VALUE;
-
- // Pseudo-keywords that should also be valid identifiers.
- private static final String ABSTRACT_KEYWORD = "abstract";
- private static final String AS_KEYWORD = "as";
- private static final String CALL_KEYWORD = "call";
- public static final String DYNAMIC_KEYWORD = "dynamic";
- private static final String EXPORT_KEYWORD = "export";
- private static final String EXTERNAL_KEYWORD = "external";
- private static final String FACTORY_KEYWORD = "factory";
- private static final String GETTER_KEYWORD = "get";
- private static final String HIDE_KEYWORD = "hide";
- private static final String IMPLEMENTS_KEYWORD = "implements";
- private static final String IMPORT_KEYWORD = "import";
- private static final String INTERFACE_KEYWORD = "interface";
- private static final String LIBRARY_KEYWORD = "library";
- private static final String NATIVE_KEYWORD = "native";
- private static final String OF_KEYWORD = "of";
- private static final String ON_KEYWORD = "on";
- private static final String OPERATOR_KEYWORD = "operator";
- private static final String PART_KEYWORD = "part";
- private static final String PREFIX_KEYWORD = "prefix";
- private static final String SETTER_KEYWORD = "set";
- private static final String SHOW_KEYWORD = "show";
- private static final String STATIC_KEYWORD = "static";
- private static final String TYPEDEF_KEYWORD = "typedef";
- // does not exist in specification
- private static final String PATCH_KEYWORD = "patch";
-
-
- public static final String[] PSEUDO_KEYWORDS = {
- ABSTRACT_KEYWORD,
- AS_KEYWORD,
- DYNAMIC_KEYWORD,
- EXPORT_KEYWORD,
- EXTERNAL_KEYWORD,
- FACTORY_KEYWORD,
- GETTER_KEYWORD,
- IMPLEMENTS_KEYWORD,
- IMPORT_KEYWORD,
- LIBRARY_KEYWORD,
- OPERATOR_KEYWORD,
- PART_KEYWORD,
- SETTER_KEYWORD,
- STATIC_KEYWORD,
- TYPEDEF_KEYWORD
- };
- public static final Set<String> PSEUDO_KEYWORDS_SET = ImmutableSet.copyOf(PSEUDO_KEYWORDS);
-
- public static final String[] RESERVED_WORDS = {
- "break",
- "case",
- "catch",
- "class",
- "const",
- "continue",
- "default",
- "do",
- "else",
- "extends",
- "false",
- "final",
- "finally",
- "for",
- "if",
- "in",
- "is",
- "new",
- "null",
- "return",
- "rethrow",
- "super",
- "switch",
- "this",
- "throw",
- "true",
- "try",
- "var",
- "void",
- "while"};
- public static final Set<String> RESERVED_WORDS_SET = ImmutableSet.copyOf(RESERVED_WORDS);
-
- public DartParser(Source source,
- String sourceCode,
- boolean isDietParse,
- Set<String> prefixes,
- DartCompilerListener listener,
- CompilerMetrics compilerMetrics) {
- super(new DartParserCommentsHelper.CommentParserContext(source, sourceCode, listener, compilerMetrics));
- this.source = source;
- this.sourceCode = sourceCode;
- this.isDietParse = isDietParse;
- this.prefixes = prefixes;
- this.allowNativeKeyword = source != null && PackageLibraryManager.isDartUri(source.getUri());
- // check Unicode normalization
- {
- int indexOfDifference = StringUtils.indexOfDifference(sourceCode,
- Normalizer.normalize(sourceCode, Normalizer.Form.NFC));
- if (indexOfDifference != -1) {
- DartCompilationError error = new DartCompilationError(source, new Location(
- indexOfDifference, indexOfDifference + 1),
- ParserErrorCode.INVALID_UNICODE_NORMALIZATION);
- ctx.error(error);
- }
- }
- }
-
- public static String read(Source source) throws IOException {
- return read(source.getSourceReader());
- }
-
- public static String read(Reader reader) throws IOException {
- try {
- return CharStreams.toString(reader);
- } finally {
- reader.close();
- }
- }
-
- /**
- * A flag indicating whether function expressions are allowed. See
- * {@link #setAllowFunctionExpression(boolean)}.
- */
- private boolean allowFunctionExpression = true;
-
- /**
- * 'break' (with no labels) and 'continue' stmts are not valid
- * just anywhere, they must be inside a loop or a case stmt.
- *
- * A break with a label may be valid and is allowed through and
- * checked in the resolver.
- */
- private boolean inLoopStatement = false;
- private boolean inCaseStatement = false;
-
- /**
- * Set the {@link #allowFunctionExpression} flag indicating whether function expressions are
- * allowed, returning the old value. This is required to avoid ambiguity in a few places in the
- * grammar.
- *
- * @param allow true if function expressions are allowed, false if not
- * @return previous value of the flag, which should be restored
- */
- private boolean setAllowFunctionExpression(boolean allow) {
- boolean old = allowFunctionExpression;
- allowFunctionExpression = allow;
- return old;
- }
-
- /**
- * <pre>
- * compilationUnit
- * : libraryDeclaration? topLevelDefinition* EOF
- * ;
- *
- * libraryDeclaration
- * : libraryDirective? importDirective* sourceDirective* resourceDirective* nativeDirective*
- *
- * topLevelDefinition
- * : classDefinition
- * | interfaceDefinition
- * | functionTypeAlias
- * | methodOrConstructorDeclaration functionStatementBody
- * | type? getOrSet identifier formalParameterList functionStatementBody
- * | CONST type? staticConstDeclarationList ';'
- * | variableDeclaration ';'
- * ;
- * </pre>
- */
- @Terminals(tokens={Token.EOS, Token.CLASS, Token.LIBRARY, Token.IMPORT, Token.SOURCE,
- Token.RESOURCE, Token.NATIVE})
- public DartUnit parseUnit() {
- DartSource dartSource = (DartSource) source;
-
- errorCount = 0;
-
- try {
- beginCompilationUnit();
- ctx.unitAboutToCompile(dartSource, isDietParse);
- DartUnit unit = new DartUnit(dartSource, isDietParse);
- List<DartAnnotation> metadata = parseMetadata();
-
- // parse any directives at the beginning of the source
- metadata = parseDirectives(unit, metadata);
-
- while (!EOS()) {
- DartNodeWithMetadata node = null;
- beginTopLevelElement();
- isParsingClass = isParsingInterface = false;
- // Check for ABSTRACT_KEYWORD.
- isTopLevelAbstract = false;
- topLevelAbstractModifierPosition = 0;
- if (isBuiltInSpecial() && optionalPseudoKeyword(ABSTRACT_KEYWORD)) {
- isTopLevelAbstract = true;
- topLevelAbstractModifierPosition = position();
- }
- // skip "patch" before "class"
- if (peek(1) == Token.CLASS && optionalPseudoKeyword(PATCH_KEYWORD)) {
- }
- // Parse top level element.
- if (optional(Token.CLASS)) {
- isParsingClass = true;
- node = done(parseClass());
- } else if (peekPseudoKeyword(0, INTERFACE_KEYWORD) && peek(1).equals(Token.IDENTIFIER)) {
- consume(Token.IDENTIFIER);
- isParsingInterface = true;
- reportError(position(), ParserErrorCode.DEPRECATED_INTERFACE);
- node = done(parseClass());
- } else if (peekPseudoKeyword(0, TYPEDEF_KEYWORD)
- && (peek(1).equals(Token.IDENTIFIER) || peek(1).equals(Token.VOID))) {
- consume(Token.IDENTIFIER);
- node = done(parseTypeAlias());
- } else if (looksLikeDirective()) {
- reportErrorWithoutAdvancing(ParserErrorCode.DIRECTIVE_OUT_OF_ORDER);
- metadata = parseDirectives(unit, metadata);
- } else {
- node = done(parseFieldOrMethod(false));
- }
- // Parsing was successful, add node.
- if (node != null) {
- unit.getTopLevelNodes().add(node);
- setMetadata(node, metadata);
- metadata = parseMetadata();
- // Only "class" can be top-level abstract element.
- if (isTopLevelAbstract && !isParsingClass) {
- int abstractPositionEnd = topLevelAbstractModifierPosition + ABSTRACT_KEYWORD.length();
- Location location = new Location(topLevelAbstractModifierPosition, abstractPositionEnd);
- reportError(new DartCompilationError(source, location,
- ParserErrorCode.ABSTRACT_TOP_LEVEL_ELEMENT));
- }
- }
- }
- expect(Token.EOS);
- // add comments
- {
- List<int[]> commentLocs = ((DartParserCommentsHelper.CommentParserContext) ctx).getCommentLocs();
- DartParserCommentsHelper.addComments(unit, source, sourceCode, commentLocs);
- }
- // done
- unit.setHasParseErrors(errorCount != 0);
- return done(unit);
- } catch (StringInterpolationParseError exception) {
- throw new InternalCompilerException("Failed to parse " + source.getUri(), exception);
- }
- }
-
- /**
- * Set the metadata associated with the given node to the given annotations.
- *
- * @param node the node with which the metadata is to be associated
- * @param metadata the metadata to be associated with the node
- */
- private void setMetadata(DartNodeWithMetadata node, List<DartAnnotation> annotations) {
- if (node instanceof DartFieldDefinition) {
- DartFieldDefinition fieldDefinition = (DartFieldDefinition) node;
- List<DartField> fields = fieldDefinition.getFields();
- for (DartField field : fields) {
- setMetadata(field, annotations);
- }
- return;
- }
- if (annotations != null && !annotations.isEmpty()) {
- node.setMetadata(annotations);
- if (node instanceof HasObsoleteMetadata) {
- HasObsoleteMetadata declaration = (HasObsoleteMetadata) node;
- for (int i = 0, size = annotations.size(); i < size; i++) {
- DartAnnotation annotation = annotations.get(i);
- DartExpression nameNode = annotation.getName();
- if (nameNode instanceof DartIdentifier) {
- String name = ((DartIdentifier) nameNode).getName();
- if (name.equals("deprecated")) {
- declaration.setObsoleteMetadata(declaration.getObsoleteMetadata().makeDeprecated());
- } else if (name.equals("override")) {
- declaration.setObsoleteMetadata(declaration.getObsoleteMetadata().makeOverride());
- }
- }
- }
- }
- }
- }
-
- private boolean looksLikeDirective() {
- if (!isBuiltInSpecial()) {
- return false;
- }
- switch(peek(0)) {
- case LIBRARY:
- case IMPORT:
- case SOURCE:
- case RESOURCE:
- case NATIVE:
- return true;
- }
- return peekPseudoKeyword(0, LIBRARY_KEYWORD) || peekPseudoKeyword(0, IMPORT_KEYWORD) || peekPseudoKeyword(0, PART_KEYWORD);
- }
-
- /**
- * 'interface' and 'typedef' are valid to use as names of fields and methods, so you can't
- * just blindly recover when you see them in any context. This does a further test to make
- * sure they are followed by another identifier. This would be illegal as a field or method
- * definition, as you cannot use 'interface' or 'typedef' as a type name.
- */
- private boolean looksLikeTopLevelKeyword() {
- if (peek(0).equals(Token.CLASS)) {
- return true;
- }
- if (peekPseudoKeyword(0, INTERFACE_KEYWORD)
- && peek(1).equals(Token.IDENTIFIER)) {
- return true;
- } else if (peekPseudoKeyword(0, TYPEDEF_KEYWORD)
- && (peek(1).equals(Token.IDENTIFIER) || peek(1).equals(Token.VOID))) {
- return true;
- }
- return false;
- }
-
- /**
- * A version of the parser which only parses the directives of a library.
- *
- * TODO(jbrosenberg): consider parsing the whole file here, in order to avoid
- * duplicate work. Probably requires removing use of LibraryUnit's, etc.
- * Also, this minimal parse does have benefit in the incremental compilation
- * case.
- */
- @SuppressWarnings("deprecation")
- public LibraryUnit preProcessLibraryDirectives(LibrarySource source) {
- beginCompilationUnit();
- LibraryUnit libUnit = new LibraryUnit(source);
- parseMetadata();
- if (peekPseudoKeyword(0, LIBRARY_KEYWORD)) {
- DartLibraryDirective libraryDirective = parseLibraryDirective();
- libUnit.setName(libraryDirective.getLibraryName());
- parseMetadata();
- }
- while (peekPseudoKeyword(0, IMPORT_KEYWORD) || peekPseudoKeyword(0, EXPORT_KEYWORD)) {
- if (peekPseudoKeyword(0, IMPORT_KEYWORD)) {
- DartImportDirective importDirective = parseImportDirective();
- LibraryNode importPath = new LibraryNode(importDirective);
- importPath.setSourceInfo(importDirective.getSourceInfo());
- libUnit.addImportPath(importPath);
- }
- if (peekPseudoKeyword(0, EXPORT_KEYWORD)) {
- DartExportDirective exportDirective = parseExportDirective();
- LibraryNode importPath = new LibraryNode(exportDirective);
- importPath.setSourceInfo(exportDirective.getSourceInfo());
- libUnit.addExportPath(importPath);
- }
- parseMetadata();
- }
- while (peekPseudoKeyword(0, PART_KEYWORD)) {
- if (peekPseudoKeyword(1, OF_KEYWORD)) {
- parsePartOfDirective();
- } else {
- DartSourceDirective sourceDirective = parsePartDirective();
- LibraryNode sourcePath = new LibraryNode(sourceDirective.getSourceUri().getValue());
- sourcePath.setSourceInfo(sourceDirective.getSourceInfo());
- libUnit.addSourcePath(sourcePath);
- }
- parseMetadata();
- }
- //
- // The code below is obsolete. We do not make any effort to find duplications between the old
- // and the new syntax because support for the old syntax will be removed very soon.
- //
- if (peek(0) == Token.LIBRARY) {
- beginLibraryDirective();
- DartLibraryDirective libDirective = done(parseObsoleteLibraryDirective());
- libUnit.setName(libDirective.getLibraryName());
- parseMetadata();
- }
- while (peek(0) == Token.IMPORT) {
- beginImportDirective();
- DartImportDirective importDirective = done(parseObsoleteImportDirective());
- LibraryNode importPath;
- if (importDirective.getOldPrefix() != null) {
- importPath =
- new LibraryNode(importDirective);
- } else {
- importPath = new LibraryNode(importDirective.getLibraryUri().getValue());
- }
- importPath.setSourceInfo(importDirective.getSourceInfo());
- libUnit.addImportPath(importPath);
- parseMetadata();
- }
- while (peek(0) == Token.SOURCE) {
- beginSourceDirective();
- DartSourceDirective sourceDirective = done(parseSourceDirective());
- LibraryNode sourcePath = new LibraryNode(sourceDirective.getSourceUri().getValue());
- sourcePath.setSourceInfo(sourceDirective.getSourceInfo());
- libUnit.addSourcePath(sourcePath);
- parseMetadata();
- }
- while (peek(0) == Token.RESOURCE) {
- parseResourceDirective();
- parseMetadata();
- }
- while (peek(0) == Token.NATIVE) {
- beginNativeDirective();
- DartNativeDirective nativeDirective = done(parseNativeDirective());
- LibraryNode nativePath = new LibraryNode(nativeDirective.getNativeUri().getValue());
- nativePath.setSourceInfo(nativeDirective.getSourceInfo());
- libUnit.addNativePath(nativePath);
- parseMetadata();
- }
-
- // add ourselves to the list of sources, so inline dart code will be parsed
- libUnit.addSourcePath(libUnit.getSelfSourcePath());
- return done(libUnit);
- }
-
- private List<DartAnnotation> parseDirectives(DartUnit unit, List<DartAnnotation> metadata) {
- boolean hasLibraryDirective = false;
- if (peekPseudoKeyword(0, LIBRARY_KEYWORD)) {
- DartLibraryDirective libraryDirective = parseLibraryDirective();
- for (DartDirective directive : unit.getDirectives()) {
- if (directive instanceof DartLibraryDirective) {
- reportError(position(), ParserErrorCode.ONLY_ONE_LIBRARY_DIRECTIVE);
- break;
- }
- }
- unit.getDirectives().add(libraryDirective);
- hasLibraryDirective = true;
- setMetadata(libraryDirective, metadata);
- metadata = parseMetadata();
- }
- while (peekPseudoKeyword(0, IMPORT_KEYWORD) || peekPseudoKeyword(0, EXPORT_KEYWORD)) {
- if (peekPseudoKeyword(0, IMPORT_KEYWORD)) {
- DartImportDirective importDirective = parseImportDirective();
- unit.getDirectives().add(importDirective);
- setMetadata(importDirective, metadata);
- metadata = parseMetadata();
- } else {
- DartExportDirective exportDirective = parseExportDirective();
- unit.getDirectives().add(exportDirective);
- if (!hasLibraryDirective) {
- reportError(exportDirective, ParserErrorCode.EXPORT_WITHOUT_LIBRARY_DIRECTIVE);
- }
- setMetadata(exportDirective, metadata);
- metadata = parseMetadata();
- }
- }
- while (peekPseudoKeyword(0, PART_KEYWORD)) {
- if (peekPseudoKeyword(1, OF_KEYWORD)) {
- DartPartOfDirective partOfDirective = parsePartOfDirective();
- unit.getDirectives().add(partOfDirective);
- setMetadata(partOfDirective, metadata);
- metadata = parseMetadata();
- } else {
- DartSourceDirective partDirective = parsePartDirective();
- unit.getDirectives().add(partDirective);
- setMetadata(partDirective, metadata);
- metadata = parseMetadata();
- }
- }
- //
- // The code below is obsolete. We do not make any effort to find duplications between the old
- // and the new syntax because support for the old syntax will be removed very soon.
- //
- if (peek(0) == Token.LIBRARY) {
- beginLibraryDirective();
- DartLibraryDirective libraryDirective = parseObsoleteLibraryDirective();
- for (DartDirective directive : unit.getDirectives()) {
- if (directive instanceof DartLibraryDirective) {
- reportError(position(), ParserErrorCode.ONLY_ONE_LIBRARY_DIRECTIVE);
- break;
- }
- }
- unit.getDirectives().add(libraryDirective);
- done(libraryDirective);
- setMetadata(libraryDirective, metadata);
- metadata = parseMetadata();
- }
- while (peek(0) == Token.IMPORT) {
- beginImportDirective();
- DartImportDirective importDirective = parseObsoleteImportDirective();
- unit.getDirectives().add(done(importDirective));
- setMetadata(importDirective, metadata);
- metadata = parseMetadata();
- }
- while (peek(0) == Token.SOURCE) {
- beginSourceDirective();
- DartSourceDirective sourceDirective = parseSourceDirective();
- unit.getDirectives().add(done(sourceDirective));
- setMetadata(sourceDirective, metadata);
- metadata = parseMetadata();
- }
- while (peek(0) == Token.RESOURCE) {
- parseResourceDirective();
- }
- while (peek(0) == Token.NATIVE) {
- beginNativeDirective();
- DartNativeDirective nativeDirective = parseNativeDirective();
- unit.getDirectives().add(done(nativeDirective));
- setMetadata(nativeDirective, metadata);
- metadata = parseMetadata();
- }
- return metadata;
- }
-
- private DartLibraryDirective parseLibraryDirective() {
- beginLibraryDirective();
- next(); // "library"
- DartExpression libraryName = parseLibraryName();
- expect(Token.SEMICOLON);
- return done(new DartLibraryDirective(libraryName));
- }
-
- private DartExpression parseLibraryName() {
- beginQualifiedIdentifier();
- DartExpression libraryName = parseIdentifier();
- while (optional(Token.PERIOD)) {
- beginQualifiedIdentifier();
- DartIdentifier identifier = parseIdentifier();
- libraryName = done(new DartPropertyAccess(libraryName, identifier));
- }
- return done(libraryName);
- }
-
- private DartLibraryDirective parseObsoleteLibraryDirective() {
- expect(Token.LIBRARY);
- reportDeprecatedError(position(), ParserErrorCode.DEPRECATED_LIBRARY_DIRECTIVE);
- expect(Token.LPAREN);
- beginLiteral();
- expect(Token.STRING);
- DartStringLiteral libname = done(DartStringLiteral.get(ctx.getTokenString()));
- expectCloseParen();
- expect(Token.SEMICOLON);
- return new DartLibraryDirective(libname);
- }
-
- protected DartExportDirective parseExportDirective() {
- beginExportDirective();
- next(); // "export"
- DartStringLiteral libUri = parseUri();
-
- List<ImportCombinator> combinators = new ArrayList<ImportCombinator>();
- while (peekPseudoKeyword(0, HIDE_KEYWORD) || peekPseudoKeyword(0, SHOW_KEYWORD)) {
- beginImportCombinator();
- if (optionalPseudoKeyword(HIDE_KEYWORD)) {
- List<DartIdentifier> hiddenNames = parseIdentifierList();
- combinators.add(done(new ImportHideCombinator(hiddenNames)));
- } else if (optionalPseudoKeyword(SHOW_KEYWORD)) {
- List<DartIdentifier> shownNames = parseIdentifierList();
- combinators.add(done(new ImportShowCombinator(shownNames)));
- }
- }
-
- if (!optional(Token.SEMICOLON)) {
- // If there is no semicolon, then we probably don't want to consume the next token. It might
- // make sense to advance to the next valid token for a directive or top-level declaration, but
- // our recovery mechanism isn't quite sophisticated enough for that.
- reportUnexpectedToken(position(), Token.SEMICOLON, peek(0));
- }
- return done(new DartExportDirective(libUri, combinators));
- }
-
- protected DartImportDirective parseImportDirective() {
- beginImportDirective();
- next(); // "import"
- DartStringLiteral libUri = parseUri();
- // allow "native" if we have "dart-ext:" import
- if (StringUtils.startsWith(libUri.getValue(), "dart-ext:")) {
- allowNativeKeyword = true;
- }
-
- DartIdentifier prefix = null;
- if (peek(0) == Token.IDENTIFIER && "as".equals(ctx.peekTokenString(0))) {
- ctx.advance();
- prefix = parseIdentifier();
- if (prefix instanceof DartSyntheticErrorIdentifier) {
- if (peekPseudoKeyword(1, HIDE_KEYWORD) || peekPseudoKeyword(1, SHOW_KEYWORD)
- || peek(1) == Token.BIT_AND || peek(1) == Token.COLON) {
- next();
- }
- }
- }
-
- List<ImportCombinator> combinators = new ArrayList<ImportCombinator>();
- while (peekPseudoKeyword(0, HIDE_KEYWORD) || peekPseudoKeyword(0, SHOW_KEYWORD)) {
- if (optionalPseudoKeyword(HIDE_KEYWORD)) {
- List<DartIdentifier> hiddenNames = parseIdentifierList();
- combinators.add(new ImportHideCombinator(hiddenNames));
- } else if (optionalPseudoKeyword(SHOW_KEYWORD)) {
- List<DartIdentifier> shownNames = parseIdentifierList();
- combinators.add(new ImportShowCombinator(shownNames));
- }
- }
-
- if (!optional(Token.SEMICOLON)) {
- // If there is no semicolon, then we probably don't want to consume the next token. It might
- // make sense to advance to the next valid token for a directive or top-level declaration, but
- // our recovery mechanism isn't quite sophisticated enough for that.
- reportUnexpectedToken(position(), Token.SEMICOLON, peek(0));
- }
- return done(new DartImportDirective(libUri, prefix, combinators));
- }
-
- /**
- * Parse a comma-separated list of identifiers.
- *
- * @return the identifiers that were parsed
- */
- private List<DartIdentifier> parseIdentifierList() {
- ArrayList<DartIdentifier> identifiers = new ArrayList<DartIdentifier>();
- identifiers.add(parseIdentifier());
- while (optional(Token.COMMA)) {
- identifiers.add(parseIdentifier());
- }
- return identifiers;
- }
-
- protected DartImportDirective parseObsoleteImportDirective() {
- expect(Token.IMPORT);
- reportDeprecatedError(position(), ParserErrorCode.DEPRECATED_IMPORT_DIRECTIVE);
- expect(Token.LPAREN);
-
- DartStringLiteral libUri = parseUri();
-
- // allow "native" if we have "dart-ext:" import
- if (StringUtils.startsWith(libUri.getValue(), "dart-ext:")) {
- allowNativeKeyword = true;
- }
-
- DartBooleanLiteral export = null;
- List<ImportCombinator> combinators = new ArrayList<ImportCombinator>();
- DartStringLiteral prefix = null;
- if (optional(Token.COMMA)) {
- if (optionalPseudoKeyword(PREFIX_KEYWORD)) {
- expect(Token.COLON);
- beginLiteral();
- expect(Token.STRING);
- String id = ctx.getTokenString();
- // The specification requires the value of this string be a valid identifier
- if(id == null || !id.matches("[_a-zA-Z]([_A-Za-z0-9]*)")) {
- reportError(position(), ParserErrorCode.EXPECTED_PREFIX_IDENTIFIER);
- }
- prefix = done(DartStringLiteral.get(ctx.getTokenString()));
- } else {
- reportError(position(), ParserErrorCode.EXPECTED_PREFIX_KEYWORD);
- }
- }
- expectCloseParen();
- expect(Token.SEMICOLON);
- return new DartImportDirective(libUri, export, combinators, prefix);
- }
-
- private DartSourceDirective parsePartDirective() {
- beginPartDirective();
- next(); // "part"
- beginLiteral();
- expect(Token.STRING);
- DartStringLiteral partUri = done(DartStringLiteral.get(ctx.getTokenString()));
- expect(Token.SEMICOLON);
- return done(new DartSourceDirective(partUri));
- }
-
- private DartSourceDirective parseSourceDirective() {
- expect(Token.SOURCE);
- reportDeprecatedError(position(), ParserErrorCode.DEPRECATED_SOURCE_DIRECTIVE);
- expect(Token.LPAREN);
- DartStringLiteral sourceUri = parseUri();
- expectCloseParen();
- expect(Token.SEMICOLON);
- return new DartSourceDirective(sourceUri);
- }
-
- private DartPartOfDirective parsePartOfDirective() {
- beginPartOfDirective();
- next(); // "part"
- next(); // "of"
- int ofOffset= position();
- DartExpression libraryName = parseLibraryName();
- expect(Token.SEMICOLON);
- return done(new DartPartOfDirective(ofOffset, libraryName));
- }
-
- private void parseResourceDirective() {
- expect(Token.RESOURCE);
- reportError(position(), ParserErrorCode.DEPRECATED_RESOURCE_DIRECTIVE);
- expect(Token.LPAREN);
- @SuppressWarnings("unused")
- DartStringLiteral sourceUri = parseUri();
- expectCloseParen();
- expect(Token.SEMICOLON);
- }
-
- private DartNativeDirective parseNativeDirective() {
- expect(Token.NATIVE);
- expect(Token.LPAREN);
- DartStringLiteral nativeUri = parseUri();
- expect(Token.RPAREN);
- expect(Token.SEMICOLON);
- return new DartNativeDirective(nativeUri);
- }
-
- private List<DartAnnotation> parseMetadata() {
- List<DartAnnotation> metadata = new ArrayList<DartAnnotation>();
- while (match(Token.AT)) {
- beginMetadata();
- next();
- beginQualifiedIdentifier();
- DartExpression name = parseQualified(true);
- if (optional(Token.PERIOD)) {
- name = new DartPropertyAccess(name, parseIdentifier());
- }
- done(name);
- List<DartExpression> arguments = null;
- if (match(Token.LPAREN)) {
- arguments = parseArguments();
- }
- metadata.add(done(new DartAnnotation(name, arguments)));
- }
- return metadata;
- }
-
- /**
- * <pre>
- * typeParameter
- * : identifier (EXTENDS type)?
- * ;
- *
- * typeParameters
- * : '<' typeParameter (',' typeParameter)* '>'
- * ;
- * </pre>
- */
- @Terminals(tokens={Token.GT, Token.COMMA})
- private List<DartTypeParameter> parseTypeParameters() {
- List<DartTypeParameter> types = new ArrayList<DartTypeParameter>();
- expect(Token.LT);
- do {
- DartTypeParameter typeParameter = parseTypeParameter();
- types.add(typeParameter);
-
- } while (optional(Token.COMMA));
- expect(Token.GT);
- return types;
- }
-
- /**
- * Parses single {@link DartTypeParameter} for {@link #parseTypeParameters()}.
- */
- private DartTypeParameter parseTypeParameter() {
- beginTypeParameter();
- List<DartAnnotation> metadata = parseMetadata();
- DartIdentifier name = parseIdentifier();
- if (PSEUDO_KEYWORDS_SET.contains(name.getName())) {
- reportError(name, ParserErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_VARIABLE_NAME);
- }
- // Try to parse bound.
- DartTypeNode bound = null;
- if (peek(0) != Token.EOS && peek(0) != Token.COMMA && peek(0) != Token.GT) {
- if (optional(Token.EXTENDS)) {
- // OK, this is EXTENDS, parse type.
- bound = parseTypeAnnotation();
- } else if (looksLikeTopLevelKeyword()) {
- return done(new DartTypeParameter(name, bound));
- } else if (peek(0) == Token.IDENTIFIER && (peek(1) == Token.COMMA || peek(1) == Token.GT)) {
- // <X exte{cursor}>
- // User tries to type "extends", but it is not finished yet.
- // Report problem and try to continue.
- next();
- reportError(position(), ParserErrorCode.EXPECTED_EXTENDS);
- } else if (peek(0) == Token.IDENTIFIER
- && peek(1) == Token.IDENTIFIER
- && (peek(2) == Token.COMMA || peek(2) == Token.GT)) {
- // <X somethingLikeExtends Type>
- // User mistyped word "extends" or it is not finished yet.
- // Report problem and try to continue.
- next();
- reportError(position(), ParserErrorCode.EXPECTED_EXTENDS);
- bound = parseTypeAnnotation();
- } else {
- // Something else, restart parsing from next top level element.
- next();
- reportError(position(), ParserErrorCode.EXPECTED_EXTENDS);
- }
- }
- // Ready to create DartTypeParameter.
- DartTypeParameter parameter = new DartTypeParameter(name, bound);
- parameter.setMetadata(metadata);
- return done(parameter);
- }
-
- private List<DartTypeParameter> parseTypeParametersOpt() {
- return (peek(0) == Token.LT)
- ? parseTypeParameters()
- : Collections.<DartTypeParameter>emptyList();
- }
-
- /**
- * <pre>
- * classDefinition
- * : CLASS identifier typeParameters? superclass? interfaces?
- * '{' classMemberDefinition* '}'
- * ;
- *
- * superclass
- * : EXTENDS type
- * ;
- *
- * interfaces
- * : IMPLEMENTS typeList
- * ;
- *
- * superinterfaces
- * : EXTENDS typeList
- * ;
- *
- * classMemberDefinition
- * : declaration ';'
- * | methodDeclaration blockOrNative
- *
- * interfaceDefinition
- * : INTERFACE identifier typeParameters? superinterfaces?
- * (DEFAULT type)? '{' (interfaceMemberDefinition)* '}'
- * ;
- * </pre>
- */
- private DartDeclaration<?> parseClass() {
- beginClassBody();
-
- int tokenOffset = ctx.getTokenLocation().getBegin();
- int tokenLength = ctx.getTokenLocation().getEnd() - tokenOffset;
-
- // Parse modifiers.
- Modifiers modifiers = Modifiers.NONE;
- if (isTopLevelAbstract) {
- modifiers = modifiers.makeAbstract();
- }
-
- DartIdentifier name = parseIdentifier();
- if (name.getName().equals("")) {
- // something went horribly wrong.
- if (peek(0).equals(Token.LBRACE)) {
- parseBlock();
- }
- return done(null);
- }
- if (PSEUDO_KEYWORDS_SET.contains(name.getName())) {
- reportError(name, ParserErrorCode.BUILT_IN_IDENTIFIER_AS_TYPE_NAME);
- }
- List<DartTypeParameter> typeParameters = parseTypeParametersOpt();
-
- // Parse the extends and implements clauses.
- DartTypeNode superType = null;
- int withOffset = -1;
- int implementsOffset = -1;
- List<DartTypeNode> mixins = null;
- List<DartTypeNode> interfaces = null;
- if (isParsingInterface) {
- if (optional(Token.EXTENDS)) {
- interfaces = parseTypeAnnotationList();
- }
- } else {
- boolean foundClause = true;
- while (foundClause) {
- if (optional(Token.EXTENDS)) {
- if (mixins != null) {
- reportErrorAtPosition(withOffset, withOffset + "with".length(),
- ParserErrorCode.WITH_BEFORE_EXTENDS);
- }
- if (interfaces != null) {
- reportErrorAtPosition(implementsOffset, implementsOffset + "implements".length(),
- ParserErrorCode.IMPLEMENTS_BEFORE_EXTENDS);
- }
- if (superType == null) {
- superType = parseTypeAnnotation();
- } else {
- reportError(position(), ParserErrorCode.MULTIPLE_EXTENDS_CLAUSES);
- parseTypeAnnotation();
- }
- } else if (optional(Token.WITH)) {
- if (mixins == null) {
- withOffset = position();
- mixins = parseTypeAnnotationList();
- if (interfaces != null) {
- reportErrorAtPosition(implementsOffset, implementsOffset + "implements".length(),
- ParserErrorCode.IMPLEMENTS_BEFORE_WITH);
- }
- } else {
- reportError(position(), ParserErrorCode.MULTIPLE_WITH_CLAUSES);
- parseTypeAnnotationList();
- }
- } else if (optionalPseudoKeyword(IMPLEMENTS_KEYWORD)) {
- if (interfaces == null) {
- implementsOffset = position();
- interfaces = parseTypeAnnotationList();
- } else {
- reportError(position(), ParserErrorCode.MULTIPLE_IMPLEMENTS_CLAUSES);
- parseTypeAnnotationList();
- }
- } else {
- foundClause = false;
- }
- }
- if (mixins != null && superType == null) {
- reportErrorAtPosition(withOffset, withOffset + "with".length(),
- ParserErrorCode.WITH_WITHOUT_EXTENDS);
- }
- }
-
- // Deal with factory clause for interfaces.
- DartParameterizedTypeNode defaultClass = null;
- int defaultTokenOffset = -1;
- if (isParsingInterface &&
- (optionalDeprecatedFactory() || optional(Token.DEFAULT))) {
- defaultTokenOffset = position();
- beginTypeAnnotation();
- DartExpression qualified = parseQualified(false);
- List<DartTypeParameter> defaultTypeParameters = parseTypeParametersOpt();
- defaultClass = doneWithoutConsuming(new DartParameterizedTypeNode(qualified,
- defaultTypeParameters));
- }
-
- // Deal with native clause for classes.
- DartStringLiteral nativeName = null;
- if (optionalPseudoKeyword(NATIVE_KEYWORD)) {
- if (isParsingInterface) {
- reportError(position(), ParserErrorCode.NATIVE_ONLY_CLASS);
- }
- if (!allowNativeKeyword) {
- reportError(position(), ParserErrorCode.NATIVE_ONLY_CORE_LIB);
- }
- beginLiteral();
- if (expect(Token.STRING)) {
- nativeName = done(DartStringLiteral.get(ctx.getTokenString()));
- }
- modifiers = modifiers.makeNative();
- }
-
- // Parse the members.
- int openBraceOffset = -1;
- int closeBraceOffset = -1;
- List<DartNode> members = new ArrayList<DartNode>();
- if (optional(Token.LBRACE)) {
- openBraceOffset = ctx.getTokenLocation().getBegin();
- parseClassOrInterfaceBody(members);
- expectCloseBrace(true);
- closeBraceOffset = ctx.getTokenLocation().getBegin();
- } else {
- reportErrorWithoutAdvancing(ParserErrorCode.EXPECTED_CLASS_DECLARATION_LBRACE);
- }
-
- if (isParsingInterface) {
- return done(new DartClass(tokenOffset, tokenLength, name, null, superType, implementsOffset,
- interfaces, mixins, defaultTokenOffset, openBraceOffset, closeBraceOffset, members,
- typeParameters, defaultClass, true, Modifiers.NONE));
- } else {
- return done(new DartClass(tokenOffset, tokenLength, name, nativeName, superType,
- implementsOffset, interfaces, mixins, defaultTokenOffset, openBraceOffset,
- closeBraceOffset, members, typeParameters, null, false, modifiers));
- }
- }
-
- /**
- * Helper for {@link #parseClass()}.
- *
- * classMemberDefinition*
- */
- @Terminals(tokens={Token.RBRACE, Token.SEMICOLON})
- private void parseClassOrInterfaceBody(List<DartNode> members) {
- while (!match(Token.RBRACE) && !EOS() && !looksLikeTopLevelKeyword()) {
- List<DartAnnotation> metadata = parseMetadata();
- DartNodeWithMetadata member = parseFieldOrMethod(true);
- if (member != null) {
- setMetadata(member, metadata);
- members.add(member);
- }
- // Recover at a semicolon
- if (optional(Token.SEMICOLON)) {
- reportUnexpectedToken(position(), null, Token.SEMICOLON);
- }
- }
- }
-
- private boolean optionalDeprecatedFactory() {
- if (optionalPseudoKeyword(FACTORY_KEYWORD)) {
- reportError(position(), ParserErrorCode.DEPRECATED_USE_OF_FACTORY_KEYWORD);
- return true;
- }
- return false;
- }
-
- private List<DartTypeNode> parseTypeAnnotationList() {
- List<DartTypeNode> result = new ArrayList<DartTypeNode>();
- do {
- result.add(parseTypeAnnotation());
- } while (optional(Token.COMMA));
- return result;
- }
-
- /**
- * Look ahead to detect if we are seeing ident [ TypeParameters ] "(".
- * We need this lookahead to distinguish between the optional return type
- * and the alias name of a function type alias.
- * Token position remains unchanged.
- *
- * @return true if the next tokens should be parsed as a type
- */
- private boolean isFunctionTypeAliasName() {
- beginFunctionTypeInterface();
- try {
- if (peek(0) == Token.IDENTIFIER && peek(1) == Token.LPAREN) {
- return true;
- }
- if (peek(0) == Token.IDENTIFIER && peek(1) == Token.LT) {
- consume(Token.IDENTIFIER);
- // isTypeParameter leaves the position advanced if it matches
- if (isTypeParameter() && peek(0) == Token.LPAREN) {
- return true;
- }
- }
- return false;
- } finally {
- rollback();
- }
- }
-
- /**
- * Returns true if the current and next tokens can be parsed as type
- * parameters. Current token position is not saved and restored.
- */
- private boolean isTypeParameter() {
- if (peek(0) == Token.LT) {
- // We are possibly looking at type parameters. Find closing ">".
- consume(Token.LT);
- int nestingLevel = 1;
- while (nestingLevel > 0) {
- switch (peek(0)) {
- case LT:
- nestingLevel++;
- break;
- case GT:
- nestingLevel--;
- break;
- case SAR: // >>
- nestingLevel -= 2;
- break;
- case COMMA:
- case EXTENDS:
- case IDENTIFIER:
- break;
- default:
- // We are looking at something other than type parameters.
- return false;
- }
- next();
- if (nestingLevel < 0) {
- return false;
- }
- }
- }
- return true;
- }
-
- /**
- * 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>
- *
- * @return the type alias that was parsed
- */
- private DartNodeWithMetadata parseTypeAlias() {
- if (match(Token.IDENTIFIER)) {
- Token next = peek(1);
- if (next == Token.LT) {
- int offset = skipTypeArguments(1, new DepthCounter());
- next = peek(offset);
- if (next != null && next == Token.ASSIGN) {
- return parseClassTypeAlias();
- }
- } else if (next == Token.ASSIGN) {
- return parseClassTypeAlias();
- }
- }
- return parseFunctionTypeAlias();
- }
-
- /**
- * Parse a class type alias.
- *
- * <pre>
- * classTypeAlias ::=
- * identifier typeParameters? '=' 'abstract'? mixinApplication
- *
- * mixinApplication ::=
- * type withClause implementsClause? ';'
- * </pre>
- *
- * @return the class type alias that was parsed
- */
- private DartClassTypeAlias parseClassTypeAlias() {
- beginClassTypeInterface();
-
- DartIdentifier name = parseIdentifier();
- if (PSEUDO_KEYWORDS_SET.contains(name.getName())) {
- reportError(name, ParserErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME);
- }
- List<DartTypeParameter> typeParameters = parseTypeParametersOpt();
-
- expect(Token.ASSIGN);
-
- Modifiers modifiers = Modifiers.NONE;
- if (optionalPseudoKeyword(ABSTRACT_KEYWORD)) {
- modifiers = modifiers.makeAbstract();
- }
-
- DartTypeNode superType = parseTypeAnnotation();
-
- List<DartTypeNode> mixins = null;
- if (optional(Token.WITH)) {
- mixins = parseTypeAnnotationList();
- }
-
- List<DartTypeNode> interfaces = null;
- if (optionalPseudoKeyword(IMPLEMENTS_KEYWORD)) {
- interfaces = parseTypeAnnotationList();
- }
-
- expect(Token.SEMICOLON);
- return done(new DartClassTypeAlias(name, typeParameters, modifiers, superType, mixins,
- interfaces));
- }
-
- /**
- * Parse a function type alias.
- *
- * <pre>
- * functionTypeAlias ::=
- * functionPrefix typeParameterList? formalParameterList ';'
- *
- * functionPrefix ::=
- * returnType? name
- * </pre>
- *
- * @return the function type alias that was parsed
- */
- private DartFunctionTypeAlias parseFunctionTypeAlias() {
- beginFunctionTypeInterface();
-
- DartTypeNode returnType = null;
- if (peek(0) == Token.VOID) {
- returnType = parseVoidType();
- } else if (!isFunctionTypeAliasName()) {
- returnType = parseTypeAnnotation();
- }
-
- DartIdentifier name = parseIdentifier();
- if (PSEUDO_KEYWORDS_SET.contains(name.getName())) {
- reportError(name, ParserErrorCode.BUILT_IN_IDENTIFIER_AS_TYPEDEF_NAME);
- }
-
- List<DartTypeParameter> typeParameters = parseTypeParametersOpt();
- FormalParameters params = parseFormalParameterList();
- expect(Token.SEMICOLON);
- validateNoDefaultParameterValues(
- params.val,
- ParserErrorCode.DEFAULT_VALUE_CAN_NOT_BE_SPECIFIED_IN_TYPEDEF);
-
- return done(new DartFunctionTypeAlias(name, returnType, params.val, typeParameters));
- }
-
- /**
- * Parse a field or method, which may be inside a class or at the top level.
- *
- * <pre>
- * // This rule is organized in a way that may not be most readable, but
- * // gives the best error messages.
- * classMemberDefinition
- * : declaration ';'
- * | methodDeclaration bodyOrNative
- * ;
- *
- * // Note: this syntax is not official, but used in dart_interpreter. It
- * // is unlikely that Dart will support numbered natives.
- * bodyOrNative
- * : error=NATIVE (':' (STRING | RATIONAL_NUMBER))? ';'
- * { legacy($error, "native not supported (yet)"); }
- * | functionStatementBody
- * ;
- *
- * // A method, operator, or constructor (which all should be followed by
- * // a function body).
- * methodDeclaration
- * : factoryConstructorDeclaration
- * | STATIC methodOrConstructorDeclaration
- * | specialSignatureDefinition
- * | methodOrConstructorDeclaration initializers?
- * | namedConstructorDeclaration initializers?
- * ;
- *
- *
- * // An abstract method/operator, a field, or const constructor (which
- * // all should be followed by a semicolon).
- * declaration
- * : constantConstructorDeclaration initializers?
- * | ABSTRACT specialSignatureDefinition
- * | ABSTRACT methodOrConstructorDeclaration
- * | STATIC CONST type? staticConstDeclarationList
- * | STATIC? variableDeclaration
- * ;
- *
- * interfaceMemberDefinition
- * : STATIC CONST type? initializedIdentifierList ';'
- * | methodOrConstructorDeclaration ';'
- * | constantConstructorDeclaration ';'
- * | namedConstructorDeclaration ';'
- * | specialSignatureDefinition ';'
- * | variableDeclaration ';'
- * ;
- *
- * variableDeclaration
- * : constVarOrType identifierList
- * ;
- *
- * methodOrConstructorDeclaration
- * : typeOrFunction? identifier formalParameterList
- * ;
- *
- * factoryConstructorDeclaration
- * : FACTORY qualified ('.' identifier)? formalParameterList
- * ;
- *
- * namedConstructorDeclaration
- * : identifier typeArguments? '.' identifier formalParameterList
- * ;
- *
- * constructorDeclaration
- * : identifier typeArguments? formalParameterList
- * | namedConstructorDeclaration
- * ;
- *
- * constantConstructorDeclaration
- * : CONST qualified formalParameterList
- * ;
- *
- * specialSignatureDefinition
- * : STATIC? type? getOrSet identifier formalParameterList
- * | type? OPERATOR operator formalParameterList
- * ;
- *
- * getOrSet
- * : GET
- * | SET
- * ;
- *
- * operator
- * : unaryOperator
- * | binaryOperator
- * | '[' ']' { "[]".equals($text) }?
- * | '[' ']' '=' { "[]=".equals($text) }?
- * | NEGATE
- * | CALL
- * ;
- * </pre>
- *
- * @param allowStatic true if the static modifier is allowed
- * @return a {@link DartNode} representing the grammar fragment above
- */
- @Terminals(tokens={Token.SEMICOLON})
- private DartNodeWithMetadata parseFieldOrMethod(boolean allowStatic) {
- beginClassMember();
- Modifiers modifiers = Modifiers.NONE;
- if (isBuiltInSpecial() && optionalPseudoKeyword(EXTERNAL_KEYWORD)) {
- modifiers = modifiers.makeExternal();
- }
- if (isBuiltInSpecial() && optionalPseudoKeyword(STATIC_KEYWORD)) {
- if (!allowStatic) {
- reportError(position(), ParserErrorCode.TOP_LEVEL_CANNOT_BE_STATIC);
- } else {
- if (isParsingInterface
- && peek(0) != Token.FINAL && peek(0) != Token.CONST) {
- reportError(position(), ParserErrorCode.NON_FINAL_STATIC_MEMBER_IN_INTERFACE);
- }
- modifiers = modifiers.makeStatic();
- }
- }
- if (isBuiltInSpecial() && optionalPseudoKeyword(ABSTRACT_KEYWORD)) {
- if (modifiers.isStatic()) {
- reportError(position(), ParserErrorCode.STATIC_MEMBERS_CANNOT_BE_ABSTRACT);
- }
- if (modifiers.isExternal()) {
- reportError(position(), ParserErrorCode.EXTERNAL_ABSTRACT);
- }
- modifiers = modifiers.makeAbstract();
- }
- if (isBuiltInSpecial() && optionalPseudoKeyword(FACTORY_KEYWORD)) {
- if (isParsingInterface) {
- reportError(position(), ParserErrorCode.FACTORY_MEMBER_IN_INTERFACE);
- }
- if (modifiers.isStatic()) {
- reportError(position(), ParserErrorCode.FACTORY_CANNOT_BE_STATIC);
- }
- if (modifiers.isAbstract()) {
- reportError(position(), ParserErrorCode.FACTORY_CANNOT_BE_ABSTRACT);
- }
-
- modifiers = modifiers.makeFactory();
- }
-
- if (match(Token.VAR) || match(Token.FINAL)) {
- if (modifiers.isAbstract()) {
- reportError(position(), ParserErrorCode.DISALLOWED_ABSTRACT_KEYWORD);
- }
- if (modifiers.isFactory()) {
- reportError(position(), ParserErrorCode.DISALLOWED_FACTORY_KEYWORD);
- }
- }
-
- // report "abstract" warning after all other checks to don't hide error with warning
- // we ignore problems if there was already reported problem after given position
- if (modifiers.isAbstract()) {
- reportError(position(), ParserErrorCode.DEPRECATED_ABSTRACT_METHOD);
- }
-
- if (modifiers.isFactory()) {
- if (!isParsingClass) {
- reportError(position(), ParserErrorCode.FACTORY_CANNOT_BE_TOP_LEVEL);
- }
- // Do parse factory.
- DartMethodDefinition factoryNode = parseFactory(modifiers);
- // If factory is not allowed, ensure that it is valid as method.
- DartExpression actualName = factoryNode.getName();
- if (!allowStatic && !(actualName instanceof DartIdentifier)) {
- DartExpression replacementName = new DartIdentifier(actualName.toString());
- factoryNode.setName(replacementName);
- }
- // Done.
- return done(factoryNode);
- }
-
- final DartNodeWithMetadata member;
-
- switch (peek(0)) {
- case VAR: {
- consume(Token.VAR);
- // Check for malformed method starting with 'var' : var ^ foo() { }
- if (peek(0).equals(Token.IDENTIFIER) && looksLikeMethodOrAccessorDefinition()) {
- reportError(position(), ParserErrorCode.VAR_IS_NOT_ALLOWED_ON_A_METHOD_DEFINITION);
- member = parseMethodOrAccessor(modifiers, null);
- break;
- }
-
- member = parseFieldDeclaration(modifiers, null);
- expectStatmentTerminator();
- break;
- }
-
- case CONST: {
- consume(Token.CONST);
- modifiers = modifiers.makeConstant();
- // Allow "const factory ... native" constructors for core libraries only
- if (optionalPseudoKeyword(FACTORY_KEYWORD)) {
- modifiers = modifiers.makeFactory();
- }
- if (peek(0).equals(Token.IDENTIFIER) && looksLikeMethodOrAccessorDefinition()) {
- return done(parseMethod(modifiers, null));
- }
- // Try to find type, may be "const ^ Type field".
- DartTypeNode type = null;
- if (peek(1) != Token.COMMA
- && peek(1) != Token.ASSIGN
- && peek(1) != Token.SEMICOLON) {
- type = parseTypeAnnotation();
- }
- // Parse field.
- modifiers = modifiers.makeFinal();
- member = parseFieldDeclaration(modifiers, type);
- expectStatmentTerminator();
- break;
- }
-
- case FINAL: {
- consume(Token.FINAL);
- modifiers = modifiers.makeFinal();
-
- // Check for malformed method starting with 'final': final ^ foo() { }
- if (peek(0).equals(Token.IDENTIFIER) && looksLikeMethodOrAccessorDefinition()) {
- reportError(position(), ParserErrorCode.FINAL_IS_NOT_ALLOWED_ON_A_METHOD_DEFINITION);
- member = parseMethodOrAccessor(modifiers, null);
- break;
- }
- DartTypeNode type = null;
- if (peek(1) != Token.COMMA
- && peek(1) != Token.ASSIGN
- && peek(1) != Token.SEMICOLON) {
- type = parseTypeAnnotation();
-
- // Check again for malformed method starting with 'final': final String ^ foo() { }
- if (peek(0).equals(Token.IDENTIFIER) && looksLikeMethodOrAccessorDefinition()) {
- reportError(position(), ParserErrorCode.FINAL_IS_NOT_ALLOWED_ON_A_METHOD_DEFINITION);
- member = parseMethodOrAccessor(modifiers, null);
- break;
- }
- }
- member = parseFieldDeclaration(modifiers, type);
- expectStatmentTerminator();
- break;
- }
-
- case IDENTIFIER: {
-
- // Check to see if it looks like the start of a method definition (sans type).
- if (looksLikeMethodOrAccessorDefinition()) {
- member = parseMethodOrAccessor(modifiers, null);
- break;
- }
- }
- //$FALL-THROUGH$
-
- case VOID: {
-
- // The next token may be a type specification or parameterized constructor: either a method or field.
- boolean isVoidType = peek(0) == Token.VOID;
- DartTypeNode type;
- if (isVoidType) {
- type = parseVoidType();
- } else {
- int nameIndex = skipTypeName(0);
- if (nameIndex < 0 || peek(nameIndex) != Token.IDENTIFIER) {
- // There was no type name.
- type = null;
- } else {
- type = parseTypeAnnotation();
- }
- }
- if (peek(1) == Token.SEMICOLON
- || peek(1) == Token.COMMA
- || peek(1) == Token.ASSIGN) {
- if (modifiers.isAbstract()) {
- reportError(position(), ParserErrorCode.INVALID_FIELD_DECLARATION);
- }
- member = parseFieldDeclaration(modifiers, type);
- if (isVoidType) {
- reportError(type, ParserErrorCode.VOID_FIELD);
- } else if (!modifiers.isFinal() && type == null) {
- reportError(position(), ParserErrorCode.INVALID_FIELD_DECLARATION);
- }
- expectStatmentTerminator();
- } else {
- member = parseMethodOrAccessor(modifiers, type);
- }
- break;
- }
-
- case SEMICOLON:
- default: {
- done(null);
- reportUnexpectedToken(position(), null, next());
- member = null;
- break;
- }
- }
- return member;
- }
-
- /**
- * Returns true if the beginning of a method definition follows.
- *
- * This test is needed to disambiguate between a method that returns a type
- * and a plain method.
- *
- * Assumes the next token has already been determined to be an identifier.
- *
- * The following constructs will match:
- *
- * : get (
- * | get identifier (
- * | set (
- * | set identifier (
- * | operator (
- * | operator <op> (
- * | identifier (
- * | identifier DOT identifier (
- * | identifier DOT identifier DOT identifier (
- *
- * @return <code>true</code> if the signature of a method has been found. No tokens are consumed.
- */
- private boolean looksLikeMethodOrAccessorDefinition() {
- assert (peek(0) == Token.IDENTIFIER );
- beginMethodName(); // begin() equivalent
- try {
- if (isBuiltInSpecial() && peekPseudoKeyword(0, OPERATOR_KEYWORD)) {
- next();
- // Using 'operator' as a field name is valid
- if (peek(0).equals(Token.SEMICOLON) || peek(0).equals(Token.ASSIGN)) {
- return false;
- }
- // Using 'operator' as a method name is valid (but discouraged)
- if (peek(0).equals(Token.LPAREN)) {
- return true;
- }
- // operator call (
- if (peekPseudoKeyword(0, CALL_KEYWORD) && peek(1).equals(Token.LPAREN)) {
- return true;
- }
- // TODO(zundel): Look for valid operator overload tokens. For now just assuming
- // non-idents are good enough
- // operator ??? (
- if (!(peek(0).equals(Token.IDENTIFIER) && peek(1).equals(Token.LPAREN))) {
- return true;
- }
- if (peek(0).equals(Token.LBRACK) && peek(1).equals(Token.RBRACK)) {
- // operator [] (
- if (peek(2).equals(Token.LPAREN)) {
- return true;
- }
- // operator []= (
- if (peek(2).equals(Token.ASSIGN) && peek(3).equals(Token.LPAREN)) {
- return true;
- }
- }
- return false;
- }
-
- if (peekPseudoKeyword(0, GETTER_KEYWORD)
- || peekPseudoKeyword(0, SETTER_KEYWORD)) {
- boolean isGetter = peekPseudoKeyword(0, GETTER_KEYWORD);
- next();
- // Using 'get' or 'set' as a field name is valid
- if (peek(0).equals(Token.SEMICOLON) || peek(0).equals(Token.ASSIGN)) {
- return false;
- }
- // Using 'get' or 'set' as a method name is valid (but discouraged)
- if (peek(0).equals(Token.LPAREN)) {
- return true;
- }
- // normal case: get foo (
- if (peek(0).equals(Token.IDENTIFIER) && (isGetter || peek(1).equals(Token.LPAREN))) {
- return true;
- }
- return false;
- }
-
- consume(Token.IDENTIFIER);
-
- if (peek(0).equals(Token.PERIOD) && peek(1).equals(Token.IDENTIFIER)) {
- consume(Token.PERIOD);
- consume(Token.IDENTIFIER);
-
- if (peek(0).equals(Token.PERIOD) && peek(1).equals(Token.IDENTIFIER)) {
- consume(Token.PERIOD);
- consume(Token.IDENTIFIER);
- }
- }
-
- // next token should be LPAREN
- return (peek(0).equals(Token.LPAREN));
- } finally {
- rollback();
- }
- }
-
- /**
- * <pre>
- * factoryConstructorDeclaration
- * : FACTORY qualified ('.' identifier)? formalParameterList
- * ;
- * </pre>
- */
- private DartMethodDefinition parseFactory(Modifiers modifiers) {
- beginMethodName();
- DartExpression name = parseQualified(true);
- if (optional(Token.PERIOD)) {
- name = doneWithoutConsuming(new DartPropertyAccess(name, parseIdentifier()));
- }
- done(name);
- FormalParameters formals = parseFormalParameterList();
- int parametersCloseParen = ctx.getTokenLocation().getBegin();
-
- // Parse redirecting factory
- if (match(Token.ASSIGN)) {
- next();
- if (!modifiers.isFactory()) {
- reportError(position(), ParserErrorCode.ONLY_FACTORIES_CAN_REDIRECT);
- }
- modifiers = modifiers.makeRedirectedConstructor();
- DartTypeNode redirectedTypeName = parseTypeAnnotationPossiblyFollowedByName();
- DartIdentifier redirectedConstructorName = null;
- if (optional(Token.PERIOD)) {
- redirectedConstructorName = parseIdentifier();
- }
- expect(Token.SEMICOLON);
- DartFunction function = doneWithoutConsuming(new DartFunction(formals.val, formals.openParen,
- formals.optionalOpenOffset, formals.optionalCloseOffset, parametersCloseParen, null, null));
- return DartMethodDefinition.create(name, function, modifiers, redirectedTypeName,
- redirectedConstructorName);
- }
-
- DartFunction function;
- if (peekPseudoKeyword(0, NATIVE_KEYWORD)) {
- modifiers = modifiers.makeNative();
- function = new DartFunction(formals.val, formals.optionalOpenOffset,
- formals.optionalOpenOffset, formals.optionalCloseOffset, parametersCloseParen,
- parseNativeBlock(modifiers), null);
- } else {
- function = new DartFunction(formals.val, formals.optionalOpenOffset,
- formals.optionalOpenOffset, formals.optionalCloseOffset, parametersCloseParen,
- parseFunctionStatementBody(!modifiers.isExternal(), true), null);
- }
- doneWithoutConsuming(function);
- return DartMethodDefinition.create(name, function, modifiers, null);
- }
-
- private DartIdentifier parseVoidIdentifier() {
- beginIdentifier();
- expect(Token.VOID);
- return done(new DartIdentifier(Token.VOID.getSyntax()));
- }
-
- private DartTypeNode parseVoidType() {
- beginTypeAnnotation();
- return done(new DartTypeNode(parseVoidIdentifier()));
- }
-
- private DartMethodDefinition parseMethod(Modifiers modifiers, DartTypeNode returnType) {
- DartExpression name = new DartIdentifier("");
-
- if (modifiers.isFactory()) {
- if (modifiers.isAbstract()) {
- reportError(position(), ParserErrorCode.FACTORY_CANNOT_BE_ABSTRACT);
- }
- if (modifiers.isStatic()) {
- reportError(position(), ParserErrorCode.FACTORY_CANNOT_BE_STATIC);
- }
- }
-
- int arity = -1;
- Token operation = null;
- if (isBuiltInSpecial() && optionalPseudoKeyword(OPERATOR_KEYWORD)) {
- // Overloaded operator.
- if (modifiers.isStatic()) {
- reportError(position(), ParserErrorCode.OPERATOR_CANNOT_BE_STATIC);
- }
- modifiers = modifiers.makeOperator();
-
- beginOperatorName();
- operation = next();
- if (operation.isUserDefinableOperator()) {
- name = done(new DartIdentifier(operation.getSyntax()));
- if (operation == Token.ASSIGN_INDEX) {
- arity = 2;
- } else if (operation == Token.SUB) {
- arity = -1;
- } else if (operation.isBinaryOperator()) {
- arity = 1;
- } else if (operation == Token.INDEX) {
- arity = 1;
- } else {
- assert operation.isUnaryOperator();
- arity = 0;
- }
- } else if (operation == Token.IDENTIFIER
- && ctx.getTokenString().equals(CALL_KEYWORD)) {
- name = done(new DartIdentifier(CALL_KEYWORD));
- arity = -1;
- } else if (operation == Token.IDENTIFIER
- && ctx.getTokenString().equals(CALL_KEYWORD)) {
- name = done(new DartIdentifier(CALL_KEYWORD));
- } else {
- // Not a valid operator. Try to recover.
- boolean found = false;
- for (int i = 0; i < 4; ++i) {
- if (peek(i).equals(Token.LPAREN)) {
- found = true;
- break;
- }
- }
- StringBuilder buf = new StringBuilder();
- buf.append(operation.getSyntax());
- if (found) {
- reportError(position(), ParserErrorCode.OPERATOR_IS_NOT_USER_DEFINABLE);
- while(true) {
- Token token = peek(0);
- if (token.equals(Token.LPAREN)) {
- break;
- }
- buf.append(next().getSyntax());
- }
- name = done(new DartIdentifier(buf.toString()));
- } else {
- reportUnexpectedToken(position(), Token.COMMENT, operation);
- done(null);
- }
- }
- } else {
- beginMethodName();
- // Check for getters and setters.
- if (peek(1) != Token.LPAREN && optionalPseudoKeyword(GETTER_KEYWORD)) {
- name = parseIdentifier();
- modifiers = modifiers.makeGetter();
- arity = 0;
- } else if (peek(1) != Token.LPAREN && optionalPseudoKeyword(SETTER_KEYWORD)) {
- name = parseIdentifier();
- modifiers = modifiers.makeSetter();
- arity = 1;
- } else {
- // Normal method or property.
- name = parseIdentifier();
- }
-
- // Check for named constructor.
- if (optional(Token.PERIOD)) {
- name = doneWithoutConsuming(new DartPropertyAccess(name, parseIdentifier()));
- if(currentlyParsingToplevel()) {
- // TODO: Error recovery could find a missing brace and treat this as an expression
- reportError(name, ParserErrorCode.FUNCTION_NAME_EXPECTED_IDENTIFIER);
- }
- if (optional(Token.PERIOD)) {
- name = doneWithoutConsuming(new DartPropertyAccess(name, parseIdentifier()));
- }
- }
- done(null);
- }
-
- // Parse the parameters definitions.
- FormalParameters parametersInfo;
- if (modifiers.isGetter()) {
- parametersInfo = new FormalParameters(new ArrayList<DartParameter>(), -1, -1, -1);
- if (peek(0) == Token.LPAREN) {
- reportError(position(), ParserErrorCode.DEPRECATED_GETTER);
- parametersInfo = parseFormalParameterList();
- }
- } else {
- parametersInfo = parseFormalParameterList();
- }
- List<DartParameter> parameters = parametersInfo.val;
- int parametersCloseParen = ctx.getTokenLocation().getBegin();
-
- if (arity != -1) {
- if (parameters.size() != arity) {
- reportError(position(), ParserErrorCode.ILLEGAL_NUMBER_OF_PARAMETERS);
- }
- // In methods with required arity each parameter is required.
- for (int i = 0, size = parameters.size(); i < size; i++) {
- DartParameter parameter = parameters.get(i);
- if (parameter.getModifiers().isOptional()) {
- reportError(parameter, ParserErrorCode.OPTIONAL_POSITIONAL_PARAMETER_NOT_ALLOWED);
- }
- if (parameter.getModifiers().isNamed()) {
- reportError(parameter, ParserErrorCode.NAMED_PARAMETER_NOT_ALLOWED);
- }
- }
- } else if (operation == Token.SUB) {
- if (parameters.size() != 0 && parameters.size() != 1) {
- reportError(position(), ParserErrorCode.ILLEGAL_NUMBER_OF_PARAMETERS);
- }
- // In methods with required arity each parameter is required.
- for (int i = 0, size = parameters.size(); i < size; i++) {
- DartParameter parameter = parameters.get(i);
- if (parameter.getModifiers().isNamed()) {
- reportError(parameter, ParserErrorCode.NAMED_PARAMETER_NOT_ALLOWED);
- }
- }
- }
-
- // Parse redirecting factory
- DartTypeNode redirectedTypeName = null;
- DartIdentifier redirectedConstructorName = null;
- if (match(Token.ASSIGN)) {
- next();
- if (!modifiers.isFactory()) {
- reportError(position(), ParserErrorCode.ONLY_FACTORIES_CAN_REDIRECT);
- }
- modifiers = modifiers.makeRedirectedConstructor();
- redirectedTypeName = parseTypeAnnotationPossiblyFollowedByName();
- if (optional(Token.PERIOD)) {
- redirectedConstructorName = parseIdentifier();
- }
- expect(Token.SEMICOLON);
- DartFunction function = doneWithoutConsuming(new DartFunction(parameters,
- parametersInfo.openParen, parametersInfo.optionalOpenOffset,
- parametersInfo.optionalCloseOffset, parametersCloseParen, null, returnType));
- return DartMethodDefinition.create(name, function, modifiers, redirectedTypeName,
- redirectedConstructorName);
- }
-
- // Parse initializer expressions for constructors.
- List<DartInitializer> initializers = new ArrayList<DartInitializer>();
- if (match(Token.COLON) && !(isParsingInterface || modifiers.isFactory())) {
- parseInitializers(initializers);
- boolean isRedirectedConstructor = validateInitializers(parameters, initializers);
- if (isRedirectedConstructor) {
- modifiers = modifiers.makeRedirectedConstructor();
- }
- }
-
- // Parse the body.
- DartBlock body = null;
- if (!optional(Token.SEMICOLON)) {
- if (peekPseudoKeyword(0, NATIVE_KEYWORD)) {
- modifiers = modifiers.makeNative();
- body = parseNativeBlock(modifiers);
- } else {
- body = parseFunctionStatementBody(!modifiers.isExternal(), true);
- }
- if (body != null && modifiers.isRedirectedConstructor()) {
- reportError(position(), ParserErrorCode.REDIRECTING_CONSTRUCTOR_CANNOT_HAVE_A_BODY);
- }
- }
-
- DartFunction function = doneWithoutConsuming(new DartFunction(parameters,
- parametersInfo.openParen, parametersInfo.optionalOpenOffset,
- parametersInfo.optionalCloseOffset, parametersCloseParen, body, returnType));
- return DartMethodDefinition.create(name, function, modifiers, initializers);
- }
-
- private DartBlock parseNativeBlock(Modifiers modifiers) {
- beginNativeBody();
- if (!optionalPseudoKeyword(NATIVE_KEYWORD)) {
- throw new AssertionError();
- }
- if (!allowNativeKeyword) {
- reportError(position(), ParserErrorCode.NATIVE_ONLY_CORE_LIB);
- }
- DartExpression body = null;
- if (match(Token.STRING)) {
- body = parseStringWithPasting();
- }
- if (match(Token.LBRACE) || match(Token.ARROW)) {
- return done(parseFunctionStatementBody(!modifiers.isExternal(), true));
- } else {
- expect(Token.SEMICOLON);
- return done(new DartNativeBlock(body));
- }
- }
-
- private DartNodeWithMetadata parseMethodOrAccessor(Modifiers modifiers, DartTypeNode returnType) {
- DartMethodDefinition method = done(parseMethod(modifiers, returnType));
- // Abstract method can not have a body.
- if (method.getFunction().getBody() != null) {
- if (isParsingInterface) {
- reportError(method.getName(), ParserErrorCode.INTERFACE_METHOD_WITH_BODY);
- }
- if (method.getModifiers().isAbstract()) {
- reportError(method.getName(), ParserErrorCode.ABSTRACT_METHOD_WITH_BODY);
- }
- }
- // If getter or setter, generate DartFieldDefinition instead.
- if (method.getModifiers().isGetter() || method.getModifiers().isSetter()) {
- DartField field = new DartField((DartIdentifier) method.getName(),
- method.getModifiers().makeAbstractField(), method, null);
- field.setSourceInfo(method.getSourceInfo());
- DartFieldDefinition fieldDefinition =
- new DartFieldDefinition(null, Lists.<DartField>create(field));
- fieldDefinition.setSourceInfo(field.getSourceInfo());
- return fieldDefinition;
- }
- // OK, use method as method.
- return method;
- }
-
- /**
- * <pre>
- * initializers
- * : ':' superCallOrFirstFieldInitializer (',' fieldInitializer)*
- * | THIS ('.' identifier) formalParameterList
- * ;
- *
- * fieldInitializer
- * : (THIS '.')? identifier '=' conditionalExpression
- * ;
- *
- * superCallOrFirstFieldInitializer
- * : SUPER arguments | SUPER '.' identifier arguments
- * | fieldInitializer
- * ;
- *
- * fieldInitializer
- * : (THIS '.')? identifier '=' conditionalExpression
- * | THIS ('.' identifier)? arguments
- * ;
- * </pre>
- */
- private void parseInitializers(List<DartInitializer> initializers) {
- expect(Token.COLON);
- do {
- beginInitializer();
- if (match(Token.SUPER)) {
- beginSuperInitializer();
- expect(Token.SUPER);
- DartIdentifier constructor = null;
- if (optional(Token.PERIOD)) {
- constructor = parseIdentifier();
- }
- DartSuperConstructorInvocation superInvocation =
- new DartSuperConstructorInvocation(constructor, parseArguments());
- initializers.add(done(new DartInitializer(null, done(superInvocation))));
- } else {
- boolean hasThisPrefix = optional(Token.THIS);
- if (hasThisPrefix) {
- if (match(Token.LPAREN)) {
- parseRedirectedConstructorInvocation(null, initializers);
- continue;
- }
- expect(Token.PERIOD);
- }
- DartIdentifier name = parseIdentifier();
- if (hasThisPrefix && match(Token.LPAREN)) {
- parseRedirectedConstructorInvocation(name, initializers);
- continue;
- } else {
- expect(Token.ASSIGN);
- boolean save = setAllowFunctionExpression(false);
- DartExpression initExpr = parseExpression();
- setAllowFunctionExpression(save);
- initializers.add(done(new DartInitializer(name, initExpr)));
- }
- }
- } while (optional(Token.COMMA));
- }
-
- private void parseRedirectedConstructorInvocation(DartIdentifier name,
- List<DartInitializer> initializers) {
- DartRedirectConstructorInvocation redirConstructor =
- new DartRedirectConstructorInvocation(name, parseArguments());
- initializers.add(done(new DartInitializer(null, doneWithoutConsuming(redirConstructor))));
- }
-
- private boolean validateInitializers(List<DartParameter> parameters,
- List<DartInitializer> initializers) {
- // Try to find DartRedirectConstructorInvocation, check for multiple invocations.
- // Check for DartSuperConstructorInvocation multiple invocations.
- DartInitializer redirectInitializer = null;
- boolean firstMultipleRedirectReported = false;
- {
- DartInitializer superInitializer = null;
- boolean firstMultipleSuperReported = false;
- for (DartInitializer initializer : initializers) {
- if (initializer.isInvocation()) {
- // DartSuperConstructorInvocation
- DartExpression initializerInvocation = initializer.getValue();
- if (initializerInvocation instanceof DartSuperConstructorInvocation) {
- if (superInitializer != null) {
- if (!firstMultipleSuperReported) {
- reportError(superInitializer, ParserErrorCode.SUPER_CONSTRUCTOR_MULTIPLE);
- firstMultipleSuperReported = true;
- }
- reportError(initializer, ParserErrorCode.SUPER_CONSTRUCTOR_MULTIPLE);
- } else {
- superInitializer = initializer;
- }
- }
- // DartRedirectConstructorInvocation
- if (initializerInvocation instanceof DartRedirectConstructorInvocation) {
- if (redirectInitializer != null) {
- if (!firstMultipleRedirectReported) {
- reportError(redirectInitializer, ParserErrorCode.REDIRECTING_CONSTRUCTOR_MULTIPLE);
- firstMultipleRedirectReported = true;
- }
- reportError(initializer, ParserErrorCode.REDIRECTING_CONSTRUCTOR_MULTIPLE);
- } else {
- redirectInitializer = initializer;
- }
- }
- }
- }
- }
- // If there is redirecting constructor, then there should be no other initializers.
- if (redirectInitializer != null) {
- boolean shouldRedirectInvocationReported = false;
- // Implicit initializer in form of "this.id" parameter.
- for (DartParameter parameter : parameters) {
- if (parameter.getName() instanceof DartPropertyAccess) {
- DartPropertyAccess propertyAccess = (DartPropertyAccess) parameter.getName();
- if (propertyAccess.getQualifier() instanceof DartThisExpression) {
- shouldRedirectInvocationReported = true;
- reportError(
- parameter,
- ParserErrorCode.REDIRECTING_CONSTRUCTOR_PARAM);
- }
- }
- }
- // Iterate all initializers and mark all except of DartRedirectConstructorInvocation
- for (DartInitializer initializer : initializers) {
- if (!(initializer.getValue() instanceof DartRedirectConstructorInvocation)) {
- shouldRedirectInvocationReported = true;
- reportError(
- initializer,
- ParserErrorCode.REDIRECTING_CONSTRUCTOR_OTHER);
- }
- }
- // Mark DartRedirectConstructorInvocation if needed.
- if (shouldRedirectInvocationReported) {
- reportError(
- redirectInitializer,
- ParserErrorCode.REDIRECTING_CONSTRUCTOR_ITSELF);
- }
- }
- // Done.
- return redirectInitializer != null;
- }
-
- /**
- * <pre>
- * variableDeclaration
- * : constVarOrType identifierList
- * ;
- * identifierList
- * : identifier (',' identifier)*
- * ;
- *
- * staticConstDeclarationList
- * : staticConstDeclaration (',' staticConstDeclaration)*
- * ;
- *
- * staticConstDeclaration
- * : identifier '=' constantExpression
- * ;
- *
- * // The compile-time expression production is used to mark certain expressions
- * // as only being allowed to hold a compile-time constant. The grammar cannot
- * // express these restrictions, so this will have to be enforced by a separate
- * // analysis phase.
- * constantExpression
- * : expression
- * ;
- * </pre>
- */
- private DartFieldDefinition parseFieldDeclaration(Modifiers modifiers, DartTypeNode type) {
- List<DartField> fields = new ArrayList<DartField>();
- List<DartAnnotation> metadata = parseMetadata();
- do {
- beginVariableDeclaration();
- DartIdentifier name = parseIdentifier();
- DartExpression value = null;
- if (optional(Token.ASSIGN)) {
- value = parseExpression();
- if (value != null) {
- modifiers = modifiers.makeInitialized();
- }
- }
- if (modifiers.isExternal()) {
- reportError(name, ParserErrorCode.EXTERNAL_ONLY_METHOD);
- }
- DartField field = done(new DartField(name, modifiers, null, value));
- setMetadata(field, metadata);
- fields.add(field);
- } while (optional(Token.COMMA));
- DartFieldDefinition definition = new DartFieldDefinition(type, fields);
- setMetadata(definition, metadata);
- return done(definition);
- }
-
- private static class FormalParameters {
- private final List<DartParameter> val;
- private final int openParen;
- private final int optionalOpenOffset;
- private final int optionalCloseOffset;
- public FormalParameters(List<DartParameter> parameters, int openParen, int optionalOpenOffset,
- int optionalCloseOffset) {
- this.val = parameters;
- this.openParen = openParen;
- this.optionalOpenOffset = optionalOpenOffset;
- this.optionalCloseOffset = optionalCloseOffset;
- }
- }
-
- /**
- * <pre>
- * formalParameterList
- * : '(' ')'
- * | '(' normalFormalParameters (',' optionalFormalParameters)? ')'
- * | '(' optionalFormalParameters ')'
- * ;
- *
- * normalFormalParameters
- * : normalFormalParameter (',' normalFormalParameter)*
- * ;
- *
- * optionalFormalParameters
- * : optionalPositionalFormalParameters
- * | namedFormalParameters
- * ;
- *
- * optionalPositionalFormalParameters
- * : '[' defaultFormalParameter (',' defaultFormalParameter)* ']'
- * ;
- *
- * namedFormalParameters
- * : '{' defaultNamedParameter (',' defaultNamedParameter)* '}'
- * ;
- * </pre>
- */
- @Terminals(tokens = {Token.COMMA, Token.RPAREN})
- private FormalParameters parseFormalParameterList() {
- beginFormalParameterList();
- List<DartParameter> params = new ArrayList<DartParameter>();
- int optionalOpenOffset = -1;
- int optionalCloseOffset = -1;
- expect(Token.LPAREN);
- boolean done = optional(Token.RPAREN);
- int openParen = ctx.getTokenLocation().getBegin();
- boolean isOptional = false;
- boolean isNamed = false;
- while (!done) {
- if (!isOptional && optional(Token.LBRACK)) {
- if (isNamed) {
- reportErrorWithoutAdvancing(ParserErrorCode.CANNOT_MIX_OPTIONAL_AND_NAMED_PARAMETERS);
- }
- isOptional = true;
- optionalOpenOffset = ctx.getTokenLocation().getBegin();
- }
- if (!isNamed && optional(Token.LBRACE)) {
- if (isOptional) {
- reportErrorWithoutAdvancing(ParserErrorCode.CANNOT_MIX_OPTIONAL_AND_NAMED_PARAMETERS);
- }
- isNamed = true;
- optionalOpenOffset = ctx.getTokenLocation().getBegin();
- }
-
- DartParameter param = parseFormalParameter(isOptional, isNamed);
- params.add(param);
-
- if (isOptional && optional(Token.RBRACK)) {
- optionalCloseOffset = ctx.getTokenLocation().getBegin();
- expectCloseParen();
- break;
- }
- if (isNamed && optional(Token.RBRACE)) {
- optionalCloseOffset = ctx.getTokenLocation().getBegin();
- expectCloseParen();
- break;
- }
-
- // Ensure termination if token is anything other than COMMA.
- // Must keep Token.COMMA in sync with @Terminals above
- if (!optional(Token.COMMA)) {
- if (isOptional && !optional(Token.RBRACE)) {
- reportErrorWithoutAdvancing(ParserErrorCode.MISSING_OPTIONAL_PARAMETER_END);
- }
- if (isNamed && !optional(Token.RBRACK)) {
- reportErrorWithoutAdvancing(ParserErrorCode.MISSING_NAMED_PARAMETER_END);
- }
- // Must keep Token.RPAREN in sync with @Terminals above
- expectCloseParen();
- done = true;
- }
- }
-
- return new FormalParameters(done(params), openParen, optionalOpenOffset, optionalCloseOffset);
- }
-
- /**
- * <pre>
- * normalFormalParameter
- * : functionDeclaration
- * | fieldFormalParameter
- * | simpleFormalParameter
- * ;
- *
- * defaultFormalParameter
- * : normalFormalParameter ('=' constantExpression)?
- * ;
- *
- * defaultNamedParameter
- * : normalFormalParameter (':' constantExpression)?
- * ;
- * </pre>
- */
- private DartParameter parseFormalParameter(boolean isOptional, boolean isNamed) {
- beginFormalParameter();
- List<DartAnnotation> metadata = parseMetadata();
- DartExpression paramName = null;
- DartTypeNode type = null;
- DartExpression defaultExpr = null;
- List<DartParameter> functionParams = null;
- boolean hasVar = false;
- Modifiers modifiers = Modifiers.NONE;
-
- if (isOptional) {
- modifiers = modifiers.makeOptional();
- }
- if (isNamed) {
- modifiers = modifiers.makeNamed();
- }
-
- if (optional(Token.FINAL)) {
- modifiers = modifiers.makeFinal();
- } else if (optional(Token.CONST)) {
- reportError(position(), ParserErrorCode.FORMAL_PARAMETER_IS_CONST);
- } else if (optional(Token.VAR)) {
- hasVar = true;
- }
-
- boolean isVoidType = false;
- if (!hasVar) {
- isVoidType = (peek(0) == Token.VOID);
- if (isVoidType) {
- type = parseVoidType();
- } else if ((peek(0) != Token.ELLIPSIS)
- && (peek(1) != Token.COMMA)
- && (peek(1) != Token.RPAREN)
- && (peek(1) != Token.RBRACE)
- && (peek(1) != Token.RBRACK)
- && (peek(1) != Token.ASSIGN)
- && (peek(1) != Token.COLON)
- && (peek(1) != Token.LPAREN)
- && (peek(0) != Token.THIS)) {
- // Must be a type specification.
- type = parseTypeAnnotation();
- }
- }
-
- paramName = parseParameterName();
-
- if (peek(0) == Token.LPAREN) {
- // Function parameter.
- if (modifiers.isFinal()) {
- reportError(position(), ParserErrorCode.FUNCTION_TYPED_PARAMETER_IS_FINAL);
- }
- if (hasVar) {
- reportError(position(), ParserErrorCode.FUNCTION_TYPED_PARAMETER_IS_VAR);
- }
- functionParams = parseFormalParameterList().val;
- validateNoDefaultParameterValues(
- functionParams,
- ParserErrorCode.DEFAULT_VALUE_CAN_NOT_BE_SPECIFIED_IN_CLOSURE);
- } else {
- // Not a function parameter.
- if (isVoidType) {
- reportError(type, ParserErrorCode.VOID_PARAMETER);
- }
- }
-
- // Look for an initialization expression
- switch (peek(0)) {
- case COMMA:
- case RPAREN:
- case RBRACE:
- case RBRACK:
- // It is a simple parameter.
- break;
-
- case ASSIGN:
- // Default parameter -- only allowed for optional parameters.
- if (isOptional) {
- consume(Token.ASSIGN);
- defaultExpr = parseExpression();
- } else if (isNamed) {
- reportError(position(), ParserErrorCode.INVALID_SEPARATOR_FOR_NAMED);
- consume(Token.ASSIGN);
- defaultExpr = parseExpression();
- } else {
- reportError(position(), ParserErrorCode.DEFAULT_POSITIONAL_PARAMETER);
- }
- break;
-
- case COLON:
- // Default parameter -- only allowed for named parameters.
- if (isNamed) {
- consume(Token.COLON);
- defaultExpr = parseExpression();
- } else if (isOptional) {
- reportError(position(), ParserErrorCode.INVALID_SEPARATOR_FOR_OPTIONAL);
- consume(Token.COLON);
- defaultExpr = parseExpression();
- } else {
- reportError(position(), ParserErrorCode.DEFAULT_POSITIONAL_PARAMETER);
- }
- break;
-
- default:
- reportUnexpectedToken(position(), null, peek(0));
- break;
- }
-
- DartParameter parameter = new DartParameter(paramName, type, functionParams, defaultExpr,
- modifiers);
- setMetadata(parameter, metadata);
- return done(parameter);
- }
-
- /**
- * <pre>
- * simpleFormalParameter
- * : declaredIdentifier
- * | identifier
- * ;
- *
- * fieldFormalParameter
- * : finalVarOrType? THIS '.' identifier
- * ;
- * </pre>
- */
- private DartExpression parseParameterName() {
- beginParameterName();
- if (match(Token.THIS)) {
- beginThisExpression();
- expect(Token.THIS);
- DartThisExpression thisExpression = done(DartThisExpression.get());
- expect(Token.PERIOD);
- return done(new DartPropertyAccess(thisExpression, parseIdentifier()));
- }
- return done(parseIdentifier());
- }
-
- /**
- * Validates that given {@link DartParameter}s have no default values, or marks existing default
- * values with given {@link ErrorCode}.
- */
- private void validateNoDefaultParameterValues(List<DartParameter> parameters,
- ErrorCode errorCode) {
- for (int i = 0, size = parameters.size(); i < size; i++) {
- DartParameter parameter = parameters.get(i);
- DartExpression defaultExpr = parameter.getDefaultExpr();
- if (defaultExpr != null) {
- reportError(defaultExpr, errorCode);
- }
- }
- }
-
- /**
- * Parse an expression.
- *
- * <pre>
- * expression
- * : assignableExpression assignmentOperator expression
- * | conditionalExpression cascadeSection*
- * | throwExpression
- * ;
- *
- * assignableExpression
- * : primary (arguments* assignableSelector)+
- * | SUPER assignableSelector
- * | identifier
- * ;
- * </pre>
- *
- * @return an expression matching the {@code expression} production above
- */
- @VisibleForTesting
- public DartExpression parseExpression() {
- if (peek(0) == Token.THROW) {
- return parseThrowExpression(true);
- }
- beginExpression();
- if (looksLikeTopLevelKeyword() || peek(0).equals(Token.RBRACE)) {
- // Allow recovery back to the top level.
- reportErrorWithoutAdvancing(ParserErrorCode.UNEXPECTED_TOKEN);
- return done(null);
- }
- DartExpression result = parseConditionalExpression();
- Token token = peek(0);
- if (token == Token.CASCADE) {
- List<DartExpression> cascadeSections = new ArrayList<DartExpression>();
- while (token == Token.CASCADE) {
- beginExpression();
- DartExpression section = parseCascadeSection();
- done(section);
- if (section != null) {
- cascadeSections.add(section);
- }
- token = peek(0);
- }
- result = done(new DartCascadeExpression(result, cascadeSections));
- } else if (token.isAssignmentOperator()) {
- ensureAssignable(result);
- consume(token);
- int tokenOffset = ctx.getTokenLocation().getBegin();
- result = done(new DartBinaryExpression(token, tokenOffset, result, parseExpression()));
- } else {
- done(null);
- }
- return result;
- }
-
- /**
- * Parse an expression without a cascade.
- *
- * <pre>
- * expressionWithoutCascade
- * : assignableExpression assignmentOperator expressionWithoutCascade
- * | conditionalExpression
- * ;
- * </pre>
- *
- * @return an expression matching the {@code expression} production above
- */
- private DartExpression parseExpressionWithoutCascade() {
- if (peek(0) == Token.THROW) {
- return parseThrowExpression(false);
- }
- beginExpression();
- if (looksLikeTopLevelKeyword() || peek(0).equals(Token.RBRACE)) {
- // Allow recovery back to the top level.
- reportErrorWithoutAdvancing(ParserErrorCode.UNEXPECTED_TOKEN);
- return done(null);
- }
- DartExpression result = parseConditionalExpression();
- Token token = peek(0);
- if (token.isAssignmentOperator()) {
- ensureAssignable(result);
- consume(token);
- int tokenOffset = ctx.getTokenLocation().getBegin();
- result = done(new DartBinaryExpression(token, tokenOffset, result, parseExpressionWithoutCascade()));
- } else {
- done(null);
- }
- return result;
- }
-
- /**
- * Parse a cascade section.
- * <pre>
- * cascadeSection
- * : CASCADE (cascadeSelector arguments*) (assignableSelector arguments*)* (assignmentOperator
- * expressionWithoutCascade)?
- * ;
- *
- * cascadeSelector
- * : LBRACK expression RBRACK
- * | identifier
- * ;
- * </pre>
- *
- * @return the expression representing the cascaded method invocation
- */
- private DartExpression parseCascadeSection() {
- expect(Token.CASCADE);
- DartExpression result = null;
- DartIdentifier functionName = null;
- if (peek(0) == Token.IDENTIFIER) {
- functionName = parseIdentifier();
- } else if (peek(0) == Token.LBRACK) {
- consume(Token.LBRACK);
- result = doneWithoutConsuming(new DartArrayAccess(result, true, parseExpression()));
- expect(Token.RBRACK);
- } else {
- reportUnexpectedToken(position(), null, next());
- return result;
- }
- if (peek(0) == Token.LPAREN) {
- while (peek(0) == Token.LPAREN) {
- if (functionName != null) {
- result = doneWithoutConsuming(new DartMethodInvocation(result, result == null, functionName, parseArguments()));
- functionName = null;
- } else if (result == null) {
- return null;
- } else {
- result = doneWithoutConsuming(new DartFunctionObjectInvocation(result, parseArguments()));
- }
- }
- } else if (functionName != null) {
- result = doneWithoutConsuming(new DartPropertyAccess(result, result == null, functionName));
- }
- boolean progress = true;
- while (progress) {
- progress = false;
- DartExpression selector = tryParseAssignableSelector(result);
- if (selector != null) {
- result = selector;
- progress = true;
- while (peek(0) == Token.LPAREN) {
- result = doneWithoutConsuming(new DartFunctionObjectInvocation(result, parseArguments()));
- }
- }
- }
- Token token = peek(0);
- if (token.isAssignmentOperator()) {
- ensureAssignable(result);
- consume(token);
- int tokenOffset = ctx.getTokenLocation().getBegin();
- result = doneWithoutConsuming(new DartBinaryExpression(token, tokenOffset, result, parseExpressionWithoutCascade()));
- }
- return result;
- }
-
- /**
- * expressionList
- * : expression (',' expression)*
- * ;
- */
- @Terminals(tokens={Token.COMMA})
- private DartExpression parseExpressionList() {
- beginExpressionList();
- DartExpression result = parseExpression();
- // Must keep in sync with @Terminals above
- while (optional(Token.COMMA)) {
- int tokenOffset = ctx.getTokenLocation().getBegin();
- result = new DartBinaryExpression(Token.COMMA, tokenOffset, result, parseExpression());
- if (match(Token.COMMA)) {
- result = doneWithoutConsuming(result);
- }
- }
- return done(result);
- }
-
-
- /**
- * Parse a binary expression.
- *
- * <pre>
- * logicalOrExpression
- * : logicalAndExpression ('||' logicalAndExpression)*
- * ;
- *
- * logicalAndExpression
- * : bitwiseOrExpression ('&&' bitwiseOrExpression)*
- * ;
- *
- * bitwiseOrExpression
- * : bitwiseXorExpression ('|' bitwiseXorExpression)*
- * ;
- *
- * bitwiseXorExpression
- * : bitwiseAndExpression ('^' bitwiseAndExpression)*
- * ;
- *
- * bitwiseAndExpression
- * : equalityExpression ('&' equalityExpression)*
- * ;
- *
- * equalityExpression
- * : relationalExpression (equalityOperator relationalExpression)?
- * ;
- *
- * relationalExpression
- * : shiftExpression (isOperator type | relationalOperator shiftExpression)?
- * ;
- *
- * shiftExpression
- * : additiveExpression (shiftOperator additiveExpression)*
- * ;
- *
- * additiveExpression
- * : multiplicativeExpression (additiveOperator multiplicativeExpression)*
- * ;
- *
- * multiplicativeExpression
- * : unaryExpression (multiplicativeOperator unaryExpression)*
- * ;
- * </pre>
- *
- * @return an expression matching one of the productions above
- */
- private DartExpression parseBinaryExpression(int precedence) {
- assert (precedence >= 4);
- beginBinaryExpression();
- DartExpression lastResult = parseUnaryExpression();
- DartExpression result = lastResult;
- for (int level = peekMaybeAS(0).getPrecedence(); level >= precedence; level--) {
- while (peekMaybeAS(0).getPrecedence() == level) {
- int prevPositionStart = ctx.getTokenLocation().getBegin();
- int prevPositionEnd = ctx.getTokenLocation().getEnd();
- Token token = nextMaybeAS();
- int tokenOffset = ctx.getTokenLocation().getBegin();
- if (lastResult instanceof DartSuperExpression
- && (token == Token.AND || token == Token.OR)) {
- reportErrorAtPosition(prevPositionStart, prevPositionEnd,
- ParserErrorCode.SUPER_IS_NOT_VALID_AS_A_BOOLEAN_OPERAND);
- }
- if (token == Token.EQ_STRICT) {
- reportError(tokenOffset, ParserErrorCode.DEPRECATED_STRICT_EQ);
- }
- if (token == Token.NE_STRICT) {
- reportError(tokenOffset, ParserErrorCode.DEPRECATED_STRICT_NE);
- }
- DartExpression right;
- if (token == Token.IS) {
- beginTypeExpression();
- if (optional(Token.NOT)) {
- int notOffset = ctx.getTokenLocation().getBegin();
- beginTypeExpression();
- DartTypeExpression typeExpression = done(new DartTypeExpression(parseTypeAnnotation()));
- right = done(new DartUnaryExpression(Token.NOT, notOffset, typeExpression, true));
- } else {
- right = done(new DartTypeExpression(parseTypeAnnotation()));
- }
- } else if (token == Token.AS) {
- beginTypeExpression();
- right = done(new DartTypeExpression(parseTypeAnnotation()));
- } else {
- right = parseBinaryExpression(level + 1);
- }
- if (right instanceof DartSuperExpression) {
- reportError(position(), ParserErrorCode.SUPER_CANNOT_BE_USED_AS_THE_SECOND_OPERAND);
- }
-
- lastResult = right;
- result = doneWithoutConsuming(new DartBinaryExpression(token, tokenOffset, result, right));
- if (token == Token.IS
- || token == Token.AS
- || token.isRelationalOperator()
- || token.isEqualityOperator()) {
- // The operations cannot be chained.
- if (peekMaybeAS(0) == token) {
- reportError(position(), ParserErrorCode.INVALID_OPERATOR_CHAINING,
- token.toString().toLowerCase());
- }
- break;
- }
- }
- }
- done(null);
- return result;
- }
-
- /**
- * Use this method where token "as" is expected to be used as built-in identifier.
- *
- * @return the {@link Token} at given position or {@link Token#AS}.
- */
- private Token peekMaybeAS(int n) {
- Token token = ctx.peek(n);
- String tokenString = ctx.peekTokenString(n);
- if (token == Token.IDENTIFIER && "as".equals(tokenString)) {
- return Token.AS;
- }
- return token;
- }
-
- /**
- * Use this method where token "as" is expected to be used as built-in identifier.
- *
- * @return the current {@link Token} or {@link Token#AS}.
- */
- private Token nextMaybeAS() {
- ctx.advance();
- Token token = ctx.getCurrentToken();
- String tokenString = ctx.getTokenString();
- if (token == Token.IDENTIFIER && "as".equals(tokenString)) {
- return Token.AS;
- }
- return token;
- }
-
- /**
- * Parse the arguments passed to a function or method invocation.
- *
- * <pre>
- * arguments
- * : '(' argumentList? ')'
- * ;
- *
- * argumentList
- * : expression (',' expression)* (',' spreadArgument)?
- * | spreadArgument
- * ;
- *
- * spreadArgument
- * : '...' expression
- * ;
- * </pre>
- *
- * @return a list of expressions containing the arguments to be passed
- */
- @Terminals(tokens={Token.RPAREN, Token.COMMA})
- public List<DartExpression> parseArguments() {
- List<DartExpression> arguments = new ArrayList<DartExpression>();
- expect(Token.LPAREN);
- // SEMICOLON is for error recovery
- boolean namedArgumentParsed = false;
- outer: while (!match(Token.RPAREN) && !match(Token.EOS) && !match(Token.SEMICOLON)) {
- beginParameter();
- // parse argument, may be named
- DartExpression expression;
- if (peek(1) == Token.COLON) {
- DartIdentifier name = parseIdentifier();
- expect(Token.COLON);
- expression = new DartNamedExpression(name, parseExpression());
- namedArgumentParsed = true;
- } else {
- expression = parseExpression();
- if (namedArgumentParsed) {
- reportError(expression, ParserErrorCode.POSITIONAL_AFTER_NAMED_ARGUMENT);
- }
- }
- done(expression);
- // add argument, if parsed successfully
- if (expression != null) {
- arguments.add(expression);
- }
- // do we have more arguments?
- switch(peek(0)) {
- // Must keep in sync with @Terminals above
- case COMMA:
- if (peek(-1) == Token.COMMA) {
- reportErrorWithoutAdvancing(ParserErrorCode.EXPECTED_EXPRESSION_AFTER_COMMA);
- }
- consume(Token.COMMA);
- break;
- // Must keep in sync with @Terminals above
- case RPAREN:
- break;
- default:
- Token actual = peek(0);
- Set<Token> terminals = collectTerminalAnnotations();
- if (terminals.contains(actual) || looksLikeTopLevelKeyword()) {
- // Looks like a method already on the stack could use this token.
- reportErrorWithoutAdvancing(ParserErrorCode.EXPECTED_COMMA_OR_RIGHT_PAREN);
- break outer;
- } else {
- // Advance the parser state if no other method on the stack can use this token.
- ctx.advance();
- }
- reportError(ctx.getTokenLocation().getEnd(),
- ParserErrorCode.EXPECTED_COMMA_OR_RIGHT_PAREN, actual);
- break;
- }
- }
- if (peek(-1) == Token.COMMA) {
- reportErrorWithoutAdvancing(ParserErrorCode.EXPECTED_EXPRESSION_AFTER_COMMA);
- }
- expectCloseParen();
- return arguments;
- }
-
- /**
- * Parse a conditional expression.
- *
- * <pre>
- * conditionalExpression
- * : logicalOrExpression ('?' expression ':' expression)?
- * ;
- * </pre>
- *
- * @return an expression matching the {@code conditionalExpression} production
- */
- private DartExpression parseConditionalExpression() {
- beginConditionalExpression();
- DartExpression result = parseBinaryExpression(4);
- if (result instanceof DartSuperExpression) {
- reportError(position(), ParserErrorCode.SUPER_IS_NOT_VALID_ALONE_OR_AS_A_BOOLEAN_OPERAND);
- }
- if (peek(0) != Token.CONDITIONAL) {
- return done(result);
- }
- consume(Token.CONDITIONAL);
- DartExpression yes = parseExpressionWithoutCascade();
- expect(Token.COLON);
- DartExpression no = parseExpressionWithoutCascade();
- return done(new DartConditional(result, yes, no));
- }
-
- private boolean looksLikeStringInterpolation() {
- int peekAhead = 0;
- while (true) {
- switch (peek(peekAhead++)) {
- case STRING:
- break;
- case STRING_SEGMENT:
- case STRING_LAST_SEGMENT:
- case STRING_EMBED_EXP_START:
- case STRING_EMBED_EXP_END:
- return true;
- default:
- return false;
- }
- }
- }
- /**
- * Pastes together adjacent strings. Re-uses the StringInterpolation
- * node if there is more than one adjacent string.
- */
- private DartExpression parseStringWithPasting() {
- List<DartExpression> expressions = new ArrayList<DartExpression>();
- if (looksLikeStringInterpolation()) {
- beginStringInterpolation();
- } else {
- beginLiteral();
- }
- DartExpression result = null;
- boolean foundStringInterpolation = false;
- do {
- result = null;
- switch(peek(0)) {
- case STRING:
- case STRING_SEGMENT:
- case STRING_EMBED_EXP_START:
- // another string is coming, glue it together.
- result = parseString();
- if (result != null) {
- expressions.add(result);
- }
- if (result instanceof DartStringInterpolation) {
- foundStringInterpolation = true;
- }
- break;
- }
- } while (result != null);
-
- if (expressions.size() == 0) {
- return doneWithoutConsuming(null);
- } else if (expressions.size() == 1) {
- return done(expressions.get(0));
- }
-
- if (foundStringInterpolation) {
- DartStringInterpolationBuilder builder = new DartStringInterpolationBuilder();
- // Create a new DartStringInterpolation object from the expressions.
- boolean first = true;
- for (DartExpression expr : expressions) {
- if (!first) {
- // pad between interpolations with a dummy expression
- builder.addExpression(DartStringLiteral.get(""));
- }
- if (expr instanceof DartStringInterpolation) {
- builder.addInterpolation((DartStringInterpolation)expr);
- } else if (expr instanceof DartStringLiteral) {
- builder.addString((DartStringLiteral)expr);
- } else {
- throw new InternalCompilerException("Expected String or StringInterpolation");
- }
- first = false;
- }
- return done(builder.buildInterpolation());
- }
-
- // Synthesize a single String literal
- List<DartStringLiteral> stringParts = new ArrayList<DartStringLiteral>();
- StringBuilder builder = new StringBuilder();
- for (DartExpression expr : expressions) {
- DartStringLiteral stringPart = (DartStringLiteral)expr;
- stringParts.add(stringPart);
- builder.append(stringPart.getValue());
- }
- return done(DartStringLiteral.get(builder.toString(), stringParts));
- }
-
- private DartExpression parseString() {
- switch(peek(0)) {
- case STRING: {
- beginLiteral();
- consume(Token.STRING);
- return done(DartStringLiteral.get(ctx.getTokenString()));
- }
-
- case STRING_SEGMENT:
- case STRING_EMBED_EXP_START:
- return parseStringInterpolation();
-
- default:
- DartExpression expression = parseExpression();
- reportError(position(), ParserErrorCode.EXPECTED_STRING_LITERAL);
- return expression;
- }
- }
-
- private int skipStringLiteral(int offset) {
- Token token = peek(offset);
- while (token == Token.STRING || token == Token.STRING_SEGMENT || token == Token.STRING_EMBED_EXP_START) {
- switch(token) {
- case STRING:
- offset = offset + 1;
-
- case STRING_SEGMENT:
- case STRING_EMBED_EXP_START:
- offset = skipStringInterpolation(offset);
- }
- token = peek(offset);
- }
- return offset;
- }
-
- private int skipStringInterpolation(int offset) {
- Token token = peek(offset);
- if (token == Token.STRING_LAST_SEGMENT) {
- return -1;
- }
- boolean inString = true;
- while (inString) { // Iterate until we find the last string segment.
- switch (token) {
- case STRING_SEGMENT:
- offset = offset + 1;
- token = peek(offset);
- break;
- case STRING_LAST_SEGMENT:
- offset = offset + 1;
- token = peek(offset);
- inString = false;
- break;
- case STRING_EMBED_EXP_START: {
- offset = offset + 1;
- token = peek(offset);
- while (token != Token.EOS && token != Token.STRING_EMBED_EXP_END && token != Token.STRING_LAST_SEGMENT) {
- if (token == Token.STRING || token == Token.STRING_SEGMENT || token == Token.STRING_EMBED_EXP_START) {
- offset = skipStringLiteral(offset);
- } else {
- offset = offset + 1;
- }
- token = peek(offset);
- }
- if (token != Token.STRING_EMBED_EXP_END) {
- inString = Token.STRING_LAST_SEGMENT != token;
- }
- break;
- }
- default:
- inString = false;
- break;
- }
- }
- return offset;
- }
-
- private DartStringLiteral parseUri() {
- DartExpression str = parseStringWithPasting();
- if (str instanceof DartStringLiteral) {
- return (DartStringLiteral) str;
- } else if (str != null) {
- reportError(str, ParserErrorCode.URI_CANNOT_USE_INTERPOLATION);
- DartStringLiteral result = DartStringLiteral.get("<invalid-uri>");
- result.setSourceInfo(str.getSourceInfo());
- return result;
- } else {
- expect(Token.STRING);
- return DartStringLiteral.get(null);
- }
- }
-
- /**
- * Instances of the class {@code DepthCounter} represent the number of less than tokens that have
- * not yet been matched.
- */
- private static class DepthCounter {
- /**
- * The number of less than tokens that have not yet been matched.
- */
- private int count = 0;
-
- /**
- * Increment the number of less than tokens that have not yet been matched by the given amount
- * (or decrement the count if the argument is negative).
- *
- * @param value the amount by which the count should be changed
- * @return the count after it has been modified
- */
- public int add(int value) {
- count += value;
- return count;
- }
-
- /**
- * Return the number of less than tokens that have not yet been matched.
- *
- * @return the number of less than tokens that have not yet been matched
- */
- public int getCount() {
- return count;
- }
- }
-
- /**
- * Return the offset of the first token after a type name, or {@code -1} if the token at the given
- * offset is not the start of a type name.
- *
- * @param offset the offset of the first token of the type name
- * @return the offset of the first token after a type name
- */
- private int skipTypeName(int offset) {
- return skipTypeName(offset, new DepthCounter());
- }
-
- /**
- * Return the offset of the first token after a type name, or {@code -1} if the token at the given
- * offset is not the start of a type name.
- *
- * @param offset the offset of the first token of the type name
- * @param depth the number of less-thans that have been encountered since the outer-most type name
- * @return the offset of the first token after a type name
- */
- private int skipTypeArguments(int offset, DepthCounter depth) {
- if (peek(offset) != Token.LT) {
- return -1;
- }
- int oldDepth = depth.add(1);
- offset = skipTypeName(offset + 1, depth);
- if (offset < 0) {
- return offset;
- }
- while (peek(offset) == Token.COMMA) {
- offset = skipTypeName(offset + 1, depth);
- if (offset < 0) {
- return offset;
- }
- }
- if (depth.getCount() < oldDepth) {
- // We already passed the closing '>' for this list of type arguments
- return offset;
- }
- if (peek(offset) == Token.GT) {
- depth.add(-1);
- return offset + 1;
- } else if (peek(offset) == Token.SAR) {
- depth.add(-2);
- return offset + 1;
- }
- return -1;
- }
-
- /**
- * Return the offset of the first token after a type name, or {@code -1} if the token at the given
- * offset is not the start of a type name.
- *
- * @param offset the offset of the first token of the type name
- * @param depth the number of less-thans that have been encountered since the outer-most type name
- * @return the offset of the first token after a type name
- */
- private int skipTypeName(int offset, DepthCounter depth) {
- if (peek(offset) != Token.IDENTIFIER) {
- return -1;
- }
- offset++;
- if (peek(offset) == Token.PERIOD) {
- offset++;
- if (peek(offset) == Token.IDENTIFIER) {
- // We tolerate a missing identifier in order to recover better
- offset++;
- }
- }
- if (peek(offset) == Token.LT) {
- offset = skipTypeArguments(offset, depth);
- }
- return offset;
- }
-
- /**
- * Parse any literal that is not a function literal (those have already been
- * handled before this method is called, so we don't need to handle them
- * here).
- *
- * <pre>
- * nonFunctionLiteral
- * : NULL
- * | TRUE
- * | FALSE
- * | HEX_NUMBER
- * | RATIONAL_NUMBER
- * | DOUBLE_NUMBER
- * | STRING
- * | mapLiteral
- * | arrayLiteral
- * ;
- * </pre>
- *
- * @return an expression matching the {@code literal} production above
- */
- private DartExpression parseLiteral() {
- beginLiteral();
- if (PSEUDO_KEYWORDS_SET.contains(peek(0).getSyntax())) {
- return done(parseIdentifier());
- }
- switch (peek(0)) {
- case NULL_LITERAL: {
- consume(Token.NULL_LITERAL);
- return done(DartNullLiteral.get());
- }
-
- case TRUE_LITERAL: {
- consume(Token.TRUE_LITERAL);
- return done(DartBooleanLiteral.get(true));
- }
-
- case FALSE_LITERAL: {
- consume(Token.FALSE_LITERAL);
- return done(DartBooleanLiteral.get(false));
- }
-
- case INTEGER_LITERAL: {
- consume(Token.INTEGER_LITERAL);
- String number = ctx.getTokenString();
- return done(DartIntegerLiteral.get(new BigInteger(number)));
- }
-
- case DOUBLE_LITERAL: {
- consume(Token.DOUBLE_LITERAL);
- String number = ctx.getTokenString();
- return done(DartDoubleLiteral.get(Double.parseDouble(number)));
- }
-
- case HEX_LITERAL: {
- consume(Token.HEX_LITERAL);
- String number = ctx.getTokenString();
- return done(DartIntegerLiteral.get(new BigInteger(number, 16)));
- }
-
- case LBRACE: {
- return done(parseMapLiteral(false, null));
- }
-
- case INDEX: {
- expect(peek(0));
- return done(new DartArrayLiteral(false, null, new ArrayList<DartExpression>()));
- }
-
- case LBRACK: {
- return done(parseArrayLiteral(false, null));
- }
-
- case VOID:
- // For better error recovery / code completion in the IDE, treat "void" as an identifier
- // here and let it get reported as a resolution error.
- case IDENTIFIER: {
- return done(parseIdentifier());
- }
-
- case SEMICOLON: {
- // this is separate from the default case for better error recovery,
- // leaving the semicolon for the caller to use for a statement boundary
-
- // we have to advance to get the proper position, but we want to leave
- // the semicolon
- startLookahead();
- next();
- reportUnexpectedToken(position(), null, Token.SEMICOLON);
- rollback();
- return done(new DartSyntheticErrorExpression(""));
- }
-
- default: {
- Token unexpected = peek(0);
- String unexpectedString = ctx.getTokenString();
- if (unexpectedString == null && unexpected != Token.EOS) {
- unexpectedString = unexpected.getSyntax();
- }
-
- // Don't eat tokens that could be used to successfully terminate a non-terminal
- // further up the stack.
- Set<Token> terminals = collectTerminalAnnotations();
- if (!looksLikeTopLevelKeyword() && !terminals.contains(unexpected)) {
- next();
- }
- reportUnexpectedToken(position(), null, unexpected);
- StringBuilder tokenStr = new StringBuilder();
- if (unexpectedString != null) {
- tokenStr.append(unexpectedString);
- }
- // TODO(jat): should we eat additional tokens here for error recovery?
- return done(new DartSyntheticErrorExpression(tokenStr.toString()));
- }
- }
- }
-
- /**
- * mapLiteralEntry
- * : STRING ':' expression
- * ;
- */
- private DartMapLiteralEntry parseMapLiteralEntry() {
- beginMapLiteralEntry();
- // Parse the key.
- DartExpression keyExpr = parseStringWithPasting();
- if (keyExpr == null) {
- return done(null);
- }
- // Parse the value.
- DartExpression value;
- if (expect(Token.COLON)) {
- value = parseExpression();
- } else {
- value = doneWithoutConsuming(new DartSyntheticErrorExpression());
- }
- return done(new DartMapLiteralEntry(keyExpr, value));
- }
- private boolean looksLikeString() {
- switch(peek(0)) {
- case STRING:
- case STRING_SEGMENT:
- case STRING_EMBED_EXP_START:
- return true;
- }
- return false;
- }
-
- /**
- * <pre> mapLiteral : '{' (mapLiteralEntry (',' mapLiteralEntry)* ','?)? '}' ;
- * </pre>
- */
- @Terminals(tokens={Token.RBRACE, Token.COMMA})
- private DartExpression parseMapLiteral(boolean isConst, List<DartTypeNode> typeArguments) {
- beginMapLiteral();
- boolean foundOpenBrace = expect(Token.LBRACE);
- boolean save = setAllowFunctionExpression(true);
- List<DartMapLiteralEntry> entries = new ArrayList<DartMapLiteralEntry>();
-
- while (!match(Token.RBRACE) && !match(Token.EOS)) {
- if (!looksLikeString()) {
- ctx.advance();
- reportError(position(), ParserErrorCode.EXPECTED_STRING_LITERAL_MAP_ENTRY_KEY);
- if (peek(0) == Token.COMMA) {
- // a common error is to put an empty entry in the list, allow it to
- // recover.
- continue;
- } else {
- break;
- }
- }
- DartMapLiteralEntry entry = parseMapLiteralEntry();
- if (entry != null) {
- entries.add(entry);
- }
- Token nextToken = peek(0);
- switch (nextToken) {
- // Must keep in sync with @Terminals above
- case COMMA:
- consume(Token.COMMA);
- break;
- // Must keep in sync with @Terminals above
- case RBRACE:
- break;
- default:
- if (entry == null) {
- Set<Token> terminals = collectTerminalAnnotations();
- if (!terminals.contains(nextToken) && !looksLikeTopLevelKeyword()) {
- if (entry == null) {
- // Ensure the parser makes progress.
- ctx.advance();
- }
- }
- }
- reportError(position(), ParserErrorCode.EXPECTED_COMMA_OR_RIGHT_BRACE);
- break;
- }
- }
-
- expectCloseBrace(foundOpenBrace);
- setAllowFunctionExpression(save);
- return done(new DartMapLiteral(isConst, typeArguments, entries));
- }
-
- /**
- * // The array literal syntax doesn't allow elided elements, unlike
- * // in ECMAScript.
- *
- * <pre>
- * arrayLiteral
- * : '[' expressionList? ']'
- * ;
- * </pre>
- */
- @Terminals(tokens={Token.RBRACK, Token.COMMA})
- private DartExpression parseArrayLiteral(boolean isConst, List<DartTypeNode> typeArguments) {
- beginArrayLiteral();
- expect(Token.LBRACK);
- boolean save = setAllowFunctionExpression(true);
- List<DartExpression> exprs = new ArrayList<DartExpression>();
- while (!match(Token.RBRACK) && !EOS()) {
- exprs.add(parseExpression());
- // Must keep in sync with @Terminals above
- if (!optional(Token.COMMA)) {
- break;
- }
- }
- // Must keep in sync with @Terminals above
- expect(Token.RBRACK);
- setAllowFunctionExpression(save);
- return done(new DartArrayLiteral(isConst, typeArguments, exprs));
- }
-
- /**
- * Parse a postfix expression.
- *
- * <pre>
- * postfixExpression
- * | assignableExpression postfixOperator
- * : primary selector*
- * ;
- * </pre>
- *
- * @return an expression matching the {@code postfixExpression} production above
- */
- private DartExpression parsePostfixExpression() {
- beginPostfixExpression();
- DartExpression receiver = doneWithoutConsuming(parsePrimaryExpression());
- DartExpression result = receiver;
- do {
- receiver = result;
- result = doneWithoutConsuming(parseSelectorExpression(receiver));
- } while (receiver != result);
-
- Token token = peek(0);
- if (token.isCountOperator()) {
- ensureAssignable(result);
- consume(token);
- int tokenOffset = ctx.getTokenLocation().getBegin();
- result = doneWithoutConsuming(new DartUnaryExpression(token, tokenOffset, result, false));
- }
-
- return done(result);
- }
-
- /**
- * <pre>
- * typeParameters? (arrayLiteral | mapLiteral)
- * </pre>
- *
- * @param isConst <code>true</code> if a CONST expression
- *
- */
- private DartExpression tryParseTypedCompoundLiteral(boolean isConst) {
- beginLiteral();
- List<DartTypeNode> typeArguments = parseTypeArgumentsOpt();
- switch (peek(0)) {
- case INDEX:
- beginArrayLiteral();
- consume(Token.INDEX);
- return done(done(new DartArrayLiteral(isConst, typeArguments, new ArrayList<DartExpression>())));
- case LBRACK:
- return done(parseArrayLiteral(isConst, typeArguments));
- case LBRACE:
- return done(parseMapLiteral(isConst, typeArguments));
- default:
- if (typeArguments != null) {
- rollback();
- return null;
- }
-
- }
- // Doesn't look like a typed compound literal and no tokens consumed.
- return done(null);
- }
-
- private enum LastSeenNode {
- NONE,
- STRING,
- EXPRESSION;
- }
-
- private class DartStringInterpolationBuilder {
-
- private final List<DartStringLiteral> strings = new ArrayList<DartStringLiteral>();
- private final List<DartExpression> expressions = new ArrayList<DartExpression>();
- private LastSeenNode lastSeen = LastSeenNode.NONE;
-
- DartStringInterpolationBuilder() {
- }
-
- void addString(DartStringLiteral string) {
- if (lastSeen == LastSeenNode.STRING) {
- expressions.add(new DartSyntheticErrorExpression());
- }
- strings.add(string);
- lastSeen = LastSeenNode.STRING;
- }
-
- void addExpression(DartExpression expression) {
- switch (lastSeen) {
- case EXPRESSION:
- case NONE:
- strings.add(DartStringLiteral.get(""));
- break;
- default:
- break;
- }
- expressions.add(expression);
- lastSeen = LastSeenNode.EXPRESSION;
- }
-
- void addInterpolation(DartStringInterpolation interpolation) {
- strings.addAll(interpolation.getStrings());
- expressions.addAll(interpolation.getExpressions());
- lastSeen = LastSeenNode.STRING;
- }
-
- DartStringInterpolation buildInterpolation() {
- if (strings.size() == expressions.size()) {
- strings.add(DartStringLiteral.get(""));
- }
- return new DartStringInterpolation(strings, expressions);
- }
- }
-
- /**
- * Instances of the class {@code StringInterpolationParseError} represent the detection of an
- * error that needs to be handled in an enclosing context.
- */
- private static class StringInterpolationParseError extends RuntimeException {
- private static final long serialVersionUID = 1L;
-
- public StringInterpolationParseError() {
- super();
- }
- }
-
- /**
- * <pre>
- * string-interpolation
- * : (STRING_SEGMENT? embedded-exp?)* STRING_LAST_SEGMENT
- *
- * embedded-exp
- * : STRING_EMBED_EXP_START expression STRING_EMBED_EXP_END
- * </pre>
- */
- private DartExpression parseStringInterpolation() {
- // TODO(sigmund): generalize to parse string templates as well.
- if (peek(0) == Token.STRING_LAST_SEGMENT) {
- throw new InternalCompilerException("Invariant broken");
- }
- beginStringInterpolation();
- DartStringInterpolationBuilder builder = new DartStringInterpolationBuilder();
- boolean inString = true;
- while (inString) { // Iterate until we find the last string segment.
- switch (peek(0)) {
- case STRING_SEGMENT: {
- beginStringSegment();
- consume(Token.STRING_SEGMENT);
- builder.addString(done(DartStringLiteral.get(ctx.getTokenString())));
- break;
- }
- case STRING_LAST_SEGMENT: {
- beginStringSegment();
- consume(Token.STRING_LAST_SEGMENT);
- builder.addString(done(DartStringLiteral.get(ctx.getTokenString())));
- inString = false;
- break;
- }
- case STRING_EMBED_EXP_START: {
- consume(Token.STRING_EMBED_EXP_START);
- /*
- * We check for ILLEGAL specifically here to give nicer error
- * messages, and because the scanner doesn't generate a
- * STRING_EMBED_EXP_END to match the START in the case of an ILLEGAL
- * token.
- */
- if (peek(0) == Token.ILLEGAL) {
- reportError(position(), ParserErrorCode.UNEXPECTED_TOKEN_IN_STRING_INTERPOLATION,
- next());
- builder.addExpression(new DartSyntheticErrorExpression(""));
- break;
- } else {
- try {
- builder.addExpression(parseExpression());
- } catch (StringInterpolationParseError exception) {
- if (peek(0) == Token.STRING_LAST_SEGMENT) {
- break;
- }
- throw new InternalCompilerException("Invalid expression found in string interpolation");
- }
- }
- Token lookAhead = peek(0);
- String lookAheadString = getPeekTokenValue(0);
- if (!expect(Token.STRING_EMBED_EXP_END)) {
- String errorText = null;
- if (lookAheadString != null && lookAheadString.length() > 0) {
- errorText = lookAheadString;
- } else if (lookAhead.getSyntax() != null && lookAhead.getSyntax().length() > 0) {
- errorText = lookAhead.getSyntax();
- }
- if (errorText != null) {
- builder.addExpression(new DartSyntheticErrorExpression(errorText));
- }
- inString = !(Token.STRING_LAST_SEGMENT == lookAhead);
- }
- break;
- }
- case EOS: {
- reportError(position(), ParserErrorCode.INCOMPLETE_STRING_LITERAL);
- inString = false;
- break;
- }
- default: {
- String errorText = getPeekTokenValue(0) != null && getPeekTokenValue(0).length() > 0
- ? getPeekTokenValue(0) : null;
- if(errorText != null) {
- builder.addExpression(new DartSyntheticErrorExpression(getPeekTokenValue(0)));
- }
- reportError(position(), ParserErrorCode.UNEXPECTED_TOKEN_IN_STRING_INTERPOLATION,
- next());
- break;
- }
- }
- }
- return done(builder.buildInterpolation());
- }
-
- /**
- * Parse a return type, giving an error if the .
- *
- * @return a return type or null if the current text is not a return type
- */
- private DartTypeNode parseReturnType() {
- if (peek(0) == Token.VOID) {
- return parseVoidType();
- } else {
- return parseTypeAnnotation();
- }
- }
-
- /**
- * Check if the current text could be a return type, and advance past it if so. The current
- * position is unchanged if it is not a return type.
- *
- * NOTE: if the grammar is changed for what constitutes an acceptable return type, this method
- * must be updated to match {@link #parseReturnType()}/etc.
- *
- * @return true if current text could be a return type, false otherwise
- */
- private boolean isReturnType() {
- beginReturnType();
- if (optional(Token.VOID)) {
- done(null);
- return true;
- }
- if (!optional(Token.IDENTIFIER)) {
- rollback();
- return false;
- }
- // handle prefixed identifiers
- if (optional(Token.PERIOD)) {
- if (!optional(Token.IDENTIFIER)) {
- rollback();
- return false;
- }
- }
- // skip over type arguments if they are present
- if (optional(Token.LT)) {
- int count = 1;
- while (count > 0) {
- switch (next()) {
- case EOS:
- rollback();
- return false;
- case LT:
- count++;
- break;
- case GT:
- count--;
- break;
- case SHL:
- count += 2;
- break;
- case SAR: // >>
- count -= 2;
- break;
- case COMMA:
- case IDENTIFIER:
- // extends is a pseudokeyword, so shows up as IDENTIFIER
- break;
- default:
- rollback();
- return false;
- }
- }
- if (count < 0) {
- // if we had too many > (which can only be >> or >>>), can't be a return type
- rollback();
- return false;
- }
- }
- done(null);
- return true;
- }
-
- /**
- * Checks to see if the current text looks like a function expression:
- *
- * <pre>
- * FUNCTION name? ( args ) < => | { >
- * returnType name? ( args ) < => | { >
- * name? ( args ) < => | { >
- * </pre>
- *
- * The current position is unchanged on return.
- *
- * NOTE: if the grammar for function expressions changes, this method must be
- * adapted to match the actual parsing code. It is acceptable for this method
- * to return true when the source text does not actually represent a function
- * expression (which would result in error messages assuming it was a function
- * expression, but it must not do so when the source text would be correct if
- * parsed as a non-function expression.
- *
- * @return true if the current text looks like a function expression, false
- * otherwise
- */
- @VisibleForTesting
- boolean looksLikeFunctionExpression() {
- if (!allowFunctionExpression) {
- return false;
- }
- return looksLikeFunctionDeclarationOrExpression();
- }
-
- /**
- * Check to see if the following tokens could be a function expression, and if so try and parse
- * it as one.
- *
- * @return a function expression if found, or null (with no tokens consumed) if not
- */
- private DartExpression parseFunctionExpressionWithReturnType() {
- beginFunctionLiteral();
- DartIdentifier[] namePtr = new DartIdentifier[1];
- DartFunction function = parseFunctionDeclarationOrExpression(namePtr, false);
- if (function == null) {
- rollback();
- return null;
- }
- if (function != null && function.getReturnTypeNode() != null) {
- reportError(function.getReturnTypeNode(), ParserErrorCode.DEPRECATED_FUNCTION_LITERAL);
- } else if (namePtr[0] != null) {
- reportError(namePtr[0], ParserErrorCode.DEPRECATED_FUNCTION_LITERAL);
- }
- return done(new DartFunctionExpression(namePtr[0], doneWithoutConsuming(function), false));
- }
-
- /**
- * Parse a function declaration or expression, including the body.
- * <pre>
- * ... | functionDeclaration functionBody
- *
- * functionDeclaration
- * : returnType? identifier formalParameterList
- * ;
- *
- * functionExpression
- * : (returnType? identifier)? formalParameterList functionExpressionBody
- * ;
- *
- * functionBody
- * : '=>' expression ';'
- * | block
- * ;
- *
- * functionExpressionBody
- * : '=>' expression
- * | block
- * ;
- * </pre>
- *
- * @param namePtr out parameter - parsed function name stored in namePtr[0]
- * @param isDeclaration true if this is a declaration (i.e. a name is required and a trailing
- * semicolon is needed for arrow syntax
- * @return a {@link DartFunction} containing the body of the function, or null
- * if the next tokens cannot be parsed as a function declaration or expression
- */
- private DartFunction parseFunctionDeclarationOrExpression(DartIdentifier[] namePtr,
- boolean isDeclaration) {
- DartTypeNode returnType = null;
- namePtr[0] = null;
- if (optionalPseudoKeyword(STATIC_KEYWORD)) {
- reportError(position(), ParserErrorCode.LOCAL_CANNOT_BE_STATIC);
- }
- switch (peek(0)) {
- case LPAREN:
- // no type or name, just the formal parameter list
- break;
- case IDENTIFIER:
- if (peek(1) == Token.LPAREN) {
- // if there is only one identifier, it must be the name
- namePtr[0] = parseIdentifier();
- break;
- }
- //$FALL-THROUGH$
- case VOID:
- returnType = parseReturnType();
- if (peek(0) == Token.IDENTIFIER) {
- namePtr[0] = parseIdentifier();
- }
- break;
- default:
- return null;
- }
- FormalParameters params = parseFormalParameterList();
- int parametersCloseParen = ctx.getTokenLocation().getBegin();
- DartBlock body = parseFunctionStatementBody(true, isDeclaration);
- DartFunction function = new DartFunction(params.val, params.openParen,
- params.optionalOpenOffset, params.optionalCloseOffset, parametersCloseParen, body,
- returnType);
- doneWithoutConsuming(function);
- return function;
- }
-
- /**
- * Parse a primary expression.
- *
- * <pre>
- * primary
- * : THIS
- * | SUPER assignableSelector
- * | literal
- * | identifier
- * | NEW type ('.' identifier)? arguments
- * | typeArguments? (arrayLiteral | mapLiteral)
- * | CONST typeArguments? (arrayLiteral | mapLiteral)
- * | CONST typeArguments? (arrayLiteral | mapLiteral)
- * | CONST type ('.' identifier)? arguments
- * | '(' expression ')'
- * | string-interpolation
- * | functionExpression
- * ;
- * </pre>
- *
- * @return an expression matching the {@code primary} production above
- */
- private DartExpression parsePrimaryExpression() {
- if (looksLikeFunctionExpression()) {
- return parseFunctionExpressionWithReturnType();
- }
- switch (peek(0)) {
- case THIS: {
- beginThisExpression();
- consume(Token.THIS);
- return done(DartThisExpression.get());
- }
-
- case SUPER: {
- beginSuperExpression();
- consume(Token.SUPER);
- return done(DartSuperExpression.get());
- }
-
- case NEW: {
- beginNewExpression(); // DartNewExpression
- consume(Token.NEW);
- return done(parseConstructorInvocation(false));
- }
-
- case CONST: {
- beginConstExpression();
- consume(Token.CONST);
-
- DartExpression literal = tryParseTypedCompoundLiteral(true);
- if (literal != null) {
- return done(literal);
- }
- return done(parseConstructorInvocation(true));
- }
-
- case LPAREN: {
- beginParenthesizedExpression();
- consume(Token.LPAREN);
- beginExpression();
- // inside parens, function blocks are allowed again
- boolean save = setAllowFunctionExpression(true);
- DartExpression expression = done(parseExpression());
- setAllowFunctionExpression(save);
- expectCloseParen();
- return done(new DartParenthesizedExpression(expression));
- }
-
- case LT: {
- beginLiteral();
- DartExpression literal = tryParseTypedCompoundLiteral(false);
- if (literal == null) {
- reportError(position(), ParserErrorCode.EXPECTED_ARRAY_OR_MAP_LITERAL);
- }
- return done(literal);
- }
-
- case STRING:
- case STRING_SEGMENT:
- case STRING_EMBED_EXP_START: {
- return parseStringWithPasting();
- }
-
- case STRING_LAST_SEGMENT:
- throw new StringInterpolationParseError();
-
- case CONDITIONAL:
- return parseArgumentDefinitionTest();
-
- default: {
- return parseLiteral();
- }
- }
- }
-
- private DartExpression parseArgumentDefinitionTest() {
- beginArgumentDefinitionTest();
- int operatorOffset = position();
- expect(Token.CONDITIONAL);
- return done(new DartUnaryExpression(Token.CONDITIONAL, operatorOffset, parseIdentifier(), true));
- }
-
- private DartExpression parseConstructorInvocation(boolean isConst) {
- List<DartTypeNode> parts = new ArrayList<DartTypeNode>();
- beginConstructor();
- do {
- beginConstructorNamePart();
- parts.add(done(new DartTypeNode(parseIdentifier(), parseTypeArgumentsOpt())));
- } while (optional(Token.PERIOD));
- assert parts.size() > 0;
-
- DartNode constructor;
- switch (parts.size()) {
- case 1:
- constructor = doneWithoutConsuming(parts.get(0));
- break;
-
- case 2: {
- // This case is ambiguous. It can either be prefix.Type or
- // Type.namedConstructor.
- boolean hasPrefix = false;
- DartTypeNode part1 = parts.get(0);
- DartTypeNode part2 = parts.get(1);
- if (prefixes.contains(((DartIdentifier) part1.getIdentifier()).getName())) {
- hasPrefix = true;
- }
- if (!part2.getTypeArguments().isEmpty()) {
- // If the second part has type arguments, the first part must be a prefix.
- // If it isn't a prefix, the resolver will complain.
- hasPrefix = true;
- }
- if (hasPrefix) {
- constructor = doneWithoutConsuming(toPrefixedType(parts));
- } else {
- // Named constructor.
- DartIdentifier identifier = (DartIdentifier) part2.getIdentifier();
- constructor = doneWithoutConsuming(new DartPropertyAccess(part1, identifier));
- }
- break;
- }
- default: {
- // This case is unambiguous. It must be prefix.Type.namedConstructor.
- if (parts.size() > 3) {
- reportError(parts.get(3), ParserErrorCode.EXPECTED_LEFT_PAREN);
- }
- DartTypeNode typeNode = doneWithoutConsuming(toPrefixedType(parts));
- DartIdentifier identifier = (DartIdentifier)parts.get(2).getIdentifier();
- constructor = doneWithoutConsuming(new DartPropertyAccess(typeNode, identifier));
- break;
- }
- }
-
- boolean save = setAllowFunctionExpression(true);
- try {
- List<DartExpression> args = parseArguments();
- return done(new DartNewExpression(constructor, args, isConst));
- } finally {
- setAllowFunctionExpression(save);
- }
- }
-
- private DartTypeNode toPrefixedType(List<DartTypeNode> parts) {
- DartIdentifier part1 = (DartIdentifier)parts.get(0).getIdentifier();
- DartTypeNode part2 = parts.get(1);
- DartIdentifier identifier = (DartIdentifier) part2.getIdentifier();
- DartPropertyAccess access = doneWithoutConsuming(new DartPropertyAccess(part1, identifier));
- return new DartTypeNode(access, part2.getTypeArguments());
- }
-
- /**
- * Parse a selector expression.
- *
- * <pre>
- * selector
- * : assignableSelector
- * | arguments
- * ;
- * </pre>
- *
- * @return an expression matching the {@code selector} production above
- */
- private DartExpression parseSelectorExpression(DartExpression receiver) {
- DartExpression expression = tryParseAssignableSelector(receiver);
- if (expression != null) {
- return expression;
- }
-
- if (peek(0) == Token.LPAREN) {
- beginSelectorExpression();
- boolean save = setAllowFunctionExpression(true);
- List<DartExpression> args = parseArguments();
- setAllowFunctionExpression(save);
- if (receiver instanceof DartIdentifier) {
- return(done(new DartUnqualifiedInvocation((DartIdentifier) receiver, args)));
- } else {
- return(done(new DartFunctionObjectInvocation(receiver, args)));
- }
- }
-
- return receiver;
- }
-
- /**
- * <pre>
- * assignableSelector
- * : '[' expression ']'
- * | '.' identifier
- * ;
- * </pre>
- */
- private DartExpression tryParseAssignableSelector(DartExpression receiver) {
- switch (peek(0)) {
- case PERIOD:
- consume(Token.PERIOD);
- switch (peek(0)) {
- case SEMICOLON:
- case RBRACE:
- reportError(position(), ParserErrorCode.EXPECTED_IDENTIFIER);
- DartIdentifier error = doneWithoutConsuming(new DartIdentifier(""));
- return doneWithoutConsuming(new DartPropertyAccess(receiver, error));
- }
- // receiver.() = missing name
- if (peek(0) == Token.LPAREN) {
- reportUnexpectedToken(position(), Token.IDENTIFIER, peek(0));
- DartIdentifier name;
- {
- beginIdentifier();
- name = done(new DartSyntheticErrorIdentifier());
- }
- boolean save = setAllowFunctionExpression(true);
- DartMethodInvocation expr = doneWithoutConsuming(new DartMethodInvocation(receiver,
- false, name, parseArguments()));
- setAllowFunctionExpression(save);
- return expr;
- }
- // expect name
- DartIdentifier name = parseIdentifier();
- if (peek(0) == Token.LPAREN) {
- boolean save = setAllowFunctionExpression(true);
- DartMethodInvocation expr = doneWithoutConsuming(new DartMethodInvocation(receiver, false,
- name, parseArguments()));
- setAllowFunctionExpression(save);
- return expr;
- } else {
- return doneWithoutConsuming(new DartPropertyAccess(receiver, name));
- }
-
- case LBRACK:
- consume(Token.LBRACK);
- DartExpression key = parseExpression();
- expect(Token.RBRACK);
- return doneWithoutConsuming(new DartArrayAccess(receiver, key));
-
- default:
- return null;
- }
- }
-
- /**
- * <pre>
- * block
- * : '{' statements deadCode* '}'
- * ;
- *
- * statements
- * : statement*
- * ;
- *
- * deadCode
- * : (normalCompletingStatement | abruptCompletingStatement)
- * ;
- * </pre>
- */
- @Terminals(tokens={Token.RBRACE})
- private DartBlock parseBlock() {
- if (isDietParse) {
- expect(Token.LBRACE);
- DartBlock emptyBlock = new DartBlock(new ArrayList<DartStatement>());
- int nesting = 1;
- while (nesting > 0) {
- Token token = next();
- switch (token) {
- case LBRACE:
- ++nesting;
- break;
- case RBRACE:
- --nesting;
- break;
- case EOS:
- return emptyBlock;
- }
- }
- // Return an empty block so we don't generate unparseable code.
- return emptyBlock;
- } else {
- Token nextToken = peek(0);
- if (!nextToken.equals(Token.LBRACE)
- && (looksLikeTopLevelKeyword() || nextToken.equals(Token.RBRACE))) {
- beginBlock();
- // Allow recovery back to the top level.
- reportErrorWithoutAdvancing(ParserErrorCode.UNEXPECTED_TOKEN);
- return done(new DartBlock(new ArrayList<DartStatement>()));
- }
- beginBlock();
- List<DartStatement> statements = new ArrayList<DartStatement>();
- boolean foundOpenBrace = expect(Token.LBRACE);
-
- while (!match(Token.RBRACE) && !EOS()) {
- if (looksLikeTopLevelKeyword()) {
- reportErrorWithoutAdvancing(ParserErrorCode.UNEXPECTED_TOKEN);
- break;
- }
- int startPosition = position();
- DartStatement newStatement = parseStatement();
- if (newStatement == null) {
- break;
- }
- if (startPosition == position()) {
- // The parser is not making progress.
- Set<Token> terminals = this.collectTerminalAnnotations();
- if (terminals.contains(peek(0))) {
- // bail out of the block
- break;
- }
- reportUnexpectedToken(position(), null, next());
- }
- statements.add(newStatement);
- }
- expectCloseBrace(foundOpenBrace);
- return done(new DartBlock(statements));
- }
- }
-
- /**
- * Parse a function statement body.
- *
- * <pre>
- * functionStatementBody
- * : '=>' expression ';'
- * | block
- * </pre>
- *
- * @param requireSemicolonForArrow true if a semicolon is required after an arrow expression
- * @return {@link DartBlock} instance containing function body
- */
- private DartBlock parseFunctionStatementBody(boolean allowBody, boolean requireSemicolonForArrow) {
- // A break inside a function body should have nothing to do with a loop in
- // the code surrounding the definition.
- boolean oldInLoopStatement = inLoopStatement;
- boolean oldInCaseStatement = inCaseStatement;
- inLoopStatement = inCaseStatement = false;
- try {
- DartBlock result;
- if (isDietParse) {
- result = dietParseFunctionStatementBody();
- } else {
- beginFunctionStatementBody();
- if (optional(Token.SEMICOLON)) {
- if (allowBody) {
- reportError(position(), ParserErrorCode.EXPECTED_FUNCTION_STATEMENT_BODY);
- }
- result = done(null);
- } else if (optional(Token.ARROW)) {
- DartExpression expr = parseExpression();
- if (expr == null) {
- expr = new DartSyntheticErrorExpression();
- }
- if (requireSemicolonForArrow) {
- expect(Token.SEMICOLON);
- }
- result = done(makeReturnBlock(expr));
- } else {
- result = done(parseBlock());
- }
- }
- if (!allowBody && result != null) {
- reportError(result, ParserErrorCode.EXTERNAL_METHOD_BODY);
- }
- return result;
- } finally {
- inLoopStatement = oldInLoopStatement;
- inCaseStatement = oldInCaseStatement;
- }
- }
-
- private DartBlock dietParseFunctionStatementBody() {
- DartBlock emptyBlock = new DartBlock(new ArrayList<DartStatement>());
- if (optional(Token.ARROW)) {
- while (true) {
- Token token = next();
- if (token == Token.SEMICOLON) {
- break;
- }
- }
- } else {
- if (!peek(0).equals(Token.LBRACE) && looksLikeTopLevelKeyword()) {
- // Allow recovery back to the top level.
- reportErrorWithoutAdvancing(ParserErrorCode.UNEXPECTED_TOKEN);
- return done(emptyBlock);
- }
- expect(Token.LBRACE);
- int nesting = 1;
- while (nesting > 0) {
- Token token = next();
- switch (token) {
- case LBRACE:
- ++nesting;
- break;
- case RBRACE:
- --nesting;
- break;
- case EOS:
- return emptyBlock;
- }
- }
- }
- // Return an empty block so we don't generate unparseable code.
- return emptyBlock;
- }
-
- /**
- * Create a block containing a single return statement.
- *
- * @param returnVal return value expression
- * @return block containing a single return statement
- */
- private DartBlock makeReturnBlock(DartExpression returnVal) {
- return new DartReturnBlock(returnVal);
- }
-
- /**
- * <pre>
- * initializedVariableDeclaration
- * : constVarOrType initializedIdentifierList
- * ;
- *
- * initializedIdentifierList
- * : initializedIdentifier (',' initializedIdentifier)*
- * ;
- *
- * initializedIdentifier
- * : IDENTIFIER ('=' assignmentExpression)?
- * ;
- * </pre>
- */
- private List<DartVariable> parseInitializedVariableList() {
- List<DartVariable> idents = new ArrayList<DartVariable>();
- do {
- beginVariableDeclaration();
- List<DartAnnotation> metadata = parseMetadata();
- DartIdentifier name = parseIdentifier();
- DartExpression value = null;
- if (isParsingInterface) {
- expect(Token.ASSIGN);
- value = parseExpression();
- } else if (optional(Token.ASSIGN)) {
- value = parseExpression();
- }
- DartVariable variable = done(new DartVariable(name, value));
- setMetadata(variable, metadata);
- idents.add(variable);
- } while (optional(Token.COMMA));
-
- return idents;
- }
-
- private DartAssertStatement parseAssertStatement() {
- beginAssertStatement();
- expect(Token.ASSERT);
- expect(Token.LPAREN);
- DartExpression condition = parseExpression();
- expectCloseParen();
- expectStatmentTerminator();
- return done(new DartAssertStatement(condition));
- }
-
- /**
- * <pre>
- * abruptCompletingStatement
- * : BREAK identifier? ';'
- * | CONTINUE identifier? ';'
- * | RETURN expression? ';'
- * | THROW expression? ';'
- * ;
- * </pre>
- */
- private DartBreakStatement parseBreakStatement() {
- beginBreakStatement();
- expect(Token.BREAK);
- DartIdentifier label = null;
- if (match(Token.IDENTIFIER)) {
- label = parseIdentifier();
- } else if (!inLoopStatement && !inCaseStatement) {
- // The validation of matching of labels to break statements is done later.
- reportErrorWithoutAdvancing(ParserErrorCode.BREAK_OUTSIDE_OF_LOOP);
- }
- expectStatmentTerminator();
- return done(new DartBreakStatement(label));
- }
-
- private DartContinueStatement parseContinueStatement() {
- beginContinueStatement();
- expect(Token.CONTINUE);
- DartIdentifier label = null;
- if (!inLoopStatement && !inCaseStatement) {
- reportErrorWithoutAdvancing(ParserErrorCode.CONTINUE_OUTSIDE_OF_LOOP);
- }
- if (peek(0) == Token.IDENTIFIER) {
- label = parseIdentifier();
- } else if (!inLoopStatement && inCaseStatement) {
- reportErrorWithoutAdvancing(ParserErrorCode.CONTINUE_IN_CASE_MUST_HAVE_LABEL);
- }
- expectStatmentTerminator();
- return done(new DartContinueStatement(label));
- }
-
- private DartReturnStatement parseReturnStatement() {
- beginReturnStatement();
- expect(Token.RETURN);
- DartExpression value = null;
- if (peek(0) != Token.SEMICOLON) {
- value = parseExpression();
- }
- expectStatmentTerminator();
- return done(new DartReturnStatement(value));
- }
-
- private DartThrowExpression parseThrowExpression(boolean allowCascade) {
- beginThrowExpression();
- expect(Token.THROW);
- DartExpression exception = null;
- if (peek(0) != Token.SEMICOLON && peek(0) != Token.RPAREN) {
- if (allowCascade) {
- exception = parseExpression();
- } else {
- exception = parseExpressionWithoutCascade();
- }
- }
- return done(new DartThrowExpression(exception));
- }
-
- /**
- * <pre>
- * statement
- * : label* nonLabelledStatement
- * ;
- *
- * label
- * : identifier ':'
- * ;
- * </pre>
- *
- * @return a {@link DartStatement}
- */
- @VisibleForTesting
- public DartStatement parseStatement() {
- List<DartIdentifier> labels = new ArrayList<DartIdentifier>();
- while (peek(0) == Token.IDENTIFIER && peek(1) == Token.COLON) {
- beginLabel();
- labels.add(parseIdentifier());
- expect(Token.COLON);
- }
- List<DartAnnotation> metadata = parseMetadata();
- DartStatement statement = parseNonLabelledStatement();
- if (!metadata.isEmpty() && statement instanceof DartVariableStatement) {
- DartVariableStatement variableStatement = (DartVariableStatement) statement;
- if (!variableStatement.getVariables().isEmpty()) {
- setMetadata(variableStatement.getVariables().get(0), metadata);
- }
- }
- for (int i = labels.size() - 1; i >= 0; i--) {
- statement = done(new DartLabel(labels.get(i), statement));
- }
- return statement;
- }
-
- private boolean isFunctionExpression(DartStatement statement) {
- if (!(statement instanceof DartExprStmt)) {
- return false;
- }
- DartExpression expression = ((DartExprStmt) statement).getExpression();
- if (!(expression instanceof DartFunctionExpression)) {
- return false;
- }
- return ((DartFunctionExpression) expression).getName() == null;
- }
-
- /**
- * <pre>
- * normalCompletingStatement
- * : functionStatement
- * | initializedVariableDeclaration ';'
- * | simpleStatement
- * ;
- *
- * functionStatement
- * : typeOrFunction identifier formalParameterList block
- * ;
- * ;
- *
- * simpleStatement
- * : ('{')=> block // Guard to break tie with map literal.
- * | expression? ';'
- * | tryStatement
- * | ASSERT '(' conditionalExpression ')' ';'
- * | abruptCompletingStatement
- * ;
- * </pre>
- */
- // TODO(zundel): Possibly we could use Token.IDENTIFIER too, but it is used
- // in so many places, it might make recovery worse rather than better.
- @Terminals(tokens={Token.IF, Token.SWITCH, Token.WHILE, Token.DO, Token.FOR,
- Token.VAR, Token.FINAL, Token.CONTINUE, Token.BREAK, Token.RETHROW,
- Token.RETURN, Token.THROW, Token.TRY, Token.SEMICOLON })
- private DartStatement parseNonLabelledStatement() {
- // Try to parse as function declaration.
- if (looksLikeFunctionDeclarationOrExpression()) {
- ctx.begin();
- DartStatement functionDeclaration = parseFunctionDeclaration();
- // If "null", then we tried to parse, but found that this is not function declaration.
- // So, parsing was rolled back and we can try to parse it as expression.
- if (functionDeclaration != null) {
- if (!isFunctionExpression(functionDeclaration)) {
- ctx.done(null);
- return functionDeclaration;
- }
- ctx.rollback();
- } else {
- ctx.done(null);
- }
- }
- // Check possible statement kind.
- switch (peek(0)) {
- case ASSERT:
- return parseAssertStatement();
-
- case IF:
- return parseIfStatement();
-
- case SWITCH:
- return parseSwitchStatement();
-
- case WHILE:
- return parseWhileStatement();
-
- case DO:
- return parseDoWhileStatement();
-
- case FOR:
- return parseForStatement();
-
- case VAR: {
- beginVarDeclaration();
- consume(Token.VAR);
- List<DartVariable> vars = parseInitializedVariableList();
- expectStatmentTerminator();
- return done(new DartVariableStatement(vars, null));
- }
-
- case FINAL: {
- beginFinalDeclaration();
- consume(peek(0));
- DartTypeNode type = null;
- if (peek(1) == Token.IDENTIFIER || peek(1) == Token.LT || peek(1) == Token.PERIOD) {
- // We know we have a type.
- type = parseTypeAnnotation();
- }
- List<DartVariable> vars = parseInitializedVariableList();
- expectStatmentTerminator();
- return done(new DartVariableStatement(vars, type, Modifiers.NONE.makeFinal()));
- }
-
- case LBRACE:
- Token token = peek(1);
- if (token == Token.STRING || token == Token.STRING_SEGMENT || token == Token.STRING_EMBED_EXP_START) {
- int offset = skipStringLiteral(1);
- if (peek(offset) == Token.COLON) {
- DartStatement statement = parseExpressionStatement();
- if (statement instanceof DartExprStmt
- && ((DartExprStmt) statement).getExpression() instanceof DartMapLiteral) {
- reportError(
- ((DartExprStmt) statement).getExpression(),
- ParserErrorCode.NON_CONST_MAP_LITERAL_STATEMENT);
- }
- return statement;
- }
- }
- return parseBlock();
-
- case CONTINUE:
- return parseContinueStatement();
-
- case BREAK:
- return parseBreakStatement();
-
- case RETURN:
- return parseReturnStatement();
-
- case THROW:
- return parseExpressionStatement();
-
- case RETHROW:
- consume(Token.RETHROW);
- beginExpressionStatement();
- return done(new DartExprStmt(new DartThrowExpression(null)));
-
- case TRY:
- return parseTryStatement();
-
- case SEMICOLON:
- beginEmptyStatement();
- consume(Token.SEMICOLON);
- return done(new DartEmptyStatement());
-
- case CONST:
- // Check to see whether this is a variable declaration. If not, then default to parsing an
- // expression statement.
- int offset = skipTypeName(1);
- if (offset > 1 && (peek(offset) == Token.IDENTIFIER || (offset == 2
- && (peek(offset) == Token.ASSIGN || peek(offset) == Token.COMMA || peek(offset) == Token.SEMICOLON)))) {
- boolean hasType = peek(offset) == Token.IDENTIFIER;
- beginVariableDeclaration();
- next();
- DartTypeNode type = null;
- if (hasType) {
- type = parseTypeAnnotation();
- }
- List<DartVariable> vars = parseInitializedVariableList();
- expect(Token.SEMICOLON);
- return done(new DartVariableStatement(vars, type, Modifiers.NONE.makeConstant().makeFinal()));
- }
- break;
-
- case IDENTIFIER:
- // We have already eliminated function declarations earlier, so check for:
- // a) variable declarations;
- // b) beginning of function literal invocation.
- if (peek(1) == Token.LT || peekMaybeAS(1) == Token.IDENTIFIER
- || (peek(1) == Token.PERIOD && peek(2) == Token.IDENTIFIER)) {
- beginTypeFunctionOrVariable();
- DartTypeNode type = tryTypeAnnotation();
- if (type != null && peekMaybeAS(0) == Token.IDENTIFIER) {
- List<DartVariable> vars = parseInitializedVariableList();
- if (optional(Token.SEMICOLON)) {
- return done(new DartVariableStatement(vars, type));
- } else if (peek(0) == Token.LPAREN) {
- // Probably a function object invocation.
- rollback();
- } else {
- //reportError(position(), ParserErrorCode.EXPECTED_SEMICOLON);
- expectStatmentTerminator();
- return done(new DartVariableStatement(vars, type));
- }
- } else {
- rollback();
- }
- }
- break;
- }
- return parseExpressionStatement();
- }
-
- /**
- * Check if succeeding tokens look like a function declaration - the parser state is unchanged
- * upon return.
- *
- * See {@link #parseFunctionDeclaration()}.
- *
- * @return true if the following tokens should be parsed as a function definition
- */
- private boolean looksLikeFunctionDeclarationOrExpression() {
- beginMethodName();
- try {
- optionalPseudoKeyword(STATIC_KEYWORD);
- if (peek(0) == Token.IDENTIFIER && peek(1) == Token.LPAREN) {
- // just a name, no return type
- consume(Token.IDENTIFIER);
- } else if (isReturnType()) {
- if (!optional(Token.IDENTIFIER)) {
- // return types must be followed by a function name
- return false;
- }
- }
- // start of parameter list
- if (!optional(Token.LPAREN)) {
- return false;
- }
- // if it looks as "(Type name, ....)" then it may be function expression
- boolean hasTwoIdentifiersComma;
- {
- int nameOffset = skipTypeName(0);
- hasTwoIdentifiersComma = nameOffset != -1 && peek(nameOffset + 0) == Token.IDENTIFIER
- && peek(nameOffset + 1) == Token.COMMA;
- }
- // find matching parenthesis
- int count = 1;
- while (count != 0) {
- switch (next()) {
- case EOS:
- return false;
- case LPAREN:
- count++;
- break;
- case RPAREN:
- count--;
- break;
- }
- }
- return (peek(0) == Token.ARROW || peek(0) == Token.LBRACE) || hasTwoIdentifiersComma;
- } finally {
- rollback();
- }
- }
-
- /**
- * Parse a function declaration.
- *
- * <pre>
- * nonLabelledStatement : ...
- * | functionDeclaration functionBody
- *
- * functionDeclaration
- * : FUNCTION identifier formalParameterList
- * { legacy($start, "deprecated 'function' keyword"); }
- * | returnType error=FUNCTION identifier? formalParameterList
- * { legacy($error, "deprecated 'function' keyword"); }
- * | returnType? identifier formalParameterList
- * ;
- * </pre>
- *
- * @return a {@link DartStatement} representing the function declaration or <code>null</code> if
- * code ends with function invocation, so this is not function declaration.
- */
- private DartStatement parseFunctionDeclaration() {
- beginFunctionDeclaration();
- DartIdentifier[] namePtr = new DartIdentifier[1];
- DartFunction function = parseFunctionDeclarationOrExpression(namePtr, true);
- if (function.getBody() instanceof DartReturnBlock || peek(0) != Token.LPAREN) {
- return done(new DartExprStmt(doneWithoutConsuming(new DartFunctionExpression(namePtr[0],
- doneWithoutConsuming(function),
- true))));
- } else {
- rollback();
- return null;
- }
- }
-
- private DartStatement parseExpressionStatement() {
- beginExpressionStatement();
- DartExpression expression = parseExpression();
- expectStatmentTerminator();
-
- return done(new DartExprStmt(expression));
- }
-
- /**
- * Expect a close paren, reporting an error and consuming tokens until a
- * plausible continuation is found if it isn't present.
- */
- private void expectCloseParen() {
- int parenCount = 1;
- Token nextToken = peek(0);
- switch (nextToken) {
- case RPAREN:
- expect(Token.RPAREN);
- return;
-
- case EOS:
- case LBRACE:
- case SEMICOLON:
- reportError(position(), ParserErrorCode.EXPECTED_TOKEN, Token.RPAREN.getSyntax(),
- nextToken.getSyntax());
- return;
-
- case LPAREN:
- ++parenCount;
- //$FALL-THROUGH$
- default:
- reportError(position(), ParserErrorCode.EXPECTED_TOKEN, Token.RPAREN.getSyntax(),
- nextToken.getSyntax());
- Set<Token> terminals = this.collectTerminalAnnotations();
- if (terminals.contains(nextToken) || looksLikeTopLevelKeyword()) {
- return;
- }
- break;
- }
-
- // eat tokens until we get a close paren or a plausible terminator (which
- // is not consumed)
- while (parenCount > 0) {
- switch (peek(0)) {
- case RPAREN:
- expect(Token.RPAREN);
- --parenCount;
- break;
-
- case LPAREN:
- expect(Token.LPAREN);
- ++parenCount;
- break;
-
- case EOS:
- reportErrorWithoutAdvancing(ParserErrorCode.UNEXPECTED_TOKEN);
- return;
-
- case LBRACE:
- case SEMICOLON:
- return;
-
- default:
- next();
- break;
- }
- }
- }
-
- /**
- * Expect a close brace, reporting an error and consuming tokens until a
- * plausible continuation is found if it isn't present.
- */
- private void expectCloseBrace(boolean foundOpenBrace) {
- // If a top level keyword is seen, bail out to recover.
- if (looksLikeTopLevelKeyword()) {
- reportUnexpectedToken(position(), Token.RBRACE, peek(0));
- return;
- }
-
- int braceCount = 0;
- if (foundOpenBrace) {
- braceCount++;
- }
- Token nextToken = peek(0);
- if (expect(Token.RBRACE)) {
- return;
- }
- if (nextToken == Token.LBRACE) {
- braceCount++;
- }
-
- // eat tokens until we get a matching close brace or end of stream
- while (braceCount > 0) {
- if (looksLikeTopLevelKeyword()) {
- return;
- }
- switch (next()) {
- case RBRACE:
- braceCount--;
- break;
-
- case LBRACE:
- braceCount++;
- break;
-
- case EOS:
- return;
- }
- }
- }
-
- /**
- * Collect plausible statement tokens and return a synthetic error statement
- * containing them.
- * <p>
- * Note that this is a crude heuristic that needs to be improved for better
- * error recovery.
- *
- * @return a {@link DartSyntheticErrorStatement}
- */
- private DartStatement parseErrorStatement() {
- StringBuilder buf = new StringBuilder();
- boolean done = false;
- int braceCount = 1;
- while (!done) {
- buf.append(getPeekTokenValue(0));
- next();
- switch (peek(0)) {
- case RBRACE:
- if (--braceCount == 0) {
- done = true;
- }
- break;
- case LBRACE:
- braceCount++;
- break;
- case EOS:
- case SEMICOLON:
- done = true;
- break;
- }
- }
- return new DartSyntheticErrorStatement(buf.toString());
- }
-
-
- /**
- * Look for a statement terminator, giving error messages and consuming tokens
- * for error recovery.
- */
- protected void expectStatmentTerminator() {
- Token token = peek(0);
- if (expect(Token.SEMICOLON)) {
- return;
- }
- Set<Token> terminals = collectTerminalAnnotations();
- assert(terminals.contains(Token.SEMICOLON));
-
- if (peek(0) == token) {
- reportErrorWithoutAdvancing(ParserErrorCode.EXPECTED_SEMICOLON);
- } else {
- reportError(position(), ParserErrorCode.EXPECTED_SEMICOLON);
- token = peek(0);
- }
-
- // Consume tokens until we see something that could terminate or start a new statement
- while (token != Token.SEMICOLON) {
- if (looksLikeTopLevelKeyword() || terminals.contains(token)) {
- return;
- }
- token = next();
- }
- }
-
- /**
- * Report an error without advancing past the next token.
- *
- * @param errCode the error code to report, which may take a string parameter
- * containing the actual token found
- */
- private void reportErrorWithoutAdvancing(ErrorCode errCode) {
- startLookahead();
- Token actual = peek(0);
- next();
- reportError(position(), errCode, actual);
- rollback();
- }
-
- /**
- * <pre>
- * iterationStatement
- * : WHILE '(' expression ')' statement
- * | DO statement WHILE '(' expression ')' ';'
- * | FOR '(' forLoopParts ')' statement
- * ;
- * </pre>
- */
- private DartWhileStatement parseWhileStatement() {
- beginWhileStatement();
- expect(Token.WHILE);
- expect(Token.LPAREN);
- DartExpression condition = parseExpression();
- expectCloseParen();
- int closeParenOffset = ctx.getTokenLocation().getBegin();
- DartStatement body = parseLoopStatement();
- return done(new DartWhileStatement(condition, closeParenOffset, body));
- }
-
- /**
- * <pre>
- * iterationStatement
- * : WHILE '(' expression ')' statement
- * | DO statement WHILE '(' expression ')' ';'
- * | FOR '(' forLoopParts ')' statement
- * ;
- * </pre>
- */
- private DartDoWhileStatement parseDoWhileStatement() {
- beginDoStatement();
- expect(Token.DO);
- DartStatement body = parseLoopStatement();
- expect(Token.WHILE);
- expect(Token.LPAREN);
- DartExpression condition = parseExpression();
- expectCloseParen();
- expectStatmentTerminator();
- return done(new DartDoWhileStatement(condition, body));
- }
-
- /**
- * Use this wrapper to parse the body of a loop
- *
- * Sets up flag variables to make sure continue and break are properly
- * marked as errors when in wrong context.
- */
- private DartStatement parseLoopStatement() {
- boolean oldInLoop = inLoopStatement;
- inLoopStatement = true;
- try {
- return parseStatement();
- } finally {
- inLoopStatement = oldInLoop;
- }
- }
-
- /**
- * <pre>
- * iterationStatement
- * : WHILE '(' expression ')' statement
- * | DO statement WHILE '(' expression ')' ';'
- * | FOR '(' forLoopParts ')' statement
- * ;
- *
- * forLoopParts
- * : forInitializerStatement expression? ';' expressionList?
- * | constVarOrType? identifier IN expression
- * ;
- *
- * forInitializerStatement
- * : initializedVariableDeclaration ';'
- * | expression? ';'
- * ;
- * </pre>
- */
- private DartStatement parseForStatement() {
- beginForStatement();
- expect(Token.FOR);
- expect(Token.LPAREN);
-
- // Setup
- DartStatement setup = null;
- if (peek(0) != Token.SEMICOLON) {
- // Found a setup expression/statement
- beginForInitialization();
- Modifiers modifiers = Modifiers.NONE;
- if (optional(Token.VAR)) {
- setup = done(new DartVariableStatement(parseInitializedVariableList(), null, modifiers));
- } else {
- if (optional(Token.CONST)) {
- modifiers = modifiers.makeConstant();
- }
- if (optional(Token.FINAL)) {
- modifiers = modifiers.makeFinal();
- }
- DartTypeNode type = (peek(1) == Token.IDENTIFIER || peek(1) == Token.LT || peek(1) == Token.PERIOD)
- ? tryTypeAnnotation() : null;
- if (modifiers.isFinal() || type != null) {
- setup = done(new DartVariableStatement(parseInitializedVariableList(), type, modifiers));
- } else {
- setup = done(new DartExprStmt(parseExpression()));
- }
- }
- }
-
- if (optional(Token.IN)) {
- if (setup instanceof DartVariableStatement) {
- DartVariableStatement variableStatement = (DartVariableStatement) setup;
- List<DartVariable> variables = variableStatement.getVariables();
- if (variables.size() != 1) {
- reportError(variables.get(1), ParserErrorCode.FOR_IN_WITH_MULTIPLE_VARIABLES);
- }
- DartExpression initializer = variables.get(0).getValue();
- if (initializer != null) {
- reportError(initializer, ParserErrorCode.FOR_IN_WITH_VARIABLE_INITIALIZER);
- }
- } else {
- DartExpression expression = ((DartExprStmt) setup).getExpression();
- if (!(expression instanceof DartIdentifier)) {
- reportError(setup, ParserErrorCode.FOR_IN_WITH_COMPLEX_VARIABLE);
- }
- }
-
- DartExpression iterable = parseExpression();
- expectCloseParen();
- int closeParenOffset = ctx.getTokenLocation().getBegin();
-
- DartStatement body = parseLoopStatement();
- return done(new DartForInStatement(setup, iterable, closeParenOffset, body));
-
- } else if (optional(Token.SEMICOLON)) {
-
- // Condition
- DartExpression condition = null;
- if (peek(0) != Token.SEMICOLON) {
- condition = parseExpression();
- }
- expect(Token.SEMICOLON);
-
- // Next
- DartExpression next = null;
- if (peek(0) != Token.RPAREN) {
- next = parseExpressionList();
- }
- expectCloseParen();
- int closeParenOffset = ctx.getTokenLocation().getBegin();
-
- DartStatement body = parseLoopStatement();
- return done(new DartForStatement(setup, condition, next, closeParenOffset, body));
- } else {
- reportUnexpectedToken(position(), null, peek(0));
- return done(parseErrorStatement());
- }
- }
-
- /**
- * <pre>
- * selectionStatement
- * : IF '(' expression ')' statement ((ELSE)=> ELSE statement)?
- * | SWITCH '(' expression ')' '{' switchCase* defaultCase? '}'
- * ;
- * </pre>
- */
- private DartIfStatement parseIfStatement() {
- beginIfStatement();
- expect(Token.IF);
- expect(Token.LPAREN);
- DartExpression condition = parseExpression();
- expectCloseParen();
- int closeParenOffset = ctx.getTokenLocation().getBegin();
- DartStatement yes = parseStatement();
- DartStatement no = null;
- int elseTokenOffset = 0;
- if (optional(Token.ELSE)) {
- elseTokenOffset = ctx.getTokenLocation().getBegin();
- no = parseStatement();
- }
- return done(new DartIfStatement(condition, closeParenOffset, yes, elseTokenOffset, no));
- }
-
- /**
- * <pre>
- * caseStatements
- * : normalCompletingStatement* abruptCompletingStatement
- * ;
- * </pre>
- */
- private List<DartStatement> parseCaseStatements() {
- List<DartStatement> statements = new ArrayList<DartStatement>();
- DartStatement statement = null;
- boolean endOfCaseFound = false;
- boolean warnedUnreachable = false;
- while (true) {
- switch (peek(0)) {
- case CLASS:
- // exit loop to report error condition
- case CASE:
- case DEFAULT:
- case RBRACE:
- case EOS:
- return statements;
- case IDENTIFIER:
- // Handle consecutively labeled case statements
- if (isCaseOrDefault()) {
- return statements;
- }
- default:
- boolean oldInCaseStatement = inCaseStatement;
- inCaseStatement = true;
- try {
- if (endOfCaseFound && !warnedUnreachable) {
- reportErrorWithoutAdvancing(ParserErrorCode.UNREACHABLE_CODE_IN_CASE);
- warnedUnreachable = true;
- }
- statement = parseStatement();
- } finally {
- inCaseStatement = oldInCaseStatement;
- }
- if (statement == null) {
- return statements;
- }
-
- // Don't add unreachable code to the list of statements.
- if (!endOfCaseFound) {
- statements.add(statement);
- if (statement.isAbruptCompletingStatement()) {
- endOfCaseFound = true;
- }
- }
- }
- }
- }
-
- private boolean isCaseOrDefault() {
- int index = 0;
- while (peek(index) == Token.IDENTIFIER && peek(index + 1) == Token.COLON) {
- index += 2;
- }
- Token next = peek(index);
- return next == Token.CASE || next == Token.DEFAULT;
- }
-
- /**
- * <pre>
- * switchCase
- * : label? (CASE expression ':')+ caseStatements
- * ;
- * </pre>
- */
- private DartSwitchMember parseCaseMember(List<DartLabel> labels) {
- // The begin() associated with the done() in this method is in the method
- // parseSwitchStatement(), called by beginSwitchMember().
- expect(Token.CASE);
- DartExpression caseExpr = parseExpression();
- expect(Token.COLON);
- return done(new DartCase(caseExpr, labels, parseCaseStatements()));
- }
-
- /**
- * <pre>
- * defaultCase
- * : label? (CASE expression ':')* DEFAULT ':' caseStatements
- * ;
- * </pre>
- */
- private DartSwitchMember parseDefaultMember(List<DartLabel> labels) {
- // The begin() associated with the done() in this method is in the method
- // parseSwitchStatement(), called by beginSwitchMember().
- expect(Token.DEFAULT);
- expect(Token.COLON);
- return done(new DartDefault(labels, parseCaseStatements()));
- }
-
-
- /**
- * <pre>
- * selectionStatement
- * : IF '(' expression ')' statement ((ELSE)=> ELSE statement)?
- * | SWITCH '(' expression ')' '{' switchCase* defaultCase? '}'
- * ;
- * </pre>
- */
- private DartStatement parseSwitchStatement() {
- beginSwitchStatement();
- expect(Token.SWITCH);
-
- expect(Token.LPAREN);
- DartExpression expr = parseExpression();
- expectCloseParen();
-
- List<DartSwitchMember> members = new ArrayList<DartSwitchMember>();
- if (peek(0) != Token.LBRACE) {
- reportUnexpectedToken(position(), Token.LBRACE, peek(0));
- return done(new DartSwitchStatement(expr, members));
- }
- boolean foundOpenBrace = expect(Token.LBRACE);
-
- boolean done = optional(Token.RBRACE);
- while (!done) {
- List<DartLabel> labels = new ArrayList<DartLabel>();
- beginSwitchMember(); // switch member
- while (peek(0) == Token.IDENTIFIER && peek(1) == Token.COLON) {
- beginLabel();
- DartIdentifier identifier = parseIdentifier();
- expect(Token.COLON);
- labels.add(done(new DartLabel(identifier, null)));
- if (peek(0) == Token.RBRACE) {
- reportError(position(), ParserErrorCode.LABEL_NOT_FOLLOWED_BY_CASE_OR_DEFAULT);
- expectCloseBrace(foundOpenBrace);
- return done(new DartSwitchStatement(expr, members));
- }
- }
- if (peek(0) == Token.CASE) {
- members.add(parseCaseMember(labels));
- } else if (optional(Token.RBRACE)) {
- if (!labels.isEmpty()) {
- reportError(position(), ParserErrorCode.EXPECTED_CASE_OR_DEFAULT);
- }
- done = true;
- done(null);
- } else {
- if (peek(0) == Token.DEFAULT) {
- members.add(parseDefaultMember(labels));
- }
- expectCloseBrace(foundOpenBrace);
- done = true; // Ensure termination.
- }
- }
- return done(new DartSwitchStatement(expr, members));
- }
-
- /**
- * <pre>
- * catchParameter
- * : FINAL type? identifier
- * | VAR identifier
- * | type identifier
- * ;
- * </pre>
- */
- private DartParameter parseCatchParameter() {
- beginCatchParameter();
- List<DartAnnotation> metadata = parseMetadata();
- DartTypeNode type = null;
- Modifiers modifiers = Modifiers.NONE;
- boolean isDeclared = false;
- if (optional(Token.VAR)) {
- isDeclared = true;
- } else {
- if (optional(Token.FINAL)) {
- modifiers = modifiers.makeFinal();
- isDeclared = true;
- }
- if (peek(1) != Token.COMMA && peek(1) != Token.RPAREN) {
- type = parseTypeAnnotation();
- isDeclared = true;
- }
- }
- DartIdentifier name = parseIdentifier();
- if (!isDeclared) {
- reportError(name, ParserErrorCode.EXPECTED_VAR_FINAL_OR_TYPE);
- }
- DartParameter parameter = done(new DartParameter(name, type, null, null, modifiers));
- setMetadata(parameter, metadata);
- return parameter;
- }
-
- /**
- * Parse either the old try statement syntax:
- * <pre>
- * tryStatement
- * : TRY block (catchPart+ finallyPart? | finallyPart)
- * ;
- *
- * catchPart
- * : CATCH '(' declaredIdentifier (',' declaredIdentifier)? ')' block
- * ;
- *
- * finallyPart
- * : FINALLY block
- * ;
- * </pre>
- * or the new syntax:
- * <pre>
- * tryStatement
- * : TRY block (onPart+ finallyPart? | finallyPart)
- * ;
- *
- * onPart
- * : catchPart block
- * | ON qualified catchPart? block
- *
- * catchPart
- * : CATCH '(' identifier (',' identifier)? ')'
- * ;
- *
- * finallyPart
- * : FINALLY block
- * ;
- * </pre>
- */
- private DartTryStatement parseTryStatement() {
- beginTryStatement();
- // Try.
- expect(Token.TRY);
- // TODO(zundel): It would be nice here to setup 'ON', 'CATCH' and 'FINALLY' as tokens for recovery
- DartBlock tryBlock = parseBlock();
-
- List<DartCatchBlock> catches = new ArrayList<DartCatchBlock>();
- while (peekPseudoKeyword(0, ON_KEYWORD) || match(Token.CATCH)) {
- // TODO(zundel): It would be nice here to setup 'FINALLY' as token for recovery
- if (peekPseudoKeyword(0, ON_KEYWORD)) {
- beginCatchClause();
- next();
- int onTokenOffset = position();
- DartTypeNode exceptionType = parseTypeAnnotation();
- DartParameter exception = null;
- DartParameter stackTrace = null;
- if (optional(Token.CATCH)) {
- expect(Token.LPAREN);
- beginCatchParameter();
- List<DartAnnotation> metadata = parseMetadata();
- DartIdentifier exceptionName = parseIdentifier();
- exception = done(new DartParameter(exceptionName, exceptionType, null, null, Modifiers.NONE));
- setMetadata(exception, metadata);
- if (optional(Token.COMMA)) {
- beginCatchParameter();
- DartIdentifier stackName = parseIdentifier();
- stackTrace = done(new DartParameter(stackName, null, null, null, Modifiers.NONE));
- }
- expectCloseParen();
- } else {
- // Create a dummy identifier that the user cannot reliably reference.
- beginCatchParameter();
- List<DartAnnotation> metadata = parseMetadata();
- beginIdentifier();
- DartIdentifier exceptionName = done(new DartIdentifier("e" + Long.toHexString(System.currentTimeMillis())));
- exception = done(new DartParameter(exceptionName, exceptionType, null, null, Modifiers.NONE));
- setMetadata(exception, metadata);
- }
- DartBlock block = parseBlock();
- catches.add(done(new DartCatchBlock(block, onTokenOffset, exception, stackTrace)));
- } else {
- beginCatchClause();
- next();
- expect(Token.LPAREN);
- DartParameter exception;
- if (match(Token.IDENTIFIER) && (peek(1) == Token.COMMA || peek(1) == Token.RPAREN)) {
- beginCatchParameter();
- List<DartAnnotation> metadata = parseMetadata();
- DartIdentifier exceptionName = parseIdentifier();
- exception = done(new DartParameter(exceptionName, null , null, null, Modifiers.NONE));
- setMetadata(exception, metadata);
- } else {
- // Old-style parameter
- reportError(position(), ParserErrorCode.DEPRECATED_CATCH);
- exception = parseCatchParameter();
- }
- DartParameter stackTrace = null;
- if (optional(Token.COMMA)) {
- if (match(Token.IDENTIFIER) && peek(1) == Token.RPAREN) {
- beginCatchParameter();
- List<DartAnnotation> metadata = parseMetadata();
- DartIdentifier stackName = parseIdentifier();
- stackTrace = done(new DartParameter(stackName, null, null, null, Modifiers.NONE));
- setMetadata(stackTrace, metadata);
- } else {
- // Old-style parameter
- reportError(position(), ParserErrorCode.DEPRECATED_CATCH);
- stackTrace = parseCatchParameter();
- }
- }
- expectCloseParen();
- DartBlock block = parseBlock();
- catches.add(done(new DartCatchBlock(block, -1, exception, stackTrace)));
- }
- }
-
- // Finally.
- DartBlock finallyBlock = null;
- if (optional(Token.FINALLY)) {
- finallyBlock = parseBlock();
- }
-
- if ( catches.size() == 0 && finallyBlock == null) {
- reportError(new DartCompilationError(tryBlock.getSourceInfo().getSource(), new Location(position()),
- ParserErrorCode.CATCH_OR_FINALLY_EXPECTED));
- }
-
- return done(new DartTryStatement(tryBlock, catches, finallyBlock));
- }
-
- /**
- * <pre>
- * unaryExpression
- * : postfixExpression
- * | prefixOperator unaryExpression
- * | incrementOperator assignableExpression
- * ;
- *
- * @return an expression or null if noFail is true and the next tokens could not be parsed as an
- * expression, leaving the state unchanged.
- * </pre>
- */
- private DartExpression parseUnaryExpression() {
- // There is no unary plus operator in Dart.
- // However, we allow a leading plus in decimal numeric literals.
- if (optional(Token.ADD)) {
- if (peek(0) != Token.INTEGER_LITERAL && peek(0) != Token.DOUBLE_LITERAL) {
- reportError(position(), ParserErrorCode.NO_UNARY_PLUS_OPERATOR);
- } else if (position() + 1 != peekTokenLocation(0).getBegin()) {
- reportError(position(), ParserErrorCode.NO_SPACE_AFTER_PLUS);
- }
- }
- // Check for unary minus operator.
- Token token = peek(0);
- if (token.isUnaryOperator() || token == Token.SUB) {
- if (token == Token.DEC && peek(1) == Token.SUPER) {
- beginUnaryExpression();
- beginUnaryExpression();
- consume(token);
- int tokenOffset = ctx.getTokenLocation().getBegin();
- DartExpression unary = parseUnaryExpression();
- DartUnaryExpression unary2 = new DartUnaryExpression(Token.SUB, tokenOffset, unary, true);
- return done(new DartUnaryExpression(Token.SUB, tokenOffset, done(unary2), true));
- } else {
- beginUnaryExpression();
- consume(token);
- int tokenOffset = ctx.getTokenLocation().getBegin();
- DartExpression unary = parseUnaryExpression();
- if (token.isCountOperator()) {
- ensureAssignable(unary);
- }
- return done(new DartUnaryExpression(token, tokenOffset, unary, true));
- }
- } else {
- return parsePostfixExpression();
- }
- }
-
- /**
- * <pre>
- * type
- * : qualified typeArguments?
- * ;
- * </pre>
- */
- private DartTypeNode parseTypeAnnotation() {
- beginTypeAnnotation();
- return done(new DartTypeNode(parseQualified(false), parseTypeArgumentsOpt()));
- }
-
- /**
- * <pre>
- * type
- * : qualified typeArguments? ('.' identifier)?
- * ;
- * </pre>
- */
- private DartTypeNode parseTypeAnnotationPossiblyFollowedByName() {
- beginTypeAnnotation();
- boolean canBeFollowedByPeriod = true;
- if (peek(Token.IDENTIFIER, Token.LT) || peek(Token.IDENTIFIER, Token.PERIOD, Token.IDENTIFIER, Token.LT)) {
- canBeFollowedByPeriod = false;
- }
- return done(new DartTypeNode(parseQualified(canBeFollowedByPeriod), parseTypeArgumentsOpt()));
- }
-
- private boolean peek(Token... tokens) {
- int index = 0;
- for (Token token : tokens) {
- if (peek(index++) != token) {
- return false;
- }
- }
- return true;
- }
-
- /**
- * <pre>
- * typeArguments
- * : '<' typeList '>'
- * ;
- *
- * typeList
- * : type (',' type)*
- * ;
- * </pre>
- */
- @Terminals(tokens={Token.GT, Token.COMMA})
- private List<DartTypeNode> parseTypeArguments() {
- consume(Token.LT);
- List<DartTypeNode> arguments = new ArrayList<DartTypeNode>();
- do {
- arguments.add(parseTypeAnnotation());
- } while (optional(Token.COMMA));
- if (!tryParameterizedTypeEnd()) {
- expect(Token.GT);
- }
- return arguments;
- }
-
- /**
- * <pre>
- * typeArguments?
- * </pre>
- */
- private List<DartTypeNode> parseTypeArgumentsOpt() {
- return (peek(0) == Token.LT)
- ? parseTypeArguments()
- : Collections.<DartTypeNode>emptyList();
- }
-
- /**
- * <pre>
- * qualified
- * : identifier ('.' identifier)?
- * ;
- * </pre>
- */
- private DartExpression parseQualified(boolean canBeFollowedByPeriod) {
- beginQualifiedIdentifier();
- DartIdentifier identifier = parseIdentifier();
- if (!prefixes.contains(identifier.getName())) {
- if (canBeFollowedByPeriod && !(peek(0) == Token.PERIOD && peek(1) == Token.IDENTIFIER && peek(2) == Token.PERIOD)) {
- return done(identifier);
- }
- }
- DartExpression qualified = identifier;
- if (optional(Token.PERIOD)) {
- // The previous identifier was a prefix.
- qualified = new DartPropertyAccess(qualified, parseIdentifier());
- }
- return done(qualified);
- }
-
- private boolean tryParameterizedTypeEnd() {
- switch (peek(0)) {
- case GT:
- consume(Token.GT);
- return true;
- case SAR:
- setPeek(0, Token.GT);
- return true;
- default:
- return false;
- }
- }
-
- private DartTypeNode tryTypeAnnotation() {
- if (peek(0) != Token.IDENTIFIER) {
- return null;
- }
- List<DartTypeNode> typeArguments = new ArrayList<DartTypeNode>();
- beginTypeAnnotation(); // to allow roll-back in case we're not at a type
-
- DartNode qualified = parseQualified(false);
-
- if (optional(Token.LT)) {
- if (peek(0) != Token.IDENTIFIER) {
- rollback();
- return null;
- }
- beginTypeArguments();
- DartNode qualified2 = parseQualified(false);
- DartTypeNode argument;
- switch (peek(0)) {
- case LT:
- // qualified < qualified2 <
- argument = done(new DartTypeNode(qualified2, parseTypeArguments()));
- break;
-
- case GT:
- case SAR:
- // qualified < qualified2 >
- case COMMA:
- // qualified < qualified2 ,
- argument = done(new DartTypeNode(qualified2, Collections.<DartTypeNode>emptyList()));
- break;
-
- default:
- done(null);
- rollback();
- return null;
- }
- typeArguments.add(argument);
-
- while (optional(Token.COMMA)) {
- typeArguments.add(parseTypeAnnotation());
- }
- if (!tryParameterizedTypeEnd()) {
- expect(Token.GT);
- }
- }
-
- return done(new DartTypeNode(qualified, typeArguments));
- }
-
- private DartIdentifier parseIdentifier() {
- beginIdentifier();
- if (looksLikeTopLevelKeyword()) {
- reportErrorWithoutAdvancing(ParserErrorCode.EXPECTED_IDENTIFIER);
- return done(new DartSyntheticErrorIdentifier());
- }
- DartIdentifier identifier;
- if (expect(Token.IDENTIFIER) && ctx.getTokenString() != null) {
- identifier = new DartIdentifier(new String(ctx.getTokenString()));
- } else {
- identifier = new DartSyntheticErrorIdentifier();
- }
- return done(identifier);
- }
-
- public DartExpression parseEntryPoint() {
- beginEntryPoint();
- DartExpression entry = parseIdentifier();
- while (!EOS()) {
- expect(Token.PERIOD);
- entry = doneWithoutConsuming(new DartPropertyAccess(entry, parseIdentifier()));
- }
- return done(entry);
- }
-
- private void ensureAssignable(DartExpression expression) {
- if (expression != null && !expression.isAssignable()) {
- reportError(position(), ParserErrorCode.ILLEGAL_ASSIGNMENT_TO_NON_ASSIGNABLE);
- }
- }
-
- /**
- * Increment the number of errors encountered while parsing this compilation unit. Returns whether
- * the current error should be reported.
- *
- * @return whether the current error should be reported
- */
- private boolean incErrorCount(ErrorCode errorCode) {
- // count only errors, but not warnings (such as "abstract")
- if (errorCode.getErrorSeverity() == ErrorSeverity.ERROR) {
- errorCount++;
- }
-
- if (errorCount >= MAX_DEFAULT_ERRORS) {
- if (errorCount == MAX_DEFAULT_ERRORS) {
- // Create a 'too many errors' error.
- DartCompilationError dartError = new DartCompilationError(ctx.getSource(),
- ctx.getTokenLocation(), ParserErrorCode.NO_SOUP_FOR_YOU);
- ctx.error(dartError);
- }
-
- // Consume the rest of the input stream. Throwing an exception - as suggested elsewhere in
- // this file - is not ideal.
- Token next = next();
-
- while (next != null && next != Token.EOS) {
- next = next();
- }
- }
-
- return errorCount < MAX_DEFAULT_ERRORS;
- }
-
- private void reportDeprecatedError(int position, ErrorCode errorCode) {
- // TODO(scheglov) remove after http://code.google.com/p/dart/issues/detail?id=6508
- if (
- true
- && !Elements.isCoreLibrarySource(source)
- && !Elements.isLibrarySource(source, "/isolate/isolate.dart")
- && !Elements.isLibrarySource(source, "/json/json.dart")
- && !Elements.isLibrarySource(source, "/math/math.dart")
- && !Elements.isLibrarySource(source, "/io/io.dart")
- && !Elements.isLibrarySource(source, "/crypto/crypto.dart")
- && !Elements.isLibrarySource(source, "/uri/uri.dart")
- && !Elements.isLibrarySource(source, "/utf/utf.dart")
- && !Elements.isLibrarySource(source, "/typed_data/typed_data.dart")
- ) {
- super.reportError(position, errorCode);
- }
- }
-
- @Override
- protected void reportError(int position, ErrorCode errorCode, Object... arguments) {
- // TODO(devoncarew): we're not correctly identifying dart:html as a core library
- if (incErrorCount(errorCode)) {
- super.reportError(position, errorCode, arguments);
- }
- }
-
- @Override
- protected void reportErrorAtPosition(int startPosition, int endPosition,
- ErrorCode errorCode, Object... arguments) {
- if (incErrorCount(errorCode)) {
- super.reportErrorAtPosition(startPosition, endPosition, errorCode, arguments);
- }
- }
-
- private void reportError(DartCompilationError dartError) {
- if (incErrorCount(dartError.getErrorCode())) {
- ctx.error(dartError);
- errorHistory.add(dartError.hashCode());
- }
- }
-
- private void reportError(DartNode node, ErrorCode errorCode, Object... arguments) {
- if (node != null) {
- reportError(new DartCompilationError(node, errorCode, arguments));
- }
- }
-
- private boolean currentlyParsingToplevel() {
- return !(isParsingInterface || isTopLevelAbstract || isParsingClass);
- }
-
- /**
- * @return <code>true</code> if current token is built-in identifier which can have special
- * meaning. For example if it is used as import prefix, this is not special meaning, this is just
- * normal identifier.
- */
- private boolean isBuiltInSpecial() {
- Token nextToken = peek(1);
- if (nextToken == Token.LT) {
- return peek(2) != Token.IDENTIFIER;
- }
- return nextToken != Token.PERIOD && nextToken != Token.LPAREN;
- }
-}

Powered by Google App Engine
This is Rietveld 408576698