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

Unified Diff: sdk/lib/_internal/compiler/implementation/scanner/parser.dart

Issue 694353007: Move dart2js from sdk/lib/_internal/compiler to pkg/compiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month 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: sdk/lib/_internal/compiler/implementation/scanner/parser.dart
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/parser.dart b/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
deleted file mode 100644
index b13a7b5ca47a281beb3bf5cd5556bc820dfbbde5..0000000000000000000000000000000000000000
--- a/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
+++ /dev/null
@@ -1,2578 +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.
-
-part of scanner;
-
-class FormalParameterType {
- final String type;
- const FormalParameterType(this.type);
- bool get isRequired => this == REQUIRED;
- bool get isPositional => this == POSITIONAL;
- bool get isNamed => this == NAMED;
- static final REQUIRED = const FormalParameterType('required');
- static final POSITIONAL = const FormalParameterType('positional');
- static final NAMED = const FormalParameterType('named');
-}
-
-/**
- * An event generating parser of Dart programs. This parser expects
- * all tokens in a linked list (aka a token stream).
- *
- * The class [Scanner] is used to generate a token stream. See the
- * file scanner.dart.
- *
- * Subclasses of the class [Listener] are used to listen to events.
- *
- * Most methods of this class belong in one of two major categories:
- * parse metods and peek methods. Parse methods all have the prefix
- * parse, and peek methods all have the prefix peek.
- *
- * Parse methods generate events (by calling methods on [listener])
- * and return the next token to parse. Peek methods do not generate
- * events (except for errors) and may return null.
- *
- * Parse methods are generally named parseGrammarProductionSuffix. The
- * suffix can be one of "opt", or "star". "opt" means zero or one
- * matches, "star" means zero or more matches. For example,
- * [parseMetadataStar] corresponds to this grammar snippet: [:
- * metadata* :], and [parseTypeOpt] corresponds to: [: type? :].
- */
-class Parser {
- final Listener listener;
- bool mayParseFunctionExpressions = true;
- bool yieldIsKeyword = false;
- bool awaitIsKeyword = false;
-
- Parser(this.listener);
-
- Token parseUnit(Token token) {
- listener.beginCompilationUnit(token);
- int count = 0;
- while (!identical(token.kind, EOF_TOKEN)) {
- token = parseTopLevelDeclaration(token);
- listener.endTopLevelDeclaration(token);
- count++;
- }
- listener.endCompilationUnit(count, token);
- return token;
- }
-
- Token parseTopLevelDeclaration(Token token) {
- token = parseMetadataStar(token);
- final String value = token.stringValue;
- if ((identical(value, 'abstract') && optional('class', token.next))
- || identical(value, 'class')) {
- return parseClassOrNamedMixinApplication(token);
- } else if (identical(value, 'typedef')) {
- return parseTypedef(token);
- } else if (identical(value, 'library')) {
- return parseLibraryName(token);
- } else if (identical(value, 'import')) {
- return parseImport(token);
- } else if (identical(value, 'export')) {
- return parseExport(token);
- } else if (identical(value, 'part')) {
- return parsePartOrPartOf(token);
- } else {
- return parseTopLevelMember(token);
- }
- }
-
- /// library qualified ';'
- Token parseLibraryName(Token token) {
- Token libraryKeyword = token;
- listener.beginLibraryName(libraryKeyword);
- assert(optional('library', token));
- token = parseQualified(token.next);
- Token semicolon = token;
- token = expect(';', token);
- listener.endLibraryName(libraryKeyword, semicolon);
- return token;
- }
-
- /// import uri (as identifier)? combinator* ';'
- Token parseImport(Token token) {
- Token importKeyword = token;
- listener.beginImport(importKeyword);
- assert(optional('import', token));
- token = parseLiteralStringOrRecoverExpression(token.next);
- Token deferredKeyword;
- if (optional('deferred', token)) {
- deferredKeyword = token;
- token = token.next;
- }
- Token asKeyword;
- if (optional('as', token)) {
- asKeyword = token;
- token = parseIdentifier(token.next);
- }
- token = parseCombinators(token);
- Token semicolon = token;
- token = expect(';', token);
- listener.endImport(importKeyword, deferredKeyword, asKeyword, semicolon);
- return token;
- }
-
- /// export uri combinator* ';'
- Token parseExport(Token token) {
- Token exportKeyword = token;
- listener.beginExport(exportKeyword);
- assert(optional('export', token));
- token = parseLiteralStringOrRecoverExpression(token.next);
- token = parseCombinators(token);
- Token semicolon = token;
- token = expect(';', token);
- listener.endExport(exportKeyword, semicolon);
- return token;
- }
-
- Token parseCombinators(Token token) {
- listener.beginCombinators(token);
- int count = 0;
- while (true) {
- String value = token.stringValue;
- if (identical('hide', value)) {
- token = parseHide(token);
- } else if (identical('show', value)) {
- token = parseShow(token);
- } else {
- listener.endCombinators(count);
- break;
- }
- count++;
- }
- return token;
- }
-
- /// hide identifierList
- Token parseHide(Token token) {
- Token hideKeyword = token;
- listener.beginHide(hideKeyword);
- assert(optional('hide', token));
- token = parseIdentifierList(token.next);
- listener.endHide(hideKeyword);
- return token;
- }
-
- /// show identifierList
- Token parseShow(Token token) {
- Token showKeyword = token;
- listener.beginShow(showKeyword);
- assert(optional('show', token));
- token = parseIdentifierList(token.next);
- listener.endShow(showKeyword);
- return token;
- }
-
- /// identifier (, identifier)*
- Token parseIdentifierList(Token token) {
- listener.beginIdentifierList(token);
- token = parseIdentifier(token);
- int count = 1;
- while (optional(',', token)) {
- token = parseIdentifier(token.next);
- count++;
- }
- listener.endIdentifierList(count);
- return token;
- }
-
- /// type (, type)*
- Token parseTypeList(Token token) {
- listener.beginTypeList(token);
- token = parseType(token);
- int count = 1;
- while (optional(',', token)) {
- token = parseType(token.next);
- count++;
- }
- listener.endTypeList(count);
- return token;
- }
-
- Token parsePartOrPartOf(Token token) {
- assert(optional('part', token));
- if (optional('of', token.next)) {
- return parsePartOf(token);
- } else {
- return parsePart(token);
- }
- }
-
- Token parsePart(Token token) {
- Token partKeyword = token;
- listener.beginPart(token);
- assert(optional('part', token));
- token = parseLiteralStringOrRecoverExpression(token.next);
- Token semicolon = token;
- token = expect(';', token);
- listener.endPart(partKeyword, semicolon);
- return token;
- }
-
- Token parsePartOf(Token token) {
- listener.beginPartOf(token);
- assert(optional('part', token));
- assert(optional('of', token.next));
- Token partKeyword = token;
- token = parseQualified(token.next.next);
- Token semicolon = token;
- token = expect(';', token);
- listener.endPartOf(partKeyword, semicolon);
- return token;
- }
-
- Token parseMetadataStar(Token token, {bool forParameter: false}) {
- listener.beginMetadataStar(token);
- int count = 0;
- while (optional('@', token)) {
- token = parseMetadata(token);
- count++;
- }
- listener.endMetadataStar(count, forParameter);
- return token;
- }
-
- /**
- * Parse
- * [: '@' qualified (‘.’ identifier)? (arguments)? :]
- */
- Token parseMetadata(Token token) {
- listener.beginMetadata(token);
- Token atToken = token;
- assert(optional('@', token));
- token = parseIdentifier(token.next);
- token = parseQualifiedRestOpt(token);
- token = parseTypeArgumentsOpt(token);
- Token period = null;
- if (optional('.', token)) {
- period = token;
- token = parseIdentifier(token.next);
- }
- token = parseArgumentsOpt(token);
- listener.endMetadata(atToken, period, token);
- return token;
- }
-
- Token parseTypedef(Token token) {
- Token typedefKeyword = token;
- if (optional('=', peekAfterType(token.next))) {
- // TODO(aprelev@gmail.com): Remove deprecated 'typedef' mixin application,
- // remove corresponding diagnostic from members.dart.
- listener.beginNamedMixinApplication(token);
- token = parseIdentifier(token.next);
- token = parseTypeVariablesOpt(token);
- token = expect('=', token);
- token = parseModifiers(token);
- token = parseMixinApplication(token);
- Token implementsKeyword = null;
- if (optional('implements', token)) {
- implementsKeyword = token;
- token = parseTypeList(token.next);
- }
- listener.endNamedMixinApplication(
- typedefKeyword, implementsKeyword, token);
- } else {
- listener.beginFunctionTypeAlias(token);
- token = parseReturnTypeOpt(token.next);
- token = parseIdentifier(token);
- token = parseTypeVariablesOpt(token);
- token = parseFormalParameters(token);
- listener.endFunctionTypeAlias(typedefKeyword, token);
- }
- return expect(';', token);
- }
-
- Token parseMixinApplication(Token token) {
- listener.beginMixinApplication(token);
- token = parseType(token);
- token = expect('with', token);
- token = parseTypeList(token);
- listener.endMixinApplication();
- return token;
- }
-
- Token parseReturnTypeOpt(Token token) {
- if (identical(token.stringValue, 'void')) {
- listener.handleVoidKeyword(token);
- return token.next;
- } else {
- return parseTypeOpt(token);
- }
- }
-
- Token parseFormalParametersOpt(Token token) {
- if (optional('(', token)) {
- return parseFormalParameters(token);
- } else {
- listener.handleNoFormalParameters(token);
- return token;
- }
- }
-
- Token parseFormalParameters(Token token) {
- Token begin = token;
- listener.beginFormalParameters(begin);
- expect('(', token);
- int parameterCount = 0;
- if (optional(')', token.next)) {
- listener.endFormalParameters(parameterCount, begin, token.next);
- return token.next.next;
- }
- do {
- ++parameterCount;
- token = token.next;
- String value = token.stringValue;
- if (identical(value, '[')) {
- token = parseOptionalFormalParameters(token, false);
- break;
- } else if (identical(value, '{')) {
- token = parseOptionalFormalParameters(token, true);
- break;
- }
- token = parseFormalParameter(token, FormalParameterType.REQUIRED);
- } while (optional(',', token));
- listener.endFormalParameters(parameterCount, begin, token);
- return expect(')', token);
- }
-
- Token parseFormalParameter(Token token, FormalParameterType type) {
- token = parseMetadataStar(token, forParameter: true);
- listener.beginFormalParameter(token);
- token = parseModifiers(token);
- // TODO(ahe): Validate that there are formal parameters if void.
- token = parseReturnTypeOpt(token);
- Token thisKeyword = null;
- if (optional('this', token)) {
- thisKeyword = token;
- // TODO(ahe): Validate field initializers are only used in
- // constructors, and not for function-typed arguments.
- token = expect('.', token.next);
- }
- token = parseIdentifier(token);
- if (optional('(', token)) {
- token = parseFormalParameters(token);
- listener.handleFunctionTypedFormalParameter(token);
- }
- String value = token.stringValue;
- if ((identical('=', value)) || (identical(':', value))) {
- // TODO(ahe): Validate that these are only used for optional parameters.
- Token equal = token;
- token = parseExpression(token.next);
- listener.handleValuedFormalParameter(equal, token);
- if (type.isRequired) {
- listener.reportError(equal,
- MessageKind.REQUIRED_PARAMETER_WITH_DEFAULT);
- } else if (type.isNamed && identical('=', value)) {
- listener.reportError(equal, MessageKind.NAMED_PARAMETER_WITH_EQUALS);
- } else if (type.isPositional && identical(':', value)) {
- listener.reportError(equal,
- MessageKind.POSITIONAL_PARAMETER_WITH_EQUALS);
- }
- }
- listener.endFormalParameter(thisKeyword);
- return token;
- }
-
- Token parseOptionalFormalParameters(Token token, bool isNamed) {
- Token begin = token;
- listener.beginOptionalFormalParameters(begin);
- assert((isNamed && optional('{', token)) || optional('[', token));
- int parameterCount = 0;
- do {
- token = token.next;
- var type = isNamed ? FormalParameterType.NAMED
- : FormalParameterType.POSITIONAL;
- token = parseFormalParameter(token, type);
- ++parameterCount;
- } while (optional(',', token));
- listener.endOptionalFormalParameters(parameterCount, begin, token);
- if (isNamed) {
- return expect('}', token);
- } else {
- return expect(']', token);
- }
- }
-
- Token parseTypeOpt(Token token) {
- String value = token.stringValue;
- Token peek = peekAfterIfType(token);
- if (peek != null && (peek.isIdentifier() || optional('this', peek))) {
- return parseType(token);
- }
- listener.handleNoType(token);
- return token;
- }
-
- bool isValidTypeReference(Token token) {
- final kind = token.kind;
- if (identical(kind, IDENTIFIER_TOKEN)) return true;
- if (identical(kind, KEYWORD_TOKEN)) {
- Keyword keyword = (token as KeywordToken).keyword;
- String value = keyword.syntax;
- return keyword.isPseudo
- || (identical(value, 'dynamic'))
- || (identical(value, 'void'));
- }
- return false;
- }
-
- Token parseQualified(Token token) {
- token = parseIdentifier(token);
- while (optional('.', token)) {
- token = parseQualifiedRest(token);
- }
- return token;
- }
-
- Token parseQualifiedRestOpt(Token token) {
- if (optional('.', token)) {
- return parseQualifiedRest(token);
- } else {
- return token;
- }
- }
-
- Token parseQualifiedRest(Token token) {
- assert(optional('.', token));
- Token period = token;
- token = parseIdentifier(token.next);
- listener.handleQualified(period);
- return token;
- }
-
- Token skipBlock(Token token) {
- if (!optional('{', token)) {
- return listener.expectedBlockToSkip(token);
- }
- BeginGroupToken beginGroupToken = token;
- Token endGroup = beginGroupToken.endGroup;
- if (endGroup == null) {
- return listener.unmatched(beginGroupToken);
- } else if (!identical(endGroup.kind, $CLOSE_CURLY_BRACKET)) {
- return listener.unmatched(beginGroupToken);
- }
- return beginGroupToken.endGroup;
- }
-
- Token parseClassOrNamedMixinApplication(Token token) {
- Token begin = token;
- Token abstractKeyword;
- if (optional('abstract', token)) {
- abstractKeyword = token;
- token = token.next;
- }
- Token classKeyword = token;
- var isMixinApplication = optional('=', peekAfterType(token.next));
- if (isMixinApplication) {
- listener.beginNamedMixinApplication(begin);
- token = parseIdentifier(token.next);
- token = parseTypeVariablesOpt(token);
- token = expect('=', token);
- } else {
- listener.beginClassDeclaration(begin);
- }
-
- // TODO(aprelev@gmail.com): Once 'typedef' named mixin application is
- // removed, move modifiers for named mixin application to the bottom of
- // listener stack. This is so stacks for class declaration and named
- // mixin application look similar.
- int modifierCount = 0;
- if (abstractKeyword != null) {
- parseModifier(abstractKeyword);
- modifierCount++;
- }
- listener.handleModifiers(modifierCount);
-
- if (isMixinApplication) {
- return parseNamedMixinApplication(token, classKeyword);
- } else {
- return parseClass(begin, classKeyword);
- }
- }
-
- Token parseNamedMixinApplication(Token token, Token classKeyword) {
- token = parseMixinApplication(token);
- Token implementsKeyword = null;
- if (optional('implements', token)) {
- implementsKeyword = token;
- token = parseTypeList(token.next);
- }
- listener.endNamedMixinApplication(
- classKeyword, implementsKeyword, token);
- return expect(';', token);
- }
-
- Token parseClass(Token begin, Token classKeyword) {
- Token token = parseIdentifier(classKeyword.next);
- token = parseTypeVariablesOpt(token);
- Token extendsKeyword;
- if (optional('extends', token)) {
- extendsKeyword = token;
- if (optional('with', peekAfterType(token.next))) {
- token = parseMixinApplication(token.next);
- } else {
- token = parseType(token.next);
- }
- } else {
- extendsKeyword = null;
- listener.handleNoType(token);
- }
- Token implementsKeyword;
- int interfacesCount = 0;
- if (optional('implements', token)) {
- implementsKeyword = token;
- do {
- token = parseType(token.next);
- ++interfacesCount;
- } while (optional(',', token));
- }
- token = parseClassBody(token);
- listener.endClassDeclaration(interfacesCount, begin, extendsKeyword,
- implementsKeyword, token);
- return token.next;
- }
-
- Token parseStringPart(Token token) {
- if (identical(token.kind, STRING_TOKEN)) {
- listener.handleStringPart(token);
- return token.next;
- } else {
- return listener.expected('string', token);
- }
- }
-
- Token parseIdentifier(Token token) {
- if (!token.isIdentifier()) {
- token = listener.expectedIdentifier(token);
- }
- listener.handleIdentifier(token);
- return token.next;
- }
-
- Token expect(String string, Token token) {
- if (!identical(string, token.stringValue)) {
- return listener.expected(string, token);
- }
- return token.next;
- }
-
- Token parseTypeVariable(Token token) {
- listener.beginTypeVariable(token);
- token = parseIdentifier(token);
- if (optional('extends', token)) {
- token = parseType(token.next);
- } else {
- listener.handleNoType(token);
- }
- listener.endTypeVariable(token);
- return token;
- }
-
- /**
- * Returns true if the stringValue of the [token] is [value].
- */
- bool optional(String value, Token token) {
- return identical(value, token.stringValue);
- }
-
- /**
- * Returns true if the stringValue of the [token] is either [value1],
- * [value2], [value3], or [value4].
- */
- bool isOneOf4(Token token,
- String value1, String value2, String value3, String value4) {
- String stringValue = token.stringValue;
- return identical(value1, stringValue) ||
- identical(value2, stringValue) ||
- identical(value3, stringValue) ||
- identical(value4, stringValue);
- }
-
- bool notEofOrValue(String value, Token token) {
- return !identical(token.kind, EOF_TOKEN) &&
- !identical(value, token.stringValue);
- }
-
- Token parseType(Token token) {
- Token begin = token;
- if (isValidTypeReference(token)) {
- token = parseIdentifier(token);
- token = parseQualifiedRestOpt(token);
- } else {
- token = listener.expectedType(token);
- }
- token = parseTypeArgumentsOpt(token);
- listener.endType(begin, token);
- return token;
- }
-
- Token parseTypeArgumentsOpt(Token token) {
- return parseStuff(token,
- (t) => listener.beginTypeArguments(t),
- (t) => parseType(t),
- (c, bt, et) => listener.endTypeArguments(c, bt, et),
- (t) => listener.handleNoTypeArguments(t));
- }
-
- Token parseTypeVariablesOpt(Token token) {
- return parseStuff(token,
- (t) => listener.beginTypeVariables(t),
- (t) => parseTypeVariable(t),
- (c, bt, et) => listener.endTypeVariables(c, bt, et),
- (t) => listener.handleNoTypeVariables(t));
- }
-
- // TODO(ahe): Clean this up.
- Token parseStuff(Token token, Function beginStuff, Function stuffParser,
- Function endStuff, Function handleNoStuff) {
- if (optional('<', token)) {
- Token begin = token;
- beginStuff(begin);
- int count = 0;
- do {
- token = stuffParser(token.next);
- ++count;
- } while (optional(',', token));
- Token next = token.next;
- if (identical(token.stringValue, '>>')) {
- token = new SymbolToken(GT_INFO, token.charOffset);
- token.next = new SymbolToken(GT_INFO, token.charOffset + 1);
- token.next.next = next;
- } else if (identical(token.stringValue, '>>>')) {
- token = new SymbolToken(GT_INFO, token.charOffset);
- token.next = new SymbolToken(GT_GT_INFO, token.charOffset + 1);
- token.next.next = next;
- }
- endStuff(count, begin, token);
- return expect('>', token);
- }
- handleNoStuff(token);
- return token;
- }
-
- Token parseTopLevelMember(Token token) {
- Token start = token;
- listener.beginTopLevelMember(token);
-
- Link<Token> identifiers = findMemberName(token);
- if (identifiers.isEmpty) {
- return listener.expectedDeclaration(start);
- }
- Token name = identifiers.head;
- identifiers = identifiers.tail;
- Token getOrSet;
- if (!identifiers.isEmpty) {
- String value = identifiers.head.stringValue;
- if ((identical(value, 'get')) || (identical(value, 'set'))) {
- getOrSet = identifiers.head;
- identifiers = identifiers.tail;
- }
- }
- Token type;
- if (!identifiers.isEmpty) {
- if (isValidTypeReference(identifiers.head)) {
- type = identifiers.head;
- identifiers = identifiers.tail;
- }
- }
-
- token = name.next;
- bool isField;
- while (true) {
- // Loop to allow the listener to rewrite the token stream for
- // error handling.
- final String value = token.stringValue;
- if ((identical(value, '(')) || (identical(value, '{'))
- || (identical(value, '=>'))) {
- isField = false;
- break;
- } else if ((identical(value, '=')) || (identical(value, ','))) {
- isField = true;
- break;
- } else if (identical(value, ';')) {
- if (getOrSet != null) {
- // If we found a "get" keyword, this must be an abstract
- // getter.
- isField = (!identical(getOrSet.stringValue, 'get'));
- // TODO(ahe): This feels like a hack.
- } else {
- isField = true;
- }
- break;
- } else {
- token = listener.unexpected(token);
- if (identical(token.kind, EOF_TOKEN)) return token;
- }
- }
- var modifiers = identifiers.reverse();
- return isField
- ? parseFields(start, modifiers, type, getOrSet, name, true)
- : parseTopLevelMethod(start, modifiers, type, getOrSet, name);
- }
-
- bool isVarFinalOrConst(Token token) {
- String value = token.stringValue;
- return identical('var', value)
- || identical('final', value)
- || identical('const', value);
- }
-
- Token expectVarFinalOrConst(Link<Token> modifiers,
- bool hasType,
- bool allowStatic) {
- int modifierCount = 0;
- Token staticModifier;
- if (allowStatic && !modifiers.isEmpty
- && optional('static', modifiers.head)) {
- staticModifier = modifiers.head;
- modifierCount++;
- parseModifier(staticModifier);
- modifiers = modifiers.tail;
- }
- if (modifiers.isEmpty) {
- listener.handleModifiers(modifierCount);
- return null;
- }
- if (modifiers.tail.isEmpty) {
- Token modifier = modifiers.head;
- if (isVarFinalOrConst(modifier)) {
- modifierCount++;
- parseModifier(modifier);
- listener.handleModifiers(modifierCount);
- // TODO(ahe): The caller checks for "var Type name", perhaps we should
- // check here instead.
- return modifier;
- }
- }
-
- // Slow case to report errors.
- List<Token> modifierList = modifiers.toList();
- Token varFinalOrConst =
- modifierList.firstWhere(isVarFinalOrConst, orElse: () => null);
- if (allowStatic && staticModifier == null) {
- staticModifier =
- modifierList.firstWhere(
- (modifier) => optional('static', modifier), orElse: () => null);
- if (staticModifier != null) {
- modifierCount++;
- parseModifier(staticModifier);
- modifierList.remove(staticModifier);
- }
- }
- bool hasTypeOrModifier = hasType;
- if (varFinalOrConst != null) {
- parseModifier(varFinalOrConst);
- modifierCount++;
- hasTypeOrModifier = true;
- modifierList.remove(varFinalOrConst);
- }
- listener.handleModifiers(modifierCount);
- var kind = hasTypeOrModifier
- ? MessageKind.EXTRANEOUS_MODIFIER
- : MessageKind.EXTRANEOUS_MODIFIER_REPLACE;
- for (Token modifier in modifierList) {
- listener.reportError(modifier, kind, {'modifier': modifier});
- }
- return null;
- }
-
- Token parseFields(Token start,
- Link<Token> modifiers,
- Token type,
- Token getOrSet,
- Token name,
- bool isTopLevel) {
- bool hasType = type != null;
- Token varFinalOrConst =
- expectVarFinalOrConst(modifiers, hasType, !isTopLevel);
- bool isVar = false;
- bool hasModifier = false;
- if (varFinalOrConst != null) {
- hasModifier = true;
- isVar = optional('var', varFinalOrConst);
- }
-
- if (getOrSet != null) {
- var kind = (hasModifier || hasType)
- ? MessageKind.EXTRANEOUS_MODIFIER
- : MessageKind.EXTRANEOUS_MODIFIER_REPLACE;
- listener.reportError(getOrSet, kind, {'modifier': getOrSet});
- }
-
- if (!hasType) {
- listener.handleNoType(name);
- } else if (optional('void', type)) {
- listener.handleNoType(name);
- // TODO(ahe): This error is reported twice, second time is from
- // [parseVariablesDeclarationMaybeSemicolon] via
- // [PartialFieldListElement.parseNode].
- listener.reportError(type, MessageKind.VOID_NOT_ALLOWED);
- } else {
- parseType(type);
- if (isVar) {
- listener.reportError(
- modifiers.head, MessageKind.EXTRANEOUS_MODIFIER,
- {'modifier': modifiers.head});
- }
- }
-
- Token token = parseIdentifier(name);
-
- int fieldCount = 1;
- token = parseVariableInitializerOpt(token);
- while (optional(',', token)) {
- token = parseIdentifier(token.next);
- token = parseVariableInitializerOpt(token);
- ++fieldCount;
- }
- Token semicolon = token;
- token = expectSemicolon(token);
- if (isTopLevel) {
- listener.endTopLevelFields(fieldCount, start, semicolon);
- } else {
- listener.endFields(fieldCount, start, semicolon);
- }
- return token;
- }
-
- Token parseTopLevelMethod(Token start,
- Link<Token> modifiers,
- Token type,
- Token getOrSet,
- Token name) {
- Token externalModifier;
- for (Token modifier in modifiers) {
- if (externalModifier == null && optional('external', modifier)) {
- externalModifier = modifier;
- } else {
- listener.reportError(
- modifier, MessageKind.EXTRANEOUS_MODIFIER, {'modifier': modifier});
- }
- }
- if (externalModifier != null) {
- parseModifier(externalModifier);
- listener.handleModifiers(1);
- } else {
- listener.handleModifiers(0);
- }
-
- if (type == null) {
- listener.handleNoType(name);
- } else {
- parseReturnTypeOpt(type);
- }
- Token token = parseIdentifier(name);
-
- token = parseFormalParametersOpt(token);
- bool previousYieldIsKeyword = yieldIsKeyword;
- bool previousAwaitIsKeyword = awaitIsKeyword;
- token = parseAsyncModifier(token);
- token = parseFunctionBody(token, false, externalModifier != null);
- yieldIsKeyword = previousYieldIsKeyword;
- awaitIsKeyword = previousAwaitIsKeyword;
- listener.endTopLevelMethod(start, getOrSet, token);
- return token.next;
- }
-
- Link<Token> findMemberName(Token token) {
- Token start = token;
- Link<Token> identifiers = const Link<Token>();
- while (!identical(token.kind, EOF_TOKEN)) {
- String value = token.stringValue;
- if ((identical(value, '(')) || (identical(value, '{'))
- || (identical(value, '=>'))) {
- // A method.
- return identifiers;
- } else if ((identical(value, '=')) || (identical(value, ';'))
- || (identical(value, ','))) {
- // A field or abstract getter.
- return identifiers;
- }
- identifiers = identifiers.prepend(token);
- if (isValidTypeReference(token)) {
- // type ...
- if (optional('.', token.next)) {
- // type '.' ...
- if (token.next.next.isIdentifier()) {
- // type '.' identifier
- token = token.next.next;
- }
- }
- if (optional('<', token.next)) {
- if (token.next is BeginGroupToken) {
- BeginGroupToken beginGroup = token.next;
- if (beginGroup.endGroup == null) {
- listener.unmatched(beginGroup);
- }
- token = beginGroup.endGroup;
- }
- }
- }
- token = token.next;
- }
- return const Link<Token>();
- }
-
- Token parseVariableInitializerOpt(Token token) {
- if (optional('=', token)) {
- Token assignment = token;
- listener.beginInitializer(token);
- token = parseExpression(token.next);
- listener.endInitializer(assignment);
- }
- return token;
- }
-
- Token parseInitializersOpt(Token token) {
- if (optional(':', token)) {
- return parseInitializers(token);
- } else {
- listener.handleNoInitializers();
- return token;
- }
- }
-
- Token parseInitializers(Token token) {
- Token begin = token;
- listener.beginInitializers(begin);
- expect(':', token);
- int count = 0;
- bool old = mayParseFunctionExpressions;
- mayParseFunctionExpressions = false;
- do {
- token = parseExpression(token.next);
- ++count;
- } while (optional(',', token));
- mayParseFunctionExpressions = old;
- listener.endInitializers(count, begin, token);
- return token;
- }
-
- Token parseLiteralStringOrRecoverExpression(Token token) {
- if (identical(token.kind, STRING_TOKEN)) {
- return parseLiteralString(token);
- } else {
- listener.recoverableError(token, "unexpected");
- return parseExpression(token);
- }
- }
-
- Token expectSemicolon(Token token) {
- return expect(';', token);
- }
-
- bool isModifier(Token token) {
- final String value = token.stringValue;
- return (identical('final', value)) ||
- (identical('var', value)) ||
- (identical('const', value)) ||
- (identical('abstract', value)) ||
- (identical('static', value)) ||
- (identical('external', value));
- }
-
- Token parseModifier(Token token) {
- assert(isModifier(token));
- listener.handleModifier(token);
- return token.next;
- }
-
- void parseModifierList(Link<Token> tokens) {
- int count = 0;
- for (; !tokens.isEmpty; tokens = tokens.tail) {
- Token token = tokens.head;
- if (isModifier(token)) {
- parseModifier(token);
- } else {
- listener.unexpected(token);
- }
- count++;
- }
- listener.handleModifiers(count);
- }
-
- Token parseModifiers(Token token) {
- int count = 0;
- while (identical(token.kind, KEYWORD_TOKEN)) {
- if (!isModifier(token))
- break;
- token = parseModifier(token);
- count++;
- }
- listener.handleModifiers(count);
- return token;
- }
-
- /**
- * Returns the first token after the type starting at [token].
- * This method assumes that [token] is an identifier (or void).
- * Use [peekAfterIfType] if [token] isn't known to be an identifier.
- */
- Token peekAfterType(Token token) {
- // We are looking at "identifier ...".
- Token peek = token.next;
- if (identical(peek.kind, PERIOD_TOKEN)) {
- if (peek.next.isIdentifier()) {
- // Look past a library prefix.
- peek = peek.next.next;
- }
- }
- // We are looking at "qualified ...".
- if (identical(peek.kind, LT_TOKEN)) {
- // Possibly generic type.
- // We are looking at "qualified '<'".
- BeginGroupToken beginGroupToken = peek;
- Token gtToken = beginGroupToken.endGroup;
- if (gtToken != null) {
- // We are looking at "qualified '<' ... '>' ...".
- return gtToken.next;
- }
- }
- return peek;
- }
-
- /**
- * If [token] is the start of a type, returns the token after that type.
- * If [token] is not the start of a type, null is returned.
- */
- Token peekAfterIfType(Token token) {
- if (!optional('void', token) && !token.isIdentifier()) {
- return null;
- }
- return peekAfterType(token);
- }
-
- Token parseClassBody(Token token) {
- Token begin = token;
- listener.beginClassBody(token);
- if (!optional('{', token)) {
- token = listener.expectedClassBody(token);
- }
- token = token.next;
- int count = 0;
- while (notEofOrValue('}', token)) {
- token = parseMember(token);
- ++count;
- }
- expect('}', token);
- listener.endClassBody(count, begin, token);
- return token;
- }
-
- bool isGetOrSet(Token token) {
- final String value = token.stringValue;
- return (identical(value, 'get')) || (identical(value, 'set'));
- }
-
- bool isFactoryDeclaration(Token token) {
- if (optional('external', token)) token = token.next;
- if (optional('const', token)) token = token.next;
- return optional('factory', token);
- }
-
- Token parseMember(Token token) {
- token = parseMetadataStar(token);
- String value = token.stringValue;
- if (isFactoryDeclaration(token)) {
- return parseFactoryMethod(token);
- }
- Token start = token;
- listener.beginMember(token);
-
- Link<Token> identifiers = findMemberName(token);
- if (identifiers.isEmpty) {
- return listener.expectedDeclaration(start);
- }
- Token name = identifiers.head;
- Token afterName = name.next;
- identifiers = identifiers.tail;
- if (!identifiers.isEmpty) {
- if (optional('operator', identifiers.head)) {
- name = identifiers.head;
- identifiers = identifiers.tail;
- }
- }
- Token getOrSet;
- if (!identifiers.isEmpty) {
- if (isGetOrSet(identifiers.head)) {
- getOrSet = identifiers.head;
- identifiers = identifiers.tail;
- }
- }
- Token type;
- if (!identifiers.isEmpty) {
- if (isValidTypeReference(identifiers.head)) {
- type = identifiers.head;
- identifiers = identifiers.tail;
- }
- }
-
- token = afterName;
- bool isField;
- while (true) {
- // Loop to allow the listener to rewrite the token stream for
- // error handling.
- final String value = token.stringValue;
- if ((identical(value, '(')) || (identical(value, '.'))
- || (identical(value, '{')) || (identical(value, '=>'))) {
- isField = false;
- break;
- } else if (identical(value, ';')) {
- if (getOrSet != null) {
- // If we found a "get" keyword, this must be an abstract
- // getter.
- isField = (!identical(getOrSet.stringValue, 'get'));
- // TODO(ahe): This feels like a hack.
- } else {
- isField = true;
- }
- break;
- } else if ((identical(value, '=')) || (identical(value, ','))) {
- isField = true;
- break;
- } else {
- token = listener.unexpected(token);
- if (identical(token.kind, EOF_TOKEN)) {
- // TODO(ahe): This is a hack, see parseTopLevelMember.
- listener.endFields(1, start, token);
- return token;
- }
- }
- }
-
- var modifiers = identifiers.reverse();
- return isField
- ? parseFields(start, modifiers, type, getOrSet, name, false)
- : parseMethod(start, modifiers, type, getOrSet, name);
-
- }
-
- Token parseMethod(Token start,
- Link<Token> modifiers,
- Token type,
- Token getOrSet,
- Token name) {
- Token externalModifier;
- Token staticModifier;
- Token constModifier;
- int modifierCount = 0;
- int allowedModifierCount = 1;
- for (Token modifier in modifiers) {
- if (externalModifier == null && optional('external', modifier)) {
- modifierCount++;
- externalModifier = modifier;
- if (modifierCount != allowedModifierCount) {
- listener.reportError(
- modifier,
- MessageKind.EXTRANEOUS_MODIFIER, {'modifier': modifier});
- }
- allowedModifierCount++;
- } else if (staticModifier == null && optional('static', modifier)) {
- modifierCount++;
- staticModifier = modifier;
- if (modifierCount != allowedModifierCount) {
- listener.reportError(
- modifier,
- MessageKind.EXTRANEOUS_MODIFIER, {'modifier': modifier});
- }
- } else if (constModifier == null && optional('const', modifier)) {
- modifierCount++;
- constModifier = modifier;
- if (modifierCount != allowedModifierCount) {
- listener.reportError(
- modifier,
- MessageKind.EXTRANEOUS_MODIFIER, {'modifier': modifier});
- }
- } else {
- listener.reportError(
- modifier, MessageKind.EXTRANEOUS_MODIFIER, {'modifier': modifier});
- }
- }
- parseModifierList(modifiers);
-
- if (type == null) {
- listener.handleNoType(name);
- } else {
- parseReturnTypeOpt(type);
- }
- Token token;
- if (optional('operator', name)) {
- token = parseOperatorName(name);
- if (staticModifier != null) {
- // TODO(ahe): Consider a more specific error message.
- listener.reportError(
- staticModifier, MessageKind.EXTRANEOUS_MODIFIER,
- {'modifier': staticModifier});
- }
- } else {
- token = parseIdentifier(name);
- }
-
- token = parseQualifiedRestOpt(token);
- token = parseFormalParametersOpt(token);
- token = parseInitializersOpt(token);
- bool previousYieldIsKeyword = yieldIsKeyword;
- bool previousAwaitIsKeyword = awaitIsKeyword;
- token = parseAsyncModifier(token);
- if (optional('=', token)) {
- token = parseRedirectingFactoryBody(token);
- } else {
- token = parseFunctionBody(
- token, false, staticModifier == null || externalModifier != null);
- }
- yieldIsKeyword = previousYieldIsKeyword;
- awaitIsKeyword = previousAwaitIsKeyword;
- listener.endMethod(getOrSet, start, token);
- return token.next;
- }
-
- Token parseFactoryMethod(Token token) {
- assert(isFactoryDeclaration(token));
- Token start = token;
- Token externalModifier;
- if (identical(token.stringValue, 'external')) {
- externalModifier = token;
- token = token.next;
- }
- Token constKeyword = null;
- if (optional('const', token)) {
- constKeyword = token;
- token = token.next;
- }
- Token factoryKeyword = token;
- listener.beginFactoryMethod(factoryKeyword);
- token = token.next; // Skip 'factory'.
- token = parseConstructorReference(token);
- token = parseFormalParameters(token);
- bool previousYieldIsKeyword = yieldIsKeyword;
- bool previousAwaitIsKeyword = awaitIsKeyword;
- token = parseAsyncModifier(token);
- if (optional('=', token)) {
- token = parseRedirectingFactoryBody(token);
- } else {
- token = parseFunctionBody(token, false, externalModifier != null);
- }
- listener.endFactoryMethod(start, token);
- return token.next;
- }
-
- Token parseOperatorName(Token token) {
- assert(optional('operator', token));
- if (isUserDefinableOperator(token.next.stringValue)) {
- Token operator = token;
- token = token.next;
- listener.handleOperatorName(operator, token);
- return token.next;
- } else {
- return parseIdentifier(token);
- }
- }
-
- Token parseFunction(Token token, Token getOrSet) {
- listener.beginFunction(token);
- token = parseModifiers(token);
- if (identical(getOrSet, token)) token = token.next;
- if (optional('operator', token)) {
- listener.handleNoType(token);
- listener.beginFunctionName(token);
- token = parseOperatorName(token);
- } else {
- token = parseReturnTypeOpt(token);
- if (identical(getOrSet, token)) token = token.next;
- listener.beginFunctionName(token);
- if (optional('operator', token)) {
- token = parseOperatorName(token);
- } else {
- token = parseIdentifier(token);
- }
- }
- token = parseQualifiedRestOpt(token);
- listener.endFunctionName(token);
- token = parseFormalParametersOpt(token);
- token = parseInitializersOpt(token);
- bool previousYieldIsKeyword = yieldIsKeyword;
- bool previousAwaitIsKeyword = awaitIsKeyword;
- token = parseAsyncModifier(token);
- if (optional('=', token)) {
- token = parseRedirectingFactoryBody(token);
- } else {
- token = parseFunctionBody(token, false, true);
- }
- yieldIsKeyword = previousYieldIsKeyword;
- awaitIsKeyword = previousAwaitIsKeyword;
- listener.endFunction(getOrSet, token);
- return token.next;
- }
-
- Token parseUnnamedFunction(Token token) {
- listener.beginUnnamedFunction(token);
- token = parseFormalParameters(token);
- bool previousYieldIsKeyword = yieldIsKeyword;
- bool previousAwaitIsKeyword = awaitIsKeyword;
- token = parseAsyncModifier(token);
- bool isBlock = optional('{', token);
- token = parseFunctionBody(token, true, false);
- yieldIsKeyword = previousYieldIsKeyword;
- awaitIsKeyword = previousAwaitIsKeyword;
- listener.endUnnamedFunction(token);
- return isBlock ? token.next : token;
- }
-
- Token parseFunctionDeclaration(Token token) {
- listener.beginFunctionDeclaration(token);
- token = parseFunction(token, null);
- listener.endFunctionDeclaration(token);
- return token;
- }
-
- Token parseFunctionExpression(Token token) {
- listener.beginFunction(token);
- listener.handleModifiers(0);
- token = parseReturnTypeOpt(token);
- listener.beginFunctionName(token);
- token = parseIdentifier(token);
- listener.endFunctionName(token);
- token = parseFormalParameters(token);
- listener.handleNoInitializers();
- bool previousYieldIsKeyword = yieldIsKeyword;
- bool previousAwaitIsKeyword = awaitIsKeyword;
- token = parseAsyncModifier(token);
- bool isBlock = optional('{', token);
- token = parseFunctionBody(token, true, false);
- yieldIsKeyword = previousYieldIsKeyword;
- awaitIsKeyword = previousAwaitIsKeyword;
- listener.endFunction(null, token);
- return isBlock ? token.next : token;
- }
-
- Token parseConstructorReference(Token token) {
- Token start = token;
- listener.beginConstructorReference(start);
- token = parseIdentifier(token);
- token = parseQualifiedRestOpt(token);
- token = parseTypeArgumentsOpt(token);
- Token period = null;
- if (optional('.', token)) {
- period = token;
- token = parseIdentifier(token.next);
- }
- listener.endConstructorReference(start, period, token);
- return token;
- }
-
- Token parseRedirectingFactoryBody(Token token) {
- listener.beginRedirectingFactoryBody(token);
- assert(optional('=', token));
- Token equals = token;
- token = parseConstructorReference(token.next);
- Token semicolon = token;
- expectSemicolon(token);
- listener.endRedirectingFactoryBody(equals, semicolon);
- return token;
- }
-
- Token parseFunctionBody(Token token, bool isExpression, bool allowAbstract) {
- if (optional(';', token)) {
- if (!allowAbstract) {
- listener.reportError(token, MessageKind.BODY_EXPECTED);
- }
- listener.endFunctionBody(0, null, token);
- return token;
- } else if (optional('=>', token)) {
- Token begin = token;
- token = parseExpression(token.next);
- if (!isExpression) {
- expectSemicolon(token);
- listener.endReturnStatement(true, begin, token);
- } else {
- listener.endReturnStatement(true, begin, null);
- }
- return token;
- }
- Token begin = token;
- int statementCount = 0;
- if (!optional('{', token)) {
- return listener.expectedFunctionBody(token);
- }
-
- listener.beginFunctionBody(begin);
- token = token.next;
- while (notEofOrValue('}', token)) {
- token = parseStatement(token);
- ++statementCount;
- }
- listener.endFunctionBody(statementCount, begin, token);
- expect('}', token);
- return token;
- }
-
- /// `async*` and `sync*` are parsed a two tokens, [token] and [star]. This
- /// method checks that there is no whitespace between [token] and [star].
- void checkStarredModifier(Token token, Token star, String name) {
- if (star.charOffset > token.charOffset + token.charCount) {
- listener.reportError(new TokenPair(token, star),
- MessageKind.INVALID_STARRED_KEYWORD, {'keyword': name});
- }
- }
-
- Token parseAsyncModifier(Token token) {
- Token async;
- Token star;
- awaitIsKeyword = false;
- yieldIsKeyword = false;
- if (optional('async', token)) {
- awaitIsKeyword = true;
- async = token;
- token = token.next;
- if (optional('*', token)) {
- yieldIsKeyword = true;
- star = token;
- token = token.next;
- checkStarredModifier(async, star, 'async*');
- }
- } else if (optional('sync', token)) {
- async = token;
- token = token.next;
- if (optional('*', token)) {
- yieldIsKeyword = true;
- star = token;
- token = token.next;
-
- checkStarredModifier(async, star, 'sync*');
- } else {
- listener.reportError(async,
- MessageKind.INVALID_SYNC_MODIFIER);
- }
- }
- listener.handleAsyncModifier(async, star);
- return token;
- }
-
- Token parseStatement(Token token) {
- final value = token.stringValue;
- if (identical(token.kind, IDENTIFIER_TOKEN)) {
- return parseExpressionStatementOrDeclaration(token);
- } else if (identical(value, '{')) {
- return parseBlock(token);
- } else if (identical(value, 'return')) {
- return parseReturnStatement(token);
- } else if (identical(value, 'var') || identical(value, 'final')) {
- return parseVariablesDeclaration(token);
- } else if (identical(value, 'if')) {
- return parseIfStatement(token);
- } else if (awaitIsKeyword && identical(value, 'await')) {
- if (identical(token.next.stringValue, 'for')) {
- return parseForStatement(token, token.next);
- } else {
- return parseExpressionStatement(token);
- }
- } else if (identical(value, 'for')) {
- return parseForStatement(null, token);
- } else if (identical(value, 'rethrow')) {
- return parseRethrowStatement(token);
- } else if (identical(value, 'throw') && optional(';', token.next)) {
- // TODO(kasperl): Stop dealing with throw here.
- return parseRethrowStatement(token);
- } else if (identical(value, 'void')) {
- return parseExpressionStatementOrDeclaration(token);
- } else if (identical(value, 'while')) {
- return parseWhileStatement(token);
- } else if (identical(value, 'do')) {
- return parseDoWhileStatement(token);
- } else if (identical(value, 'try')) {
- return parseTryStatement(token);
- } else if (identical(value, 'switch')) {
- return parseSwitchStatement(token);
- } else if (identical(value, 'break')) {
- return parseBreakStatement(token);
- } else if (identical(value, 'continue')) {
- return parseContinueStatement(token);
- } else if (identical(value, 'assert')) {
- return parseAssertStatement(token);
- } else if (identical(value, ';')) {
- return parseEmptyStatement(token);
- } else if (yieldIsKeyword && identical(value, 'yield')) {
- return parseYieldStatement(token);
- } else if (identical(value, 'const')) {
- return parseExpressionStatementOrConstDeclaration(token);
- } else if (token.isIdentifier()) {
- return parseExpressionStatementOrDeclaration(token);
- } else {
- return parseExpressionStatement(token);
- }
- }
-
- Token parseYieldStatement(Token token) {
- Token begin = token;
- listener.beginYieldStatement(begin);
- assert(identical('yield', token.stringValue));
- token = token.next;
- Token starToken;
- if (optional('*', token)) {
- starToken = token;
- token = token.next;
- checkStarredModifier(begin, starToken, 'yield*');
- }
- token = parseExpression(token);
- listener.endYieldStatement(begin, starToken, token);
- return expectSemicolon(token);
- }
-
-
- Token parseReturnStatement(Token token) {
- Token begin = token;
- listener.beginReturnStatement(begin);
- assert(identical('return', token.stringValue));
- token = token.next;
- if (optional(';', token)) {
- listener.endReturnStatement(false, begin, token);
- } else {
- token = parseExpression(token);
- listener.endReturnStatement(true, begin, token);
- }
- return expectSemicolon(token);
- }
-
- Token peekIdentifierAfterType(Token token) {
- Token peek = peekAfterType(token);
- if (peek != null && peek.isIdentifier()) {
- // We are looking at "type identifier".
- return peek;
- } else {
- return null;
- }
- }
-
- Token peekIdentifierAfterOptionalType(Token token) {
- Token peek = peekIdentifierAfterType(token);
- if (peek != null) {
- // We are looking at "type identifier".
- return peek;
- } else if (token.isIdentifier()) {
- // We are looking at "identifier".
- return token;
- } else {
- return null;
- }
- }
-
- Token parseExpressionStatementOrDeclaration(Token token) {
- assert(token.isIdentifier() || identical(token.stringValue, 'void'));
- Token identifier = peekIdentifierAfterType(token);
- if (identifier != null) {
- assert(identifier.isIdentifier());
- Token afterId = identifier.next;
- int afterIdKind = afterId.kind;
- if (identical(afterIdKind, EQ_TOKEN) ||
- identical(afterIdKind, SEMICOLON_TOKEN) ||
- identical(afterIdKind, COMMA_TOKEN)) {
- // We are looking at "type identifier" followed by '=', ';', ','.
- return parseVariablesDeclaration(token);
- } else if (identical(afterIdKind, OPEN_PAREN_TOKEN)) {
- // We are looking at "type identifier '('".
- BeginGroupToken beginParen = afterId;
- Token endParen = beginParen.endGroup;
- Token afterParens = endParen.next;
- if (optional('{', afterParens) ||
- optional('=>', afterParens) ||
- optional('async', afterParens) ||
- optional('sync', afterParens)) {
- // We are looking at "type identifier '(' ... ')'" followed
- // by '=>' or '{'.
- return parseFunctionDeclaration(token);
- }
- }
- // Fall-through to expression statement.
- } else {
- if (optional(':', token.next)) {
- return parseLabeledStatement(token);
- } else if (optional('(', token.next)) {
- BeginGroupToken begin = token.next;
- String afterParens = begin.endGroup.next.stringValue;
- if (identical(afterParens, '{') ||
- identical(afterParens, '=>') ||
- identical(afterParens, 'async') ||
- identical(afterParens, 'sync')) {
- return parseFunctionDeclaration(token);
- }
- }
- }
- return parseExpressionStatement(token);
- }
-
- Token parseExpressionStatementOrConstDeclaration(Token token) {
- assert(identical(token.stringValue, 'const'));
- if (isModifier(token.next)) {
- return parseVariablesDeclaration(token);
- }
- Token identifier = peekIdentifierAfterOptionalType(token.next);
- if (identifier != null) {
- assert(identifier.isIdentifier());
- Token afterId = identifier.next;
- int afterIdKind = afterId.kind;
- if (identical(afterIdKind, EQ_TOKEN) ||
- identical(afterIdKind, SEMICOLON_TOKEN) ||
- identical(afterIdKind, COMMA_TOKEN)) {
- // We are looking at "const type identifier" followed by '=', ';', or
- // ','.
- return parseVariablesDeclaration(token);
- }
- // Fall-through to expression statement.
- }
-
- return parseExpressionStatement(token);
- }
-
- Token parseLabel(Token token) {
- token = parseIdentifier(token);
- Token colon = token;
- token = expect(':', token);
- listener.handleLabel(colon);
- return token;
- }
-
- Token parseLabeledStatement(Token token) {
- int labelCount = 0;
- do {
- token = parseLabel(token);
- labelCount++;
- } while (token.isIdentifier() && optional(':', token.next));
- listener.beginLabeledStatement(token, labelCount);
- token = parseStatement(token);
- listener.endLabeledStatement(labelCount);
- return token;
- }
-
- Token parseExpressionStatement(Token token) {
- listener.beginExpressionStatement(token);
- token = parseExpression(token);
- listener.endExpressionStatement(token);
- return expectSemicolon(token);
- }
-
- Token parseExpression(Token token) {
- return optional('throw', token)
- ? parseThrowExpression(token, true)
- : parsePrecedenceExpression(token, ASSIGNMENT_PRECEDENCE, true);
- }
-
- Token parseExpressionWithoutCascade(Token token) {
- return optional('throw', token)
- ? parseThrowExpression(token, false)
- : parsePrecedenceExpression(token, ASSIGNMENT_PRECEDENCE, false);
- }
-
- Token parseConditionalExpressionRest(Token token) {
- assert(optional('?', token));
- Token question = token;
- token = parseExpressionWithoutCascade(token.next);
- Token colon = token;
- token = expect(':', token);
- token = parseExpressionWithoutCascade(token);
- listener.handleConditionalExpression(question, colon);
- return token;
- }
-
- Token parsePrecedenceExpression(Token token, int precedence,
- bool allowCascades) {
- assert(precedence >= 1);
- assert(precedence <= POSTFIX_PRECEDENCE);
- token = parseUnaryExpression(token, allowCascades);
- PrecedenceInfo info = token.info;
- int tokenLevel = info.precedence;
- for (int level = tokenLevel; level >= precedence; --level) {
- while (identical(tokenLevel, level)) {
- Token operator = token;
- if (identical(tokenLevel, CASCADE_PRECEDENCE)) {
- if (!allowCascades) {
- return token;
- }
- token = parseCascadeExpression(token);
- } else if (identical(tokenLevel, ASSIGNMENT_PRECEDENCE)) {
- // Right associative, so we recurse at the same precedence
- // level.
- token = parsePrecedenceExpression(token.next, level, allowCascades);
- listener.handleAssignmentExpression(operator);
- } else if (identical(tokenLevel, POSTFIX_PRECEDENCE)) {
- if (identical(info, PERIOD_INFO)) {
- // Left associative, so we recurse at the next higher
- // precedence level. However, POSTFIX_PRECEDENCE is the
- // highest level, so we just call parseUnaryExpression
- // directly.
- token = parseUnaryExpression(token.next, allowCascades);
- listener.handleBinaryExpression(operator);
- } else if ((identical(info, OPEN_PAREN_INFO)) ||
- (identical(info, OPEN_SQUARE_BRACKET_INFO))) {
- token = parseArgumentOrIndexStar(token);
- } else if ((identical(info, PLUS_PLUS_INFO)) ||
- (identical(info, MINUS_MINUS_INFO))) {
- listener.handleUnaryPostfixAssignmentExpression(token);
- token = token.next;
- } else {
- token = listener.unexpected(token);
- }
- } else if (identical(info, IS_INFO)) {
- token = parseIsOperatorRest(token);
- } else if (identical(info, AS_INFO)) {
- token = parseAsOperatorRest(token);
- } else if (identical(info, QUESTION_INFO)) {
- token = parseConditionalExpressionRest(token);
- } else {
- // Left associative, so we recurse at the next higher
- // precedence level.
- token = parsePrecedenceExpression(token.next, level + 1,
- allowCascades);
- listener.handleBinaryExpression(operator);
- }
- info = token.info;
- tokenLevel = info.precedence;
- if (level == EQUALITY_PRECEDENCE || level == RELATIONAL_PRECEDENCE) {
- // We don't allow (a == b == c) or (a < b < c).
- // Continue the outer loop if we have matched one equality or
- // relational operator.
- break;
- }
- }
- }
- return token;
- }
-
- Token parseCascadeExpression(Token token) {
- listener.beginCascade(token);
- assert(optional('..', token));
- Token cascadeOperator = token;
- token = token.next;
- if (optional('[', token)) {
- token = parseArgumentOrIndexStar(token);
- } else if (token.isIdentifier()) {
- token = parseSend(token);
- listener.handleBinaryExpression(cascadeOperator);
- } else {
- return listener.unexpected(token);
- }
- Token mark;
- do {
- mark = token;
- if (optional('.', token)) {
- Token period = token;
- token = parseSend(token.next);
- listener.handleBinaryExpression(period);
- }
- token = parseArgumentOrIndexStar(token);
- } while (!identical(mark, token));
-
- if (identical(token.info.precedence, ASSIGNMENT_PRECEDENCE)) {
- Token assignment = token;
- token = parseExpressionWithoutCascade(token.next);
- listener.handleAssignmentExpression(assignment);
- }
- listener.endCascade();
- return token;
- }
-
- Token parseUnaryExpression(Token token, bool allowCascades) {
- String value = token.stringValue;
- // Prefix:
- if (awaitIsKeyword && optional('await', token)) {
- return parseAwaitExpression(token, allowCascades);
- } else if (identical(value, '+')) {
- // Dart no longer allows prefix-plus.
- listener.reportError(token, MessageKind.UNSUPPORTED_PREFIX_PLUS);
- return parseUnaryExpression(token.next, allowCascades);
- } else if ((identical(value, '!')) ||
- (identical(value, '-')) ||
- (identical(value, '~'))) {
- Token operator = token;
- // Right associative, so we recurse at the same precedence
- // level.
- token = parsePrecedenceExpression(token.next, POSTFIX_PRECEDENCE,
- allowCascades);
- listener.handleUnaryPrefixExpression(operator);
- } else if ((identical(value, '++')) || identical(value, '--')) {
- // TODO(ahe): Validate this is used correctly.
- Token operator = token;
- // Right associative, so we recurse at the same precedence
- // level.
- token = parsePrecedenceExpression(token.next, POSTFIX_PRECEDENCE,
- allowCascades);
- listener.handleUnaryPrefixAssignmentExpression(operator);
- } else {
- token = parsePrimary(token);
- }
- return token;
- }
-
- Token parseArgumentOrIndexStar(Token token) {
- while (true) {
- if (optional('[', token)) {
- Token openSquareBracket = token;
- bool old = mayParseFunctionExpressions;
- mayParseFunctionExpressions = true;
- token = parseExpression(token.next);
- mayParseFunctionExpressions = old;
- listener.handleIndexedExpression(openSquareBracket, token);
- token = expect(']', token);
- } else if (optional('(', token)) {
- token = parseArguments(token);
- listener.endSend(token);
- } else {
- break;
- }
- }
- return token;
- }
-
- Token parsePrimary(Token token) {
- final kind = token.kind;
- if (identical(kind, IDENTIFIER_TOKEN)) {
- return parseSendOrFunctionLiteral(token);
- } else if (identical(kind, INT_TOKEN)
- || identical(kind, HEXADECIMAL_TOKEN)) {
- return parseLiteralInt(token);
- } else if (identical(kind, DOUBLE_TOKEN)) {
- return parseLiteralDouble(token);
- } else if (identical(kind, STRING_TOKEN)) {
- return parseLiteralString(token);
- } else if (identical(kind, HASH_TOKEN)) {
- return parseLiteralSymbol(token);
- } else if (identical(kind, KEYWORD_TOKEN)) {
- final value = token.stringValue;
- if ((identical(value, 'true')) || (identical(value, 'false'))) {
- return parseLiteralBool(token);
- } else if (identical(value, 'null')) {
- return parseLiteralNull(token);
- } else if (identical(value, 'this')) {
- return parseThisExpression(token);
- } else if (identical(value, 'super')) {
- return parseSuperExpression(token);
- } else if (identical(value, 'new')) {
- return parseNewExpression(token);
- } else if (identical(value, 'const')) {
- return parseConstExpression(token);
- } else if (identical(value, 'void')) {
- return parseFunctionExpression(token);
- } else if (token.isIdentifier()) {
- return parseSendOrFunctionLiteral(token);
- } else {
- return listener.expectedExpression(token);
- }
- } else if (identical(kind, OPEN_PAREN_TOKEN)) {
- return parseParenthesizedExpressionOrFunctionLiteral(token);
- } else if ((identical(kind, LT_TOKEN)) ||
- (identical(kind, OPEN_SQUARE_BRACKET_TOKEN)) ||
- (identical(kind, OPEN_CURLY_BRACKET_TOKEN)) ||
- identical(token.stringValue, '[]')) {
- return parseLiteralListOrMap(token);
- } else {
- return listener.expectedExpression(token);
- }
- }
-
- Token parseParenthesizedExpressionOrFunctionLiteral(Token token) {
- BeginGroupToken beginGroup = token;
- Token nextToken = beginGroup.endGroup.next;
- int kind = nextToken.kind;
- if (mayParseFunctionExpressions &&
- (identical(kind, FUNCTION_TOKEN) ||
- identical(kind, OPEN_CURLY_BRACKET_TOKEN) ||
- (identical(kind, KEYWORD_TOKEN) &&
- (nextToken.value == 'async' || nextToken.value == 'sync')))) {
- return parseUnnamedFunction(token);
- } else {
- bool old = mayParseFunctionExpressions;
- mayParseFunctionExpressions = true;
- token = parseParenthesizedExpression(token);
- mayParseFunctionExpressions = old;
- return token;
- }
- }
-
- Token parseParenthesizedExpression(Token token) {
- // We expect [begin] to be of type [BeginGroupToken], but we don't know for
- // sure until after calling expect.
- var begin = token;
- token = expect('(', token);
- // [begin] is now known to have type [BeginGroupToken].
- token = parseExpression(token);
- if (!identical(begin.endGroup, token)) {
- listener.unexpected(token);
- token = begin.endGroup;
- }
- listener.handleParenthesizedExpression(begin);
- return expect(')', token);
- }
-
- Token parseThisExpression(Token token) {
- listener.handleThisExpression(token);
- token = token.next;
- if (optional('(', token)) {
- // Constructor forwarding.
- token = parseArguments(token);
- listener.endSend(token);
- }
- return token;
- }
-
- Token parseSuperExpression(Token token) {
- listener.handleSuperExpression(token);
- token = token.next;
- if (optional('(', token)) {
- // Super constructor.
- token = parseArguments(token);
- listener.endSend(token);
- }
- return token;
- }
-
- Token parseLiteralListOrMap(Token token) {
- Token constKeyword = null;
- if (optional('const', token)) {
- constKeyword = token;
- token = token.next;
- }
- token = parseTypeArgumentsOpt(token);
- Token beginToken = token;
- int count = 0;
- if (optional('{', token)) {
- bool old = mayParseFunctionExpressions;
- mayParseFunctionExpressions = true;
- do {
- if (optional('}', token.next)) {
- token = token.next;
- break;
- }
- token = parseMapLiteralEntry(token.next);
- ++count;
- } while (optional(',', token));
- mayParseFunctionExpressions = old;
- listener.handleLiteralMap(count, beginToken, constKeyword, token);
- return expect('}', token);
- } else if (optional('[', token)) {
- bool old = mayParseFunctionExpressions;
- mayParseFunctionExpressions = true;
- do {
- if (optional(']', token.next)) {
- token = token.next;
- break;
- }
- token = parseExpression(token.next);
- ++count;
- } while (optional(',', token));
- mayParseFunctionExpressions = old;
- listener.handleLiteralList(count, beginToken, constKeyword, token);
- return expect(']', token);
- } else if (optional('[]', token)) {
- listener.handleLiteralList(0, token, constKeyword, token);
- return token.next;
- } else {
- listener.unexpected(token);
- return null;
- }
- }
-
- Token parseMapLiteralEntry(Token token) {
- listener.beginLiteralMapEntry(token);
- // Assume the listener rejects non-string keys.
- token = parseExpression(token);
- Token colon = token;
- token = expect(':', token);
- token = parseExpression(token);
- listener.endLiteralMapEntry(colon, token);
- return token;
- }
-
- Token parseSendOrFunctionLiteral(Token token) {
- if (!mayParseFunctionExpressions) return parseSend(token);
- Token peek = peekAfterIfType(token);
- if (peek != null &&
- identical(peek.kind, IDENTIFIER_TOKEN) &&
- isFunctionDeclaration(peek.next)) {
- return parseFunctionExpression(token);
- } else if (isFunctionDeclaration(token.next)) {
- return parseFunctionExpression(token);
- } else {
- return parseSend(token);
- }
- }
-
- bool isFunctionDeclaration(Token token) {
- if (optional('(', token)) {
- BeginGroupToken begin = token;
- String afterParens = begin.endGroup.next.stringValue;
- if (identical(afterParens, '{') ||
- identical(afterParens, '=>') ||
- identical(afterParens, 'async') ||
- identical(afterParens, 'sync')) {
- return true;
- }
- }
- return false;
- }
-
- Token parseRequiredArguments(Token token) {
- if (optional('(', token)) {
- token = parseArguments(token);
- } else {
- listener.handleNoArguments(token);
- token = listener.unexpected(token);
- }
- return token;
- }
-
- Token parseNewExpression(Token token) {
- Token newKeyword = token;
- token = expect('new', token);
- token = parseConstructorReference(token);
- token = parseRequiredArguments(token);
- listener.handleNewExpression(newKeyword);
- return token;
- }
-
- Token parseConstExpression(Token token) {
- Token constKeyword = token;
- token = expect('const', token);
- final String value = token.stringValue;
- if ((identical(value, '<')) ||
- (identical(value, '[')) ||
- (identical(value, '[]')) ||
- (identical(value, '{'))) {
- return parseLiteralListOrMap(constKeyword);
- }
- token = parseConstructorReference(token);
- token = parseRequiredArguments(token);
- listener.handleConstExpression(constKeyword);
- return token;
- }
-
- Token parseLiteralInt(Token token) {
- listener.handleLiteralInt(token);
- return token.next;
- }
-
- Token parseLiteralDouble(Token token) {
- listener.handleLiteralDouble(token);
- return token.next;
- }
-
- Token parseLiteralString(Token token) {
- bool old = mayParseFunctionExpressions;
- mayParseFunctionExpressions = true;
- token = parseSingleLiteralString(token);
- int count = 1;
- while (identical(token.kind, STRING_TOKEN)) {
- token = parseSingleLiteralString(token);
- count++;
- }
- if (count > 1) {
- listener.handleStringJuxtaposition(count);
- }
- mayParseFunctionExpressions = old;
- return token;
- }
-
- Token parseLiteralSymbol(Token token) {
- Token hashToken = token;
- listener.beginLiteralSymbol(hashToken);
- token = token.next;
- if (isUserDefinableOperator(token.stringValue)) {
- listener.handleOperator(token);
- listener.endLiteralSymbol(hashToken, 1);
- return token.next;
- } else {
- int count = 1;
- token = parseIdentifier(token);
- while (identical(token.stringValue, '.')) {
- count++;
- token = parseIdentifier(token.next);
- }
- listener.endLiteralSymbol(hashToken, count);
- return token;
- }
- }
-
- /**
- * Only called when [:token.kind === STRING_TOKEN:].
- */
- Token parseSingleLiteralString(Token token) {
- listener.beginLiteralString(token);
- // Parsing the prefix, for instance 'x of 'x${id}y${id}z'
- token = token.next;
- int interpolationCount = 0;
- var kind = token.kind;
- while (kind != EOF_TOKEN) {
- if (identical(kind, STRING_INTERPOLATION_TOKEN)) {
- // Parsing ${expression}.
- token = token.next;
- token = parseExpression(token);
- token = expect('}', token);
- } else if (identical(kind, STRING_INTERPOLATION_IDENTIFIER_TOKEN)) {
- // Parsing $identifier.
- token = token.next;
- token = parseExpression(token);
- } else {
- break;
- }
- ++interpolationCount;
- // Parsing the infix/suffix, for instance y and z' of 'x${id}y${id}z'
- token = parseStringPart(token);
- kind = token.kind;
- }
- listener.endLiteralString(interpolationCount);
- return token;
- }
-
- Token parseLiteralBool(Token token) {
- listener.handleLiteralBool(token);
- return token.next;
- }
-
- Token parseLiteralNull(Token token) {
- listener.handleLiteralNull(token);
- return token.next;
- }
-
- Token parseSend(Token token) {
- listener.beginSend(token);
- token = parseIdentifier(token);
- token = parseArgumentsOpt(token);
- listener.endSend(token);
- return token;
- }
-
- Token parseArgumentsOpt(Token token) {
- if (!optional('(', token)) {
- listener.handleNoArguments(token);
- return token;
- } else {
- return parseArguments(token);
- }
- }
-
- Token parseArguments(Token token) {
- Token begin = token;
- listener.beginArguments(begin);
- assert(identical('(', token.stringValue));
- int argumentCount = 0;
- if (optional(')', token.next)) {
- listener.endArguments(argumentCount, begin, token.next);
- return token.next.next;
- }
- bool old = mayParseFunctionExpressions;
- mayParseFunctionExpressions = true;
- do {
- Token colon = null;
- if (optional(':', token.next.next)) {
- token = parseIdentifier(token.next);
- colon = token;
- }
- token = parseExpression(token.next);
- if (colon != null) listener.handleNamedArgument(colon);
- ++argumentCount;
- } while (optional(',', token));
- mayParseFunctionExpressions = old;
- listener.endArguments(argumentCount, begin, token);
- return expect(')', token);
- }
-
- Token parseIsOperatorRest(Token token) {
- assert(optional('is', token));
- Token operator = token;
- Token not = null;
- if (optional('!', token.next)) {
- token = token.next;
- not = token;
- }
- token = parseType(token.next);
- listener.handleIsOperator(operator, not, token);
- String value = token.stringValue;
- if (identical(value, 'is') || identical(value, 'as')) {
- // The is- and as-operators cannot be chained, but they can take part of
- // expressions like: foo is Foo || foo is Bar.
- listener.unexpected(token);
- }
- return token;
- }
-
- Token parseAsOperatorRest(Token token) {
- assert(optional('as', token));
- Token operator = token;
- token = parseType(token.next);
- listener.handleAsOperator(operator, token);
- String value = token.stringValue;
- if (identical(value, 'is') || identical(value, 'as')) {
- // The is- and as-operators cannot be chained.
- listener.unexpected(token);
- }
- return token;
- }
-
- Token parseVariablesDeclaration(Token token) {
- return parseVariablesDeclarationMaybeSemicolon(token, true);
- }
-
- Token parseVariablesDeclarationNoSemicolon(Token token) {
- // Only called when parsing a for loop, so this is for parsing locals.
- return parseVariablesDeclarationMaybeSemicolon(token, false);
- }
-
- Token parseVariablesDeclarationMaybeSemicolon(Token token,
- bool endWithSemicolon) {
- int count = 1;
- listener.beginVariablesDeclaration(token);
- token = parseModifiers(token);
- token = parseTypeOpt(token);
- token = parseOptionallyInitializedIdentifier(token);
- while (optional(',', token)) {
- token = parseOptionallyInitializedIdentifier(token.next);
- ++count;
- }
- if (endWithSemicolon) {
- Token semicolon = token;
- token = expectSemicolon(semicolon);
- listener.endVariablesDeclaration(count, semicolon);
- return token;
- } else {
- listener.endVariablesDeclaration(count, null);
- return token;
- }
- }
-
- Token parseOptionallyInitializedIdentifier(Token token) {
- listener.beginInitializedIdentifier(token);
- token = parseIdentifier(token);
- token = parseVariableInitializerOpt(token);
- listener.endInitializedIdentifier();
- return token;
- }
-
- Token parseIfStatement(Token token) {
- Token ifToken = token;
- listener.beginIfStatement(ifToken);
- token = expect('if', token);
- token = parseParenthesizedExpression(token);
- token = parseStatement(token);
- Token elseToken = null;
- if (optional('else', token)) {
- elseToken = token;
- token = parseStatement(token.next);
- }
- listener.endIfStatement(ifToken, elseToken);
- return token;
- }
-
- Token parseForStatement(Token awaitToken, Token token) {
- Token forToken = token;
- listener.beginForStatement(forToken);
- token = expect('for', token);
- token = expect('(', token);
- token = parseVariablesDeclarationOrExpressionOpt(token);
- if (optional('in', token)) {
- return parseForInRest(awaitToken, forToken, token);
- } else {
- if (awaitToken != null) {
- listener.reportError(awaitToken, MessageKind.INVALID_AWAIT_FOR);
- }
- return parseForRest(forToken, token);
- }
- }
-
- Token parseVariablesDeclarationOrExpressionOpt(Token token) {
- final String value = token.stringValue;
- if (identical(value, ';')) {
- listener.handleNoExpression(token);
- return token;
- } else if ((identical(value, 'var')) || (identical(value, 'final'))) {
- return parseVariablesDeclarationNoSemicolon(token);
- }
- Token identifier = peekIdentifierAfterType(token);
- if (identifier != null) {
- assert(identifier.isIdentifier());
- if (isOneOf4(identifier.next, '=', ';', ',', 'in')) {
- return parseVariablesDeclarationNoSemicolon(token);
- }
- }
- return parseExpression(token);
- }
-
- Token parseForRest(Token forToken, Token token) {
- token = expectSemicolon(token);
- if (optional(';', token)) {
- token = parseEmptyStatement(token);
- } else {
- token = parseExpressionStatement(token);
- }
- int expressionCount = 0;
- while (true) {
- if (optional(')', token)) break;
- token = parseExpression(token);
- ++expressionCount;
- if (optional(',', token)) {
- token = token.next;
- } else {
- break;
- }
- }
- token = expect(')', token);
- token = parseStatement(token);
- listener.endForStatement(expressionCount, forToken, token);
- return token;
- }
-
- Token parseForInRest(Token awaitToken, Token forToken, Token token) {
- assert(optional('in', token));
- Token inKeyword = token;
- token = parseExpression(token.next);
- token = expect(')', token);
- token = parseStatement(token);
- listener.endForIn(awaitToken, forToken, inKeyword, token);
- return token;
- }
-
- Token parseWhileStatement(Token token) {
- Token whileToken = token;
- listener.beginWhileStatement(whileToken);
- token = expect('while', token);
- token = parseParenthesizedExpression(token);
- token = parseStatement(token);
- listener.endWhileStatement(whileToken, token);
- return token;
- }
-
- Token parseDoWhileStatement(Token token) {
- Token doToken = token;
- listener.beginDoWhileStatement(doToken);
- token = expect('do', token);
- token = parseStatement(token);
- Token whileToken = token;
- token = expect('while', token);
- token = parseParenthesizedExpression(token);
- listener.endDoWhileStatement(doToken, whileToken, token);
- return expectSemicolon(token);
- }
-
- Token parseBlock(Token token) {
- Token begin = token;
- listener.beginBlock(begin);
- int statementCount = 0;
- token = expect('{', token);
- while (notEofOrValue('}', token)) {
- token = parseStatement(token);
- ++statementCount;
- }
- listener.endBlock(statementCount, begin, token);
- return expect('}', token);
- }
-
- Token parseAwaitExpression(Token token, bool allowCascades) {
- Token awaitToken = token;
- listener.beginAwaitExpression(awaitToken);
- token = expect('await', token);
- token = parseUnaryExpression(token, allowCascades);
- listener.endAwaitExpression(awaitToken, token);
- return token;
- }
-
- Token parseThrowExpression(Token token, bool allowCascades) {
- Token throwToken = token;
- listener.beginThrowExpression(throwToken);
- token = expect('throw', token);
- token = allowCascades
- ? parseExpression(token)
- : parseExpressionWithoutCascade(token);
- listener.endThrowExpression(throwToken, token);
- return token;
- }
-
- Token parseRethrowStatement(Token token) {
- Token throwToken = token;
- listener.beginRethrowStatement(throwToken);
- // TODO(kasperl): Disallow throw here.
- if (identical(throwToken.stringValue, 'throw')) {
- token = expect('throw', token);
- } else {
- token = expect('rethrow', token);
- }
- listener.endRethrowStatement(throwToken, token);
- return expectSemicolon(token);
- }
-
- Token parseTryStatement(Token token) {
- assert(optional('try', token));
- Token tryKeyword = token;
- listener.beginTryStatement(tryKeyword);
- token = parseBlock(token.next);
- int catchCount = 0;
-
- String value = token.stringValue;
- while (identical(value, 'catch') || identical(value, 'on')) {
- var onKeyword = null;
- if (identical(value, 'on')) {
- // on qualified catchPart?
- onKeyword = token;
- token = parseType(token.next);
- value = token.stringValue;
- }
- Token catchKeyword = null;
- if (identical(value, 'catch')) {
- catchKeyword = token;
- // TODO(ahe): Validate the "parameters".
- token = parseFormalParameters(token.next);
- }
- token = parseBlock(token);
- ++catchCount;
- listener.handleCatchBlock(onKeyword, catchKeyword);
- value = token.stringValue; // while condition
- }
-
- Token finallyKeyword = null;
- if (optional('finally', token)) {
- finallyKeyword = token;
- token = parseBlock(token.next);
- listener.handleFinallyBlock(finallyKeyword);
- }
- listener.endTryStatement(catchCount, tryKeyword, finallyKeyword);
- return token;
- }
-
- Token parseSwitchStatement(Token token) {
- assert(optional('switch', token));
- Token switchKeyword = token;
- listener.beginSwitchStatement(switchKeyword);
- token = parseParenthesizedExpression(token.next);
- token = parseSwitchBlock(token);
- listener.endSwitchStatement(switchKeyword, token);
- return token.next;
- }
-
- Token parseSwitchBlock(Token token) {
- Token begin = token;
- listener.beginSwitchBlock(begin);
- token = expect('{', token);
- int caseCount = 0;
- while (!identical(token.kind, EOF_TOKEN)) {
- if (optional('}', token)) {
- break;
- }
- token = parseSwitchCase(token);
- ++caseCount;
- }
- listener.endSwitchBlock(caseCount, begin, token);
- expect('}', token);
- return token;
- }
-
- /**
- * Peek after the following labels (if any). The following token
- * is used to determine if the labels belong to a statement or a
- * switch case.
- */
- Token peekPastLabels(Token token) {
- while (token.isIdentifier() && optional(':', token.next)) {
- token = token.next.next;
- }
- return token;
- }
-
- /**
- * Parse a group of labels, cases and possibly a default keyword and
- * the statements that they select.
- */
- Token parseSwitchCase(Token token) {
- Token begin = token;
- Token defaultKeyword = null;
- int expressionCount = 0;
- int labelCount = 0;
- Token peek = peekPastLabels(token);
- while (true) {
- // Loop until we find something that can't be part of a switch case.
- String value = peek.stringValue;
- if (identical(value, 'default')) {
- while (!identical(token, peek)) {
- token = parseLabel(token);
- labelCount++;
- }
- defaultKeyword = token;
- token = expect(':', token.next);
- peek = token;
- break;
- } else if (identical(value, 'case')) {
- while (!identical(token, peek)) {
- token = parseLabel(token);
- labelCount++;
- }
- Token caseKeyword = token;
- token = parseExpression(token.next);
- Token colonToken = token;
- token = expect(':', token);
- listener.handleCaseMatch(caseKeyword, colonToken);
- expressionCount++;
- peek = peekPastLabels(token);
- } else {
- if (expressionCount == 0) {
- listener.expected("case", token);
- }
- break;
- }
- }
- // Finally zero or more statements.
- int statementCount = 0;
- while (!identical(token.kind, EOF_TOKEN)) {
- String value = peek.stringValue;
- if ((identical(value, 'case')) ||
- (identical(value, 'default')) ||
- ((identical(value, '}')) && (identical(token, peek)))) {
- // A label just before "}" will be handled as a statement error.
- break;
- } else {
- token = parseStatement(token);
- }
- statementCount++;
- peek = peekPastLabels(token);
- }
- listener.handleSwitchCase(labelCount, expressionCount, defaultKeyword,
- statementCount, begin, token);
- return token;
- }
-
- Token parseBreakStatement(Token token) {
- assert(optional('break', token));
- Token breakKeyword = token;
- token = token.next;
- bool hasTarget = false;
- if (token.isIdentifier()) {
- token = parseIdentifier(token);
- hasTarget = true;
- }
- listener.handleBreakStatement(hasTarget, breakKeyword, token);
- return expectSemicolon(token);
- }
-
- Token parseAssertStatement(Token token) {
- Token assertKeyword = token;
- token = expect('assert', token);
- expect('(', token);
- token = parseArguments(token);
- listener.handleAssertStatement(assertKeyword, token);
- return expectSemicolon(token);
- }
-
- Token parseContinueStatement(Token token) {
- assert(optional('continue', token));
- Token continueKeyword = token;
- token = token.next;
- bool hasTarget = false;
- if (token.isIdentifier()) {
- token = parseIdentifier(token);
- hasTarget = true;
- }
- listener.handleContinueStatement(hasTarget, continueKeyword, token);
- return expectSemicolon(token);
- }
-
- Token parseEmptyStatement(Token token) {
- listener.handleEmptyStatement(token);
- return expectSemicolon(token);
- }
-}

Powered by Google App Engine
This is Rietveld 408576698