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

Unified Diff: pkg/compiler/lib/src/parser/element_listener.dart

Issue 1311783012: Split parser/listener.dart, parser/class_element_listener.dart and tokens/token.dart into smaller l… (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Created 5 years, 3 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: pkg/compiler/lib/src/parser/element_listener.dart
diff --git a/pkg/compiler/lib/src/parser/element_listener.dart b/pkg/compiler/lib/src/parser/element_listener.dart
index 145264193a261e5d5027e7b42d86fad0e4548b78..00ec535ea92748c46ced28bd7b7369f16dd2370c 100644
--- a/pkg/compiler/lib/src/parser/element_listener.dart
+++ b/pkg/compiler/lib/src/parser/element_listener.dart
@@ -1,2673 +1,755 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// Copyright (c) 2015, 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.
-library dart2js.parser.listener;
+library dart2js.parser.element_listener;
-import '../compiler.dart' show
- Compiler;
-import '../dart_types.dart' show DynamicType;
import '../diagnostics/diagnostic_listener.dart';
-import '../diagnostics/invariant.dart' show
- invariant;
import '../diagnostics/messages.dart';
import '../diagnostics/spannable.dart' show
- Spannable,
- SpannableAssertionFailure;
+ Spannable;
import '../elements/elements.dart' show
- CompilationUnitElement,
- ConstructorElement,
Element,
- ElementKind,
- GetterElement,
LibraryElement,
- MetadataAnnotation,
- MethodElement,
- SetterElement;
+ MetadataAnnotation;
import '../elements/modelx.dart' show
- BaseFunctionElementX,
- ConstructorElementX,
CompilationUnitElementX,
DeclarationSite,
ElementX,
EnumClassElementX,
FieldElementX,
- GetterElementX,
LibraryElementX,
- MetadataAnnotationX,
- MethodElementX,
MixinApplicationElementX,
- SetterElementX,
- TypedefElementX,
VariableList;
import '../native/native.dart' as native;
import '../string_validator.dart' show
StringValidator;
import '../tokens/keyword.dart' show
Keyword;
+import '../tokens/precedence_constants.dart' as Precedence show
+ BAD_INPUT_INFO;
import '../tokens/token.dart' show
- BAD_INPUT_INFO,
- BadInputToken,
BeginGroupToken,
- EOF_INFO,
- EOF_TOKEN,
ErrorToken,
- IDENTIFIER_INFO,
- INDEX_INFO,
KeywordToken,
- StringToken,
- Token,
- UnmatchedToken,
- UnterminatedToken;
+ Token;
+import '../tokens/token_constants.dart' as Tokens show
+ EOF_TOKEN;
import '../tree/tree.dart';
import '../util/util.dart' show
Link;
-import 'class_element_parser.dart' show
- PartialClassElement;
-import 'parser.dart' show
- Parser;
+import 'partial_elements.dart' show
+ PartialClassElement,
+ PartialElement,
+ PartialFieldList,
+ PartialFunctionElement,
+ PartialMetadataAnnotation,
+ PartialTypedefElement;
+import 'listener.dart' show
+ closeBraceFor,
+ Listener,
+ ParserError,
+ VERBOSE;
-const bool VERBOSE = false;
+typedef int IdGenerator();
/**
- * A parser event listener that does nothing except throw exceptions
- * on parser errors.
+ * A parser event listener designed to work with [PartialParser]. It
+ * builds elements representing the top-level declarations found in
+ * the parsed compilation unit and records them in
+ * [compilationUnitElement].
*/
-class Listener {
- set suppressParseErrors(bool value) {
- }
+class ElementListener extends Listener {
+ final IdGenerator idGenerator;
+ final DiagnosticListener listener;
+ final CompilationUnitElementX compilationUnitElement;
+ final StringValidator stringValidator;
+ Link<StringQuoting> interpolationScope;
- void beginArguments(Token token) {
- }
+ Link<Node> nodes = const Link<Node>();
- void endArguments(int count, Token beginToken, Token endToken) {
- }
+ Link<MetadataAnnotation> metadata = const Link<MetadataAnnotation>();
- /// Handle async modifiers `async`, `async*`, `sync`.
- void handleAsyncModifier(Token asyncToken, Token startToken) {
- }
+ /// Records a stack of booleans for each member parsed (a stack is used to
+ /// support nested members which isn't currently possible, but it also serves
+ /// as a simple way to tell we're currently parsing a member). In this case,
+ /// member refers to members of a library or a class (but currently, classes
+ /// themselves are not considered members). If the top of the stack
+ /// (memberErrors.head) is true, the current member has already reported at
+ /// least one parse error.
+ Link<bool> memberErrors = const Link<bool>();
- void beginAwaitExpression(Token token) {
- }
+ bool suppressParseErrors = false;
- void endAwaitExpression(Token beginToken, Token endToken) {
- }
+ ElementListener(
+ DiagnosticListener listener,
+ this.compilationUnitElement,
+ this.idGenerator)
+ : this.listener = listener,
+ stringValidator = new StringValidator(listener),
+ interpolationScope = const Link<StringQuoting>();
- void beginBlock(Token token) {
+ bool get currentMemberHasParseError {
+ return !memberErrors.isEmpty && memberErrors.head;
}
- void endBlock(int count, Token beginToken, Token endToken) {
+ void pushQuoting(StringQuoting quoting) {
+ interpolationScope = interpolationScope.prepend(quoting);
}
- void beginCascade(Token token) {
+ StringQuoting popQuoting() {
+ StringQuoting result = interpolationScope.head;
+ interpolationScope = interpolationScope.tail;
+ return result;
}
- void endCascade() {
+ StringNode popLiteralString() {
+ StringNode node = popNode();
+ // TODO(lrn): Handle interpolations in script tags.
+ if (node.isInterpolation) {
+ listener.internalError(node,
+ "String interpolation not supported in library tags.");
+ return null;
+ }
+ return node;
}
- void beginClassBody(Token token) {
+ bool allowLibraryTags() {
+ // Library tags are only allowed in the library file itself, not
+ // in sourced files.
+ LibraryElement library = compilationUnitElement.implementationLibrary;
+ return !compilationUnitElement.hasMembers &&
+ library.entryCompilationUnit == compilationUnitElement;
}
- void endClassBody(int memberCount, Token beginToken, Token endToken) {
+ void endLibraryName(Token libraryKeyword, Token semicolon) {
+ Expression name = popNode();
+ addLibraryTag(new LibraryName(libraryKeyword, name,
+ popMetadata(compilationUnitElement)));
}
- void beginClassDeclaration(Token token) {
+ void endImport(Token importKeyword, Token deferredKeyword, Token asKeyword,
+ Token semicolon) {
+ NodeList combinators = popNode();
+ bool isDeferred = deferredKeyword != null;
+ Identifier prefix;
+ if (asKeyword != null) {
+ prefix = popNode();
+ }
+ StringNode uri = popLiteralString();
+ addLibraryTag(new Import(importKeyword, uri, prefix, combinators,
+ popMetadata(compilationUnitElement),
+ isDeferred: isDeferred));
}
- void endClassDeclaration(int interfacesCount, Token beginToken,
- Token extendsKeyword, Token implementsKeyword,
- Token endToken) {
+ void endEnum(Token enumKeyword, Token endBrace, int count) {
+ NodeList names = makeNodeList(count, enumKeyword.next.next, endBrace, ",");
+ Identifier name = popNode();
+
+ int id = idGenerator();
+ Element enclosing = compilationUnitElement;
+ pushElement(new EnumClassElementX(name.source, enclosing, id,
+ new Enum(enumKeyword, name, names)));
+ rejectBuiltInIdentifier(name);
}
- void beginCombinators(Token token) {
+ void endExport(Token exportKeyword, Token semicolon) {
+ NodeList combinators = popNode();
+ StringNode uri = popNode();
+ addLibraryTag(new Export(exportKeyword, uri, combinators,
+ popMetadata(compilationUnitElement)));
}
void endCombinators(int count) {
+ if (0 == count) {
+ pushNode(null);
+ } else {
+ pushNode(makeNodeList(count, null, null, " "));
+ }
}
- void beginCompilationUnit(Token token) {
- }
+ void endHide(Token hideKeyword) => pushCombinator(hideKeyword);
- void endCompilationUnit(int count, Token token) {
- }
+ void endShow(Token showKeyword) => pushCombinator(showKeyword);
- void beginConstructorReference(Token start) {
+ void pushCombinator(Token keywordToken) {
+ NodeList identifiers = popNode();
+ pushNode(new Combinator(identifiers, keywordToken));
}
- void endConstructorReference(Token start, Token periodBeforeName,
- Token endToken) {
+ void endIdentifierList(int count) {
+ pushNode(makeNodeList(count, null, null, ","));
}
- void beginDoWhileStatement(Token token) {
+ void endTypeList(int count) {
+ pushNode(makeNodeList(count, null, null, ","));
}
- void endDoWhileStatement(Token doKeyword, Token whileKeyword,
- Token endToken) {
+ void endPart(Token partKeyword, Token semicolon) {
+ StringNode uri = popLiteralString();
+ addLibraryTag(new Part(partKeyword, uri,
+ popMetadata(compilationUnitElement)));
}
- void beginEnum(Token enumKeyword) {
+ void endPartOf(Token partKeyword, Token semicolon) {
+ Expression name = popNode();
+ addPartOfTag(new PartOf(partKeyword, name,
+ popMetadata(compilationUnitElement)));
}
- void endEnum(Token enumKeyword, Token endBrace, int count) {
+ void addPartOfTag(PartOf tag) {
+ compilationUnitElement.setPartOf(tag, listener);
}
- void beginExport(Token token) {
+ void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
+ if (periodBeforeName != null) {
+ popNode(); // Discard name.
+ }
+ popNode(); // Discard node (Send or Identifier).
+ pushMetadata(new PartialMetadataAnnotation(beginToken, endToken));
}
- void endExport(Token exportKeyword, Token semicolon) {
+ void endTopLevelDeclaration(Token token) {
+ if (!metadata.isEmpty) {
+ recoverableError(metadata.head.beginToken,
+ 'Metadata not supported here.');
+ metadata = const Link<MetadataAnnotation>();
+ }
}
- void beginExpressionStatement(Token token) {
+ void endClassDeclaration(int interfacesCount, Token beginToken,
+ Token extendsKeyword, Token implementsKeyword,
+ Token endToken) {
+ makeNodeList(interfacesCount, implementsKeyword, null, ","); // interfaces
+ popNode(); // superType
+ popNode(); // typeParameters
+ Identifier name = popNode();
+ int id = idGenerator();
+ PartialClassElement element = new PartialClassElement(
+ name.source, beginToken, endToken, compilationUnitElement, id);
+ pushElement(element);
+ rejectBuiltInIdentifier(name);
}
- void endExpressionStatement(Token token) {
+ void rejectBuiltInIdentifier(Identifier name) {
+ if (name.token is KeywordToken) {
+ Keyword keyword = (name.token as KeywordToken).keyword;
+ if (!keyword.isPseudo) {
+ recoverableError(name, "Illegal name '${keyword.syntax}'.");
+ }
+ }
}
- void beginFactoryMethod(Token token) {
+ void endFunctionTypeAlias(Token typedefKeyword, Token endToken) {
+ popNode(); // TODO(karlklose): do not throw away typeVariables.
+ Identifier name = popNode();
+ popNode(); // returnType
+ pushElement(
+ new PartialTypedefElement(
+ name.source, compilationUnitElement, typedefKeyword, endToken));
+ rejectBuiltInIdentifier(name);
}
- void endFactoryMethod(Token beginToken, Token endToken) {
- }
+ void endNamedMixinApplication(Token classKeyword,
+ Token implementsKeyword,
+ Token endToken) {
+ NodeList interfaces = (implementsKeyword != null) ? popNode() : null;
+ MixinApplication mixinApplication = popNode();
+ Modifiers modifiers = popNode();
+ NodeList typeParameters = popNode();
+ Identifier name = popNode();
+ NamedMixinApplication namedMixinApplication = new NamedMixinApplication(
+ name, typeParameters, modifiers, mixinApplication, interfaces,
+ classKeyword, endToken);
- void beginFormalParameter(Token token) {
+ int id = idGenerator();
+ Element enclosing = compilationUnitElement;
+ pushElement(new MixinApplicationElementX(name.source, enclosing, id,
+ namedMixinApplication,
+ modifiers));
+ rejectBuiltInIdentifier(name);
}
- void endFormalParameter(Token thisKeyword) {
+ void endMixinApplication() {
+ NodeList mixins = popNode();
+ TypeAnnotation superclass = popNode();
+ pushNode(new MixinApplication(superclass, mixins));
}
- void handleNoFormalParameters(Token token) {
+ void handleVoidKeyword(Token token) {
+ pushNode(new TypeAnnotation(new Identifier(token), null));
}
- void beginFormalParameters(Token token) {
+ void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
+ bool hasParseError = currentMemberHasParseError;
+ memberErrors = memberErrors.tail;
+ Identifier name = popNode();
+ popNode(); // type
+ Modifiers modifiers = popNode();
+ PartialFunctionElement element = new PartialFunctionElement(
+ name.source, beginToken, getOrSet, endToken,
+ modifiers, compilationUnitElement);
+ element.hasParseError = hasParseError;
+ pushElement(element);
}
- void endFormalParameters(int count, Token beginToken, Token endToken) {
+ void endTopLevelFields(int count, Token beginToken, Token endToken) {
+ bool hasParseError = currentMemberHasParseError;
+ memberErrors = memberErrors.tail;
+ void buildFieldElement(Identifier name, VariableList fields) {
+ pushElement(
+ new FieldElementX(name, compilationUnitElement, fields));
+ }
+ NodeList variables = makeNodeList(count, null, null, ",");
+ popNode(); // type
+ Modifiers modifiers = popNode();
+ buildFieldElements(modifiers, variables, compilationUnitElement,
+ buildFieldElement,
+ beginToken, endToken, hasParseError);
}
- void endFields(int count, Token beginToken, Token endToken) {
+ void buildFieldElements(Modifiers modifiers,
+ NodeList variables,
+ Element enclosingElement,
+ void buildFieldElement(Identifier name,
+ VariableList fields),
+ Token beginToken, Token endToken,
+ bool hasParseError) {
+ VariableList fields =
+ new PartialFieldList(beginToken, endToken, modifiers, hasParseError);
+ for (Link<Node> variableNodes = variables.nodes;
+ !variableNodes.isEmpty;
+ variableNodes = variableNodes.tail) {
+ Expression initializedIdentifier = variableNodes.head;
+ Identifier identifier = initializedIdentifier.asIdentifier();
+ if (identifier == null) {
+ identifier = initializedIdentifier.asSendSet().selector.asIdentifier();
+ }
+ buildFieldElement(identifier, fields);
+ }
}
- void beginForStatement(Token token) {
+ void handleIdentifier(Token token) {
+ pushNode(new Identifier(token));
}
- void endForStatement(int updateExpressionCount,
- Token beginToken, Token endToken) {
+ void handleQualified(Token period) {
+ Identifier last = popNode();
+ Expression first = popNode();
+ pushNode(new Send(first, last));
}
- void endForIn(Token awaitToken, Token forToken,
- Token inKeyword, Token endToken) {
+ void handleNoType(Token token) {
+ pushNode(null);
}
- void beginFunction(Token token) {
+ void endTypeVariable(Token token) {
+ TypeAnnotation bound = popNode();
+ Identifier name = popNode();
+ pushNode(new TypeVariable(name, bound));
+ rejectBuiltInIdentifier(name);
}
- void endFunction(Token getOrSet, Token endToken) {
+ void endTypeVariables(int count, Token beginToken, Token endToken) {
+ pushNode(makeNodeList(count, beginToken, endToken, ','));
}
- void beginFunctionDeclaration(Token token) {
+ void handleNoTypeVariables(token) {
+ pushNode(null);
}
- void endFunctionDeclaration(Token token) {
+ void endTypeArguments(int count, Token beginToken, Token endToken) {
+ pushNode(makeNodeList(count, beginToken, endToken, ','));
}
- void beginFunctionBody(Token token) {
+ void handleNoTypeArguments(Token token) {
+ pushNode(null);
}
- void endFunctionBody(int count, Token beginToken, Token endToken) {
+ void endType(Token beginToken, Token endToken) {
+ NodeList typeArguments = popNode();
+ Expression typeName = popNode();
+ pushNode(new TypeAnnotation(typeName, typeArguments));
}
- void handleNoFunctionBody(Token token) {
+ void handleParenthesizedExpression(BeginGroupToken token) {
+ Expression expression = popNode();
+ pushNode(new ParenthesizedExpression(expression, token));
}
- void skippedFunctionBody(Token token) {
- }
-
- void beginFunctionName(Token token) {
- }
-
- void endFunctionName(Token token) {
- }
-
- void beginFunctionTypeAlias(Token token) {
- }
-
- void endFunctionTypeAlias(Token typedefKeyword, Token endToken) {
- }
-
- void beginMixinApplication(Token token) {
- }
-
- void endMixinApplication() {
- }
-
- void beginNamedMixinApplication(Token token) {
- }
-
- void endNamedMixinApplication(Token classKeyword,
- Token implementsKeyword,
- Token endToken) {
- }
-
- void beginHide(Token hideKeyword) {
- }
-
- void endHide(Token hideKeyword) {
- }
-
- void beginIdentifierList(Token token) {
- }
-
- void endIdentifierList(int count) {
- }
-
- void beginTypeList(Token token) {
- }
-
- void endTypeList(int count) {
- }
-
- void beginIfStatement(Token token) {
- }
-
- void endIfStatement(Token ifToken, Token elseToken) {
- }
-
- void beginImport(Token importKeyword) {
- }
-
- void endImport(Token importKeyword, Token DeferredKeyword,
- Token asKeyword, Token semicolon) {
- }
-
- void beginInitializedIdentifier(Token token) {
- }
-
- void endInitializedIdentifier() {
- }
-
- void beginInitializer(Token token) {
- }
-
- void endInitializer(Token assignmentOperator) {
- }
-
- void beginInitializers(Token token) {
- }
-
- void endInitializers(int count, Token beginToken, Token endToken) {
- }
-
- void handleNoInitializers() {
- }
-
- void handleLabel(Token token) {
- }
-
- void beginLabeledStatement(Token token, int labelCount) {
- }
-
- void endLabeledStatement(int labelCount) {
- }
-
- void beginLibraryName(Token token) {
- }
-
- void endLibraryName(Token libraryKeyword, Token semicolon) {
- }
-
- void beginLiteralMapEntry(Token token) {
- }
-
- void endLiteralMapEntry(Token colon, Token endToken) {
- }
-
- void beginLiteralString(Token token) {
- }
-
- void endLiteralString(int interpolationCount) {
- }
-
- void handleStringJuxtaposition(int literalCount) {
- }
-
- void beginMember(Token token) {
- }
-
- void endMethod(Token getOrSet, Token beginToken, Token endToken) {
- }
-
- void beginMetadataStar(Token token) {
- }
-
- void endMetadataStar(int count, bool forParameter) {
- }
-
- void beginMetadata(Token token) {
- }
-
- void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
- }
-
- void beginOptionalFormalParameters(Token token) {
- }
-
- void endOptionalFormalParameters(int count,
- Token beginToken, Token endToken) {
- }
-
- void beginPart(Token token) {
- }
-
- void endPart(Token partKeyword, Token semicolon) {
- }
-
- void beginPartOf(Token token) {
- }
-
- void endPartOf(Token partKeyword, Token semicolon) {
- }
-
- void beginRedirectingFactoryBody(Token token) {
- }
-
- void endRedirectingFactoryBody(Token beginToken, Token endToken) {
- }
-
- void beginReturnStatement(Token token) {
- }
-
- void endReturnStatement(bool hasExpression,
- Token beginToken, Token endToken) {
- }
-
- void beginSend(Token token) {
- }
-
- void endSend(Token token) {
- }
-
- void beginShow(Token showKeyword) {
- }
-
- void endShow(Token showKeyword) {
- }
-
- void beginSwitchStatement(Token token) {
- }
-
- void endSwitchStatement(Token switchKeyword, Token endToken) {
- }
-
- void beginSwitchBlock(Token token) {
- }
-
- void endSwitchBlock(int caseCount, Token beginToken, Token endToken) {
- }
-
- void beginLiteralSymbol(Token token) {
- }
-
- void endLiteralSymbol(Token hashToken, int identifierCount) {
- }
-
- void beginThrowExpression(Token token) {
- }
-
- void endThrowExpression(Token throwToken, Token endToken) {
- }
-
- void beginRethrowStatement(Token token) {
- }
-
- void endRethrowStatement(Token throwToken, Token endToken) {
- }
-
- void endTopLevelDeclaration(Token token) {
- }
-
- void beginTopLevelMember(Token token) {
- }
-
- void endTopLevelFields(int count, Token beginToken, Token endToken) {
- }
-
- void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
- }
-
- void beginTryStatement(Token token) {
- }
-
- void handleCaseMatch(Token caseKeyword, Token colon) {
- }
-
- void handleCatchBlock(Token onKeyword, Token catchKeyword) {
- }
-
- void handleFinallyBlock(Token finallyKeyword) {
- }
-
- void endTryStatement(int catchCount, Token tryKeyword, Token finallyKeyword) {
- }
-
- void endType(Token beginToken, Token endToken) {
- }
-
- void beginTypeArguments(Token token) {
- }
-
- void endTypeArguments(int count, Token beginToken, Token endToken) {
- }
-
- void handleNoTypeArguments(Token token) {
- }
-
- void beginTypeVariable(Token token) {
- }
-
- void endTypeVariable(Token token) {
- }
-
- void beginTypeVariables(Token token) {
- }
-
- void endTypeVariables(int count, Token beginToken, Token endToken) {
- }
-
- void beginUnnamedFunction(Token token) {
- }
-
- void endUnnamedFunction(Token token) {
- }
-
- void beginVariablesDeclaration(Token token) {
- }
-
- void endVariablesDeclaration(int count, Token endToken) {
- }
-
- void beginWhileStatement(Token token) {
- }
-
- void endWhileStatement(Token whileKeyword, Token endToken) {
- }
-
- void handleAsOperator(Token operathor, Token endToken) {
- // TODO(ahe): Rename [operathor] to "operator" when VM bug is fixed.
- }
-
- void handleAssignmentExpression(Token token) {
- }
-
- void handleBinaryExpression(Token token) {
- }
-
- void handleConditionalExpression(Token question, Token colon) {
- }
-
- void handleConstExpression(Token token) {
- }
-
- void handleFunctionTypedFormalParameter(Token token) {
- }
-
- void handleIdentifier(Token token) {
- }
-
- void handleIndexedExpression(Token openCurlyBracket,
- Token closeCurlyBracket) {
- }
-
- void handleIsOperator(Token operathor, Token not, Token endToken) {
- // TODO(ahe): Rename [operathor] to "operator" when VM bug is fixed.
- }
-
- void handleLiteralBool(Token token) {
- }
-
- void handleBreakStatement(bool hasTarget,
- Token breakKeyword, Token endToken) {
- }
-
- void handleContinueStatement(bool hasTarget,
- Token continueKeyword, Token endToken) {
- }
-
- void handleEmptyStatement(Token token) {
- }
-
- void handleAssertStatement(Token assertKeyword, Token semicolonToken) {
- }
-
- /** Called with either the token containing a double literal, or
- * an immediately preceding "unary plus" token.
- */
- void handleLiteralDouble(Token token) {
- }
-
- /** Called with either the token containing an integer literal,
- * or an immediately preceding "unary plus" token.
- */
- void handleLiteralInt(Token token) {
- }
-
- void handleLiteralList(int count, Token beginToken, Token constKeyword,
- Token endToken) {
- }
-
- void handleLiteralMap(int count, Token beginToken, Token constKeyword,
- Token endToken) {
- }
-
- void handleLiteralNull(Token token) {
- }
-
- void handleModifier(Token token) {
- }
-
- void handleModifiers(int count) {
- }
-
- void handleNamedArgument(Token colon) {
- }
-
- void handleNewExpression(Token token) {
- }
-
- void handleNoArguments(Token token) {
- }
-
- void handleNoExpression(Token token) {
- }
-
- void handleNoType(Token token) {
- }
-
- void handleNoTypeVariables(Token token) {
- }
-
- void handleOperator(Token token) {
- }
-
- void handleOperatorName(Token operatorKeyword, Token token) {
- }
-
- void handleParenthesizedExpression(BeginGroupToken token) {
- }
-
- void handleQualified(Token period) {
- }
-
- void handleStringPart(Token token) {
- }
-
- void handleSuperExpression(Token token) {
- }
-
- void handleSwitchCase(int labelCount, int expressionCount,
- Token defaultKeyword, int statementCount,
- Token firstToken, Token endToken) {
- }
-
- void handleThisExpression(Token token) {
- }
-
- void handleUnaryPostfixAssignmentExpression(Token token) {
- }
-
- void handleUnaryPrefixExpression(Token token) {
- }
-
- void handleUnaryPrefixAssignmentExpression(Token token) {
- }
-
- void handleValuedFormalParameter(Token equals, Token token) {
- }
-
- void handleVoidKeyword(Token token) {
- }
-
- void beginYieldStatement(Token token) {
- }
-
- void endYieldStatement(Token yieldToken, Token starToken, Token endToken) {
- }
-
- Token expected(String string, Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- error("expected '$string', but got '${token.value}'", token);
- }
- return skipToEof(token);
- }
-
- Token synthesizeIdentifier(Token token) {
- Token synthesizedToken =
- new StringToken.fromString(IDENTIFIER_INFO, '?', token.charOffset);
- synthesizedToken.next = token.next;
- return synthesizedToken;
- }
-
- Token expectedIdentifier(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- error("expected identifier, but got '${token.value}'", token);
- }
- return skipToEof(token);
- }
-
- Token expectedType(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- error("expected a type, but got '${token.value}'", token);
- }
- return skipToEof(token);
- }
-
- Token expectedExpression(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- error("expected an expression, but got '${token.value}'", token);
- }
- return skipToEof(token);
- }
-
- Token unexpected(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- error("unexpected token '${token.value}'", token);
- }
- return skipToEof(token);
- }
-
- Token expectedBlockToSkip(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- error("expected a block, but got '${token.value}'", token);
- }
- return skipToEof(token);
- }
-
- Token expectedFunctionBody(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- error("expected a function body, but got '${token.value}'", token);
- }
- return skipToEof(token);
- }
-
- Token expectedClassBody(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- error("expected a class body, but got '${token.value}'", token);
- }
- return skipToEof(token);
- }
-
- Token expectedClassBodyToSkip(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- error("expected a class body, but got '${token.value}'", token);
- }
- return skipToEof(token);
- }
-
- Token expectedDeclaration(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- error("expected a declaration, but got '${token.value}'", token);
- }
- return skipToEof(token);
- }
-
- Token unmatched(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- error("unmatched '${token.value}'", token);
- }
- return skipToEof(token);
- }
-
- skipToEof(Token token) {
- while (!identical(token.info, EOF_INFO)) {
- token = token.next;
- }
- return token;
- }
-
- void recoverableError(Token token, String message) {
- error(message, token);
- }
-
- void error(String message, Token token) {
- throw new ParserError("$message @ ${token.charOffset}");
- }
-
- void reportError(Spannable spannable,
- MessageKind messageKind,
- [Map arguments = const {}]) {
- MessageTemplate template = MessageTemplate.TEMPLATES[messageKind];
- String message = template.message(arguments, true).toString();
- Token token;
- if (spannable is Token) {
- token = spannable;
- } else if (spannable is Node) {
- token = spannable.getBeginToken();
- } else {
- throw new ParserError(message);
- }
- recoverableError(token, message);
- }
-
- void reportErrorToken(ErrorToken token) {
- if (token is BadInputToken) {
- String hex = token.character.toRadixString(16);
- if (hex.length < 4) {
- String padding = "0000".substring(hex.length);
- hex = "$padding$hex";
- }
- reportError(
- token, MessageKind.BAD_INPUT_CHARACTER, {'characterHex': hex});
- } else if (token is UnterminatedToken) {
- MessageKind kind;
- var arguments = const {};
- switch (token.start) {
- case '1e':
- kind = MessageKind.EXPONENT_MISSING;
- break;
- case '"':
- case "'":
- case '"""':
- case "'''":
- case 'r"':
- case "r'":
- case 'r"""':
- case "r'''":
- kind = MessageKind.UNTERMINATED_STRING;
- arguments = {'quote': token.start};
- break;
- case '0x':
- kind = MessageKind.HEX_DIGIT_EXPECTED;
- break;
- case r'$':
- kind = MessageKind.MALFORMED_STRING_LITERAL;
- break;
- case '/*':
- kind = MessageKind.UNTERMINATED_COMMENT;
- break;
- default:
- kind = MessageKind.UNTERMINATED_TOKEN;
- break;
- }
- reportError(token, kind, arguments);
- } else if (token is UnmatchedToken) {
- String begin = token.begin.value;
- String end = closeBraceFor(begin);
- reportError(
- token, MessageKind.UNMATCHED_TOKEN, {'begin': begin, 'end': end});
- } else {
- throw new SpannableAssertionFailure(token, token.assertionMessage);
- }
- }
-}
-
-String closeBraceFor(String openBrace) {
- return const {
- '(': ')',
- '[': ']',
- '{': '}',
- '<': '>',
- r'${': '}',
- }[openBrace];
-}
-
-class ParserError {
- final String reason;
- ParserError(this.reason);
- toString() => reason;
-}
-
-typedef int IdGenerator();
-
-/**
- * A parser event listener designed to work with [PartialParser]. It
- * builds elements representing the top-level declarations found in
- * the parsed compilation unit and records them in
- * [compilationUnitElement].
- */
-class ElementListener extends Listener {
- final IdGenerator idGenerator;
- final DiagnosticListener listener;
- final CompilationUnitElementX compilationUnitElement;
- final StringValidator stringValidator;
- Link<StringQuoting> interpolationScope;
-
- Link<Node> nodes = const Link<Node>();
-
- Link<MetadataAnnotation> metadata = const Link<MetadataAnnotation>();
-
- /// Records a stack of booleans for each member parsed (a stack is used to
- /// support nested members which isn't currently possible, but it also serves
- /// as a simple way to tell we're currently parsing a member). In this case,
- /// member refers to members of a library or a class (but currently, classes
- /// themselves are not considered members). If the top of the stack
- /// (memberErrors.head) is true, the current member has already reported at
- /// least one parse error.
- Link<bool> memberErrors = const Link<bool>();
-
- bool suppressParseErrors = false;
-
- ElementListener(
- DiagnosticListener listener,
- this.compilationUnitElement,
- this.idGenerator)
- : this.listener = listener,
- stringValidator = new StringValidator(listener),
- interpolationScope = const Link<StringQuoting>();
-
- bool get currentMemberHasParseError {
- return !memberErrors.isEmpty && memberErrors.head;
- }
-
- void pushQuoting(StringQuoting quoting) {
- interpolationScope = interpolationScope.prepend(quoting);
- }
-
- StringQuoting popQuoting() {
- StringQuoting result = interpolationScope.head;
- interpolationScope = interpolationScope.tail;
- return result;
- }
-
- StringNode popLiteralString() {
- StringNode node = popNode();
- // TODO(lrn): Handle interpolations in script tags.
- if (node.isInterpolation) {
- listener.internalError(node,
- "String interpolation not supported in library tags.");
- return null;
- }
- return node;
- }
-
- bool allowLibraryTags() {
- // Library tags are only allowed in the library file itself, not
- // in sourced files.
- LibraryElement library = compilationUnitElement.implementationLibrary;
- return !compilationUnitElement.hasMembers &&
- library.entryCompilationUnit == compilationUnitElement;
- }
-
- void endLibraryName(Token libraryKeyword, Token semicolon) {
- Expression name = popNode();
- addLibraryTag(new LibraryName(libraryKeyword, name,
- popMetadata(compilationUnitElement)));
- }
-
- void endImport(Token importKeyword, Token deferredKeyword, Token asKeyword,
- Token semicolon) {
- NodeList combinators = popNode();
- bool isDeferred = deferredKeyword != null;
- Identifier prefix;
- if (asKeyword != null) {
- prefix = popNode();
- }
- StringNode uri = popLiteralString();
- addLibraryTag(new Import(importKeyword, uri, prefix, combinators,
- popMetadata(compilationUnitElement),
- isDeferred: isDeferred));
- }
-
- void endEnum(Token enumKeyword, Token endBrace, int count) {
- NodeList names = makeNodeList(count, enumKeyword.next.next, endBrace, ",");
- Identifier name = popNode();
-
- int id = idGenerator();
- Element enclosing = compilationUnitElement;
- pushElement(new EnumClassElementX(name.source, enclosing, id,
- new Enum(enumKeyword, name, names)));
- rejectBuiltInIdentifier(name);
- }
-
- void endExport(Token exportKeyword, Token semicolon) {
- NodeList combinators = popNode();
- StringNode uri = popNode();
- addLibraryTag(new Export(exportKeyword, uri, combinators,
- popMetadata(compilationUnitElement)));
- }
-
- void endCombinators(int count) {
- if (0 == count) {
- pushNode(null);
- } else {
- pushNode(makeNodeList(count, null, null, " "));
- }
- }
-
- void endHide(Token hideKeyword) => pushCombinator(hideKeyword);
-
- void endShow(Token showKeyword) => pushCombinator(showKeyword);
-
- void pushCombinator(Token keywordToken) {
- NodeList identifiers = popNode();
- pushNode(new Combinator(identifiers, keywordToken));
- }
-
- void endIdentifierList(int count) {
- pushNode(makeNodeList(count, null, null, ","));
- }
-
- void endTypeList(int count) {
- pushNode(makeNodeList(count, null, null, ","));
- }
-
- void endPart(Token partKeyword, Token semicolon) {
- StringNode uri = popLiteralString();
- addLibraryTag(new Part(partKeyword, uri,
- popMetadata(compilationUnitElement)));
- }
-
- void endPartOf(Token partKeyword, Token semicolon) {
- Expression name = popNode();
- addPartOfTag(new PartOf(partKeyword, name,
- popMetadata(compilationUnitElement)));
- }
-
- void addPartOfTag(PartOf tag) {
- compilationUnitElement.setPartOf(tag, listener);
- }
-
- void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
- if (periodBeforeName != null) {
- popNode(); // Discard name.
- }
- popNode(); // Discard node (Send or Identifier).
- pushMetadata(new PartialMetadataAnnotation(beginToken, endToken));
- }
-
- void endTopLevelDeclaration(Token token) {
- if (!metadata.isEmpty) {
- recoverableError(metadata.head.beginToken,
- 'Metadata not supported here.');
- metadata = const Link<MetadataAnnotation>();
- }
- }
-
- void endClassDeclaration(int interfacesCount, Token beginToken,
- Token extendsKeyword, Token implementsKeyword,
- Token endToken) {
- makeNodeList(interfacesCount, implementsKeyword, null, ","); // interfaces
- popNode(); // superType
- popNode(); // typeParameters
- Identifier name = popNode();
- int id = idGenerator();
- PartialClassElement element = new PartialClassElement(
- name.source, beginToken, endToken, compilationUnitElement, id);
- pushElement(element);
- rejectBuiltInIdentifier(name);
- }
-
- void rejectBuiltInIdentifier(Identifier name) {
- if (name.token is KeywordToken) {
- Keyword keyword = (name.token as KeywordToken).keyword;
- if (!keyword.isPseudo) {
- recoverableError(name, "Illegal name '${keyword.syntax}'.");
- }
- }
- }
-
- void endFunctionTypeAlias(Token typedefKeyword, Token endToken) {
- popNode(); // TODO(karlklose): do not throw away typeVariables.
- Identifier name = popNode();
- popNode(); // returnType
- pushElement(
- new PartialTypedefElement(
- name.source, compilationUnitElement, typedefKeyword, endToken));
- rejectBuiltInIdentifier(name);
- }
-
- void endNamedMixinApplication(Token classKeyword,
- Token implementsKeyword,
- Token endToken) {
- NodeList interfaces = (implementsKeyword != null) ? popNode() : null;
- MixinApplication mixinApplication = popNode();
- Modifiers modifiers = popNode();
- NodeList typeParameters = popNode();
- Identifier name = popNode();
- NamedMixinApplication namedMixinApplication = new NamedMixinApplication(
- name, typeParameters, modifiers, mixinApplication, interfaces,
- classKeyword, endToken);
-
- int id = idGenerator();
- Element enclosing = compilationUnitElement;
- pushElement(new MixinApplicationElementX(name.source, enclosing, id,
- namedMixinApplication,
- modifiers));
- rejectBuiltInIdentifier(name);
- }
-
- void endMixinApplication() {
- NodeList mixins = popNode();
- TypeAnnotation superclass = popNode();
- pushNode(new MixinApplication(superclass, mixins));
- }
-
- void handleVoidKeyword(Token token) {
- pushNode(new TypeAnnotation(new Identifier(token), null));
- }
-
- void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
- bool hasParseError = currentMemberHasParseError;
- memberErrors = memberErrors.tail;
- Identifier name = popNode();
- popNode(); // type
- Modifiers modifiers = popNode();
- PartialFunctionElement element = new PartialFunctionElement(
- name.source, beginToken, getOrSet, endToken,
- modifiers, compilationUnitElement);
- element.hasParseError = hasParseError;
- pushElement(element);
- }
-
- void endTopLevelFields(int count, Token beginToken, Token endToken) {
- bool hasParseError = currentMemberHasParseError;
- memberErrors = memberErrors.tail;
- void buildFieldElement(Identifier name, VariableList fields) {
- pushElement(
- new FieldElementX(name, compilationUnitElement, fields));
- }
- NodeList variables = makeNodeList(count, null, null, ",");
- popNode(); // type
- Modifiers modifiers = popNode();
- buildFieldElements(modifiers, variables, compilationUnitElement,
- buildFieldElement,
- beginToken, endToken, hasParseError);
- }
-
- void buildFieldElements(Modifiers modifiers,
- NodeList variables,
- Element enclosingElement,
- void buildFieldElement(Identifier name,
- VariableList fields),
- Token beginToken, Token endToken,
- bool hasParseError) {
- VariableList fields =
- new PartialFieldList(beginToken, endToken, modifiers, hasParseError);
- for (Link<Node> variableNodes = variables.nodes;
- !variableNodes.isEmpty;
- variableNodes = variableNodes.tail) {
- Expression initializedIdentifier = variableNodes.head;
- Identifier identifier = initializedIdentifier.asIdentifier();
- if (identifier == null) {
- identifier = initializedIdentifier.asSendSet().selector.asIdentifier();
- }
- buildFieldElement(identifier, fields);
- }
- }
-
- void handleIdentifier(Token token) {
- pushNode(new Identifier(token));
- }
-
- void handleQualified(Token period) {
- Identifier last = popNode();
- Expression first = popNode();
- pushNode(new Send(first, last));
- }
-
- void handleNoType(Token token) {
- pushNode(null);
- }
-
- void endTypeVariable(Token token) {
- TypeAnnotation bound = popNode();
- Identifier name = popNode();
- pushNode(new TypeVariable(name, bound));
- rejectBuiltInIdentifier(name);
- }
-
- void endTypeVariables(int count, Token beginToken, Token endToken) {
- pushNode(makeNodeList(count, beginToken, endToken, ','));
- }
-
- void handleNoTypeVariables(token) {
- pushNode(null);
- }
-
- void endTypeArguments(int count, Token beginToken, Token endToken) {
- pushNode(makeNodeList(count, beginToken, endToken, ','));
- }
-
- void handleNoTypeArguments(Token token) {
- pushNode(null);
- }
-
- void endType(Token beginToken, Token endToken) {
- NodeList typeArguments = popNode();
- Expression typeName = popNode();
- pushNode(new TypeAnnotation(typeName, typeArguments));
- }
-
- void handleParenthesizedExpression(BeginGroupToken token) {
- Expression expression = popNode();
- pushNode(new ParenthesizedExpression(expression, token));
- }
-
- void handleModifier(Token token) {
- pushNode(new Identifier(token));
- }
-
- void handleModifiers(int count) {
- if (count == 0) {
- pushNode(Modifiers.EMPTY);
- } else {
- NodeList modifierNodes = makeNodeList(count, null, null, ' ');
- pushNode(new Modifiers(modifierNodes));
- }
- }
-
- Token expected(String string, Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else if (identical(';', string)) {
- // When a semicolon is missing, it often leads to an error on the
- // following line. So we try to find the token preceding the semicolon
- // and report that something is missing *after* it.
- Token preceding = findPrecedingToken(token);
- if (preceding == token) {
- reportError(
- token, MessageKind.MISSING_TOKEN_BEFORE_THIS, {'token': string});
- } else {
- reportError(
- preceding, MessageKind.MISSING_TOKEN_AFTER_THIS, {'token': string});
- }
- return token;
- } else {
- reportFatalError(
- token,
- MessageTemplate.TEMPLATES[MessageKind.MISSING_TOKEN_BEFORE_THIS]
- .message({'token': string}, true).toString());
- }
- return skipToEof(token);
- }
-
- /// Finds the preceding token via the begin token of the last AST node pushed
- /// on the [nodes] stack.
- Token findPrecedingToken(Token token) {
- Token result;
- Link<Node> nodes = this.nodes;
- while (!nodes.isEmpty) {
- result = findPrecedingTokenFromNode(nodes.head, token);
- if (result != null) {
- return result;
- }
- nodes = nodes.tail;
- }
- if (compilationUnitElement != null) {
- if (compilationUnitElement is CompilationUnitElementX) {
- CompilationUnitElementX unit = compilationUnitElement;
- Link<Element> members = unit.localMembers;
- while (!members.isEmpty) {
- ElementX member = members.head;
- DeclarationSite site = member.declarationSite;
- if (site is PartialElement) {
- result = findPrecedingTokenFromToken(site.endToken, token);
- if (result != null) {
- return result;
- }
- }
- members = members.tail;
- }
- result =
- findPrecedingTokenFromNode(compilationUnitElement.partTag, token);
- if (result != null) {
- return result;
- }
- }
- }
- return token;
- }
-
- Token findPrecedingTokenFromNode(Node node, Token token) {
- if (node != null) {
- return findPrecedingTokenFromToken(node.getBeginToken(), token);
- }
- return null;
- }
-
- Token findPrecedingTokenFromToken(Token start, Token token) {
- if (start != null) {
- Token current = start;
- while (current.kind != EOF_TOKEN && current.next != token) {
- current = current.next;
- }
- if (current.kind != EOF_TOKEN) {
- return current;
- }
- }
- return null;
- }
-
- Token expectedIdentifier(Token token) {
- if (token is KeywordToken) {
- reportError(
- token, MessageKind.EXPECTED_IDENTIFIER_NOT_RESERVED_WORD,
- {'keyword': token.value});
- } else if (token is ErrorToken) {
- reportErrorToken(token);
- return synthesizeIdentifier(token);
- } else {
- reportFatalError(token,
- "Expected identifier, but got '${token.value}'.");
- }
- return token;
- }
-
- Token expectedType(Token token) {
- pushNode(null);
- if (token is ErrorToken) {
- reportErrorToken(token);
- return synthesizeIdentifier(token);
- } else {
- reportFatalError(
- token, "Expected a type, but got '${token.value}'.");
- return skipToEof(token);
- }
- }
-
- Token expectedExpression(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- pushNode(new ErrorExpression(token));
- return token.next;
- } else {
- reportFatalError(token,
- "Expected an expression, but got '${token.value}'.");
- pushNode(null);
- return skipToEof(token);
- }
- }
-
- Token unexpected(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- String message = "Unexpected token '${token.value}'.";
- if (token.info == BAD_INPUT_INFO) {
- message = token.value;
- }
- reportFatalError(token, message);
- }
- return skipToEof(token);
- }
-
- Token expectedBlockToSkip(Token token) {
- if (identical(token.stringValue, 'native')) {
- return native.handleNativeBlockToSkip(this, token);
- } else {
- return unexpected(token);
- }
- }
-
- Token expectedFunctionBody(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- String printString = token.value;
- reportFatalError(token,
- "Expected a function body, but got '$printString'.");
- }
- return skipToEof(token);
- }
-
- Token expectedClassBody(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- reportFatalError(token,
- "Expected a class body, but got '${token.value}'.");
- }
- return skipToEof(token);
- }
-
- Token expectedClassBodyToSkip(Token token) {
- return unexpected(token);
- }
-
- Token expectedDeclaration(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- reportFatalError(token,
- "Expected a declaration, but got '${token.value}'.");
- }
- return skipToEof(token);
- }
-
- Token unmatched(Token token) {
- if (token is ErrorToken) {
- reportErrorToken(token);
- } else {
- String begin = token.value;
- String end = closeBraceFor(begin);
- reportError(
- token, MessageKind.UNMATCHED_TOKEN, {'begin': begin, 'end': end});
- }
- Token next = token.next;
- while (next is ErrorToken) {
- next = next.next;
- }
- return next;
- }
-
- void recoverableError(Spannable node, String message) {
- // TODO(johnniwinther): Make recoverable errors non-fatal.
- reportFatalError(node, message);
- }
-
- void pushElement(Element element) {
- popMetadata(element);
- compilationUnitElement.addMember(element, listener);
- }
-
- Link<MetadataAnnotation> popMetadata(ElementX element) {
- var result = const Link<MetadataAnnotation>();
- for (Link link = metadata; !link.isEmpty; link = link.tail) {
- element.addMetadata(link.head);
- // Reverse the list as is implicitly done by addMetadata.
- result = result.prepend(link.head);
- }
- metadata = const Link<MetadataAnnotation>();
- return result;
- }
-
- void pushMetadata(MetadataAnnotation annotation) {
- metadata = metadata.prepend(annotation);
- }
-
- void addLibraryTag(LibraryTag tag) {
- if (!allowLibraryTags()) {
- recoverableError(tag, 'Library tags not allowed here.');
- }
- LibraryElementX implementationLibrary =
- compilationUnitElement.implementationLibrary;
- implementationLibrary.addTag(tag, listener);
- }
-
- void pushNode(Node node) {
- nodes = nodes.prepend(node);
- if (VERBOSE) log("push $nodes");
- }
-
- Node popNode() {
- assert(!nodes.isEmpty);
- Node node = nodes.head;
- nodes = nodes.tail;
- if (VERBOSE) log("pop $nodes");
- return node;
- }
-
- void log(message) {
- print(message);
- }
-
- NodeList makeNodeList(int count, Token beginToken, Token endToken,
- String delimiter) {
- Link<Node> poppedNodes = const Link<Node>();
- for (; count > 0; --count) {
- // This effectively reverses the order of nodes so they end up
- // in correct (source) order.
- poppedNodes = poppedNodes.prepend(popNode());
- }
- return new NodeList(beginToken, poppedNodes, endToken, delimiter);
- }
-
- void beginLiteralString(Token token) {
- String source = token.value;
- StringQuoting quoting = StringValidator.quotingFromString(source);
- pushQuoting(quoting);
- // Just wrap the token for now. At the end of the interpolation,
- // when we know how many there are, go back and validate the tokens.
- pushNode(new LiteralString(token, null));
- }
-
- void handleStringPart(Token token) {
- // Just push an unvalidated token now, and replace it when we know the
- // end of the interpolation.
- pushNode(new LiteralString(token, null));
- }
-
- void endLiteralString(int count) {
- StringQuoting quoting = popQuoting();
-
- Link<StringInterpolationPart> parts =
- const Link<StringInterpolationPart>();
- // Parts of the string interpolation are popped in reverse order,
- // starting with the last literal string part.
- bool isLast = true;
- for (int i = 0; i < count; i++) {
- LiteralString string = popNode();
- DartString validation =
- stringValidator.validateInterpolationPart(string.token, quoting,
- isFirst: false,
- isLast: isLast);
- // Replace the unvalidated LiteralString with a new LiteralString
- // object that has the validation result included.
- string = new LiteralString(string.token, validation);
- Expression expression = popNode();
- parts = parts.prepend(new StringInterpolationPart(expression, string));
- isLast = false;
- }
-
- LiteralString string = popNode();
- DartString validation =
- stringValidator.validateInterpolationPart(string.token, quoting,
- isFirst: true,
- isLast: isLast);
- string = new LiteralString(string.token, validation);
- if (isLast) {
- pushNode(string);
- } else {
- NodeList partNodes = new NodeList(null, parts, null, "");
- pushNode(new StringInterpolation(string, partNodes));
- }
- }
-
- void handleStringJuxtaposition(int stringCount) {
- assert(stringCount != 0);
- Expression accumulator = popNode();
- stringCount--;
- while (stringCount > 0) {
- Expression expression = popNode();
- accumulator = new StringJuxtaposition(expression, accumulator);
- stringCount--;
- }
- pushNode(accumulator);
- }
-
- void beginMember(Token token) {
- memberErrors = memberErrors.prepend(false);
- }
-
- void beginTopLevelMember(Token token) {
- beginMember(token);
- }
-
- void endFields(fieldCount, start, token) {
- memberErrors = memberErrors.tail;
- }
-
- void endMethod(getOrSet, start, token) {
- memberErrors = memberErrors.tail;
- }
-
- void beginFactoryMethod(Token token) {
- memberErrors = memberErrors.prepend(false);
- }
-
- void endFactoryMethod(Token beginToken, Token endToken) {
- memberErrors = memberErrors.tail;
- }
-
- /// Don't call this method. Should only be used as a last resort when there
- /// is no feasible way to recover from a parser error.
- void reportFatalError(Spannable spannable, String message) {
- reportError(spannable, MessageKind.GENERIC, {'text': message});
- // Some parse errors are infeasible to recover from, so we throw an error.
- throw new ParserError(message);
- }
-
- void reportError(Spannable spannable,
- MessageKind errorCode,
- [Map arguments = const {}]) {
- if (currentMemberHasParseError) return; // Error already reported.
- if (suppressParseErrors) return;
- if (!memberErrors.isEmpty) {
- memberErrors = memberErrors.tail.prepend(true);
- }
- listener.reportError(spannable, errorCode, arguments);
- }
-}
-
-class NodeListener extends ElementListener {
- NodeListener(
- DiagnosticListener listener,
- CompilationUnitElement element)
- : super(listener, element, null);
-
- void addLibraryTag(LibraryTag tag) {
- pushNode(tag);
- }
-
- void addPartOfTag(PartOf tag) {
- pushNode(tag);
- }
-
- void endClassDeclaration(int interfacesCount, Token beginToken,
- Token extendsKeyword, Token implementsKeyword,
- Token endToken) {
- NodeList body = popNode();
- NodeList interfaces =
- makeNodeList(interfacesCount, implementsKeyword, null, ",");
- Node supertype = popNode();
- NodeList typeParameters = popNode();
- Identifier name = popNode();
- Modifiers modifiers = popNode();
- pushNode(new ClassNode(modifiers, name, typeParameters, supertype,
- interfaces, beginToken, extendsKeyword, body,
- endToken));
- }
-
- void endCompilationUnit(int count, Token token) {
- pushNode(makeNodeList(count, null, null, '\n'));
- }
-
- void endFunctionTypeAlias(Token typedefKeyword, Token endToken) {
- NodeList formals = popNode();
- NodeList typeParameters = popNode();
- Identifier name = popNode();
- TypeAnnotation returnType = popNode();
- pushNode(new Typedef(returnType, name, typeParameters, formals,
- typedefKeyword, endToken));
- }
-
- void endNamedMixinApplication(Token classKeyword,
- Token implementsKeyword,
- Token endToken) {
- NodeList interfaces = (implementsKeyword != null) ? popNode() : null;
- Node mixinApplication = popNode();
- Modifiers modifiers = popNode();
- NodeList typeParameters = popNode();
- Identifier name = popNode();
- pushNode(new NamedMixinApplication(name, typeParameters,
- modifiers, mixinApplication,
- interfaces,
- classKeyword, endToken));
- }
-
- void endEnum(Token enumKeyword, Token endBrace, int count) {
- NodeList names = makeNodeList(count, enumKeyword.next.next, endBrace, ",");
- Identifier name = popNode();
- pushNode(new Enum(enumKeyword, name, names));
- }
-
- void endClassBody(int memberCount, Token beginToken, Token endToken) {
- pushNode(makeNodeList(memberCount, beginToken, endToken, null));
- }
-
- void endTopLevelFields(int count, Token beginToken, Token endToken) {
- NodeList variables = makeNodeList(count, null, endToken, ",");
- TypeAnnotation type = popNode();
- Modifiers modifiers = popNode();
- pushNode(new VariableDefinitions(type, modifiers, variables));
- }
-
- void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
- popNode(); // body
- popNode(); // formalParameters
- Identifier name = popNode();
- popNode(); // type
- Modifiers modifiers = popNode();
- PartialFunctionElement element = new PartialFunctionElement(
- name.source, beginToken, getOrSet, endToken,
- modifiers, compilationUnitElement);
- pushElement(element);
- }
-
- void endFormalParameter(Token thisKeyword) {
- Expression name = popNode();
- if (thisKeyword != null) {
- Identifier thisIdentifier = new Identifier(thisKeyword);
- if (name.asSend() == null) {
- name = new Send(thisIdentifier, name);
- } else {
- name = name.asSend().copyWithReceiver(thisIdentifier, false);
- }
- }
- TypeAnnotation type = popNode();
- Modifiers modifiers = popNode();
- NodeList metadata = popNode();
- pushNode(new VariableDefinitions.forParameter(
- metadata, type, modifiers, new NodeList.singleton(name)));
- }
-
- void endFormalParameters(int count, Token beginToken, Token endToken) {
- pushNode(makeNodeList(count, beginToken, endToken, ","));
- }
-
- void handleNoFormalParameters(Token token) {
- pushNode(null);
- }
-
- void endArguments(int count, Token beginToken, Token endToken) {
- pushNode(makeNodeList(count, beginToken, endToken, ","));
- }
-
- void handleNoArguments(Token token) {
- pushNode(null);
- }
-
- void endConstructorReference(Token start, Token periodBeforeName,
- Token endToken) {
- Identifier name = null;
- if (periodBeforeName != null) {
- name = popNode();
- }
- NodeList typeArguments = popNode();
- Node classReference = popNode();
- if (typeArguments != null) {
- classReference = new TypeAnnotation(classReference, typeArguments);
- } else {
- Identifier identifier = classReference.asIdentifier();
- Send send = classReference.asSend();
- if (identifier != null) {
- // TODO(ahe): Should be:
- // classReference = new Send(null, identifier);
- classReference = identifier;
- } else if (send != null) {
- classReference = send;
- } else {
- internalError(node: classReference);
- }
- }
- Node constructor = classReference;
- if (name != null) {
- // Either typeName<args>.name or x.y.name.
- constructor = new Send(classReference, name);
- }
- pushNode(constructor);
- }
-
- void endRedirectingFactoryBody(Token beginToken,
- Token endToken) {
- pushNode(new RedirectingFactoryBody(beginToken, endToken, popNode()));
- }
-
- void endReturnStatement(bool hasExpression,
- Token beginToken, Token endToken) {
- Expression expression = hasExpression ? popNode() : null;
- pushNode(new Return(beginToken, endToken, expression));
- }
-
- void endYieldStatement(Token yieldToken, Token starToken, Token endToken) {
- Expression expression = popNode();
- pushNode(new Yield(yieldToken, starToken, expression, endToken));
- }
-
- void endExpressionStatement(Token token) {
- pushNode(new ExpressionStatement(popNode(), token));
- }
-
- void handleOnError(Token token, var errorInformation) {
- listener.internalError(token, "'${token.value}': ${errorInformation}");
+ void handleModifier(Token token) {
+ pushNode(new Identifier(token));
}
- Token expectedFunctionBody(Token token) {
- if (identical(token.stringValue, 'native')) {
- return native.handleNativeFunctionBody(this, token);
- } else if (token is ErrorToken) {
- pushNode(null);
- reportErrorToken(token);
+ void handleModifiers(int count) {
+ if (count == 0) {
+ pushNode(Modifiers.EMPTY);
} else {
- reportFatalError(token,
- "Expected a function body, but got '${token.value}'.");
+ NodeList modifierNodes = makeNodeList(count, null, null, ' ');
+ pushNode(new Modifiers(modifierNodes));
}
- return skipToEof(token);
}
- Token expectedClassBody(Token token) {
+ Token expected(String string, Token token) {
if (token is ErrorToken) {
reportErrorToken(token);
- return skipToEof(token);
- } else {
- reportFatalError(token,
- "Expected a class body, but got '${token.value}'.");
- return skipToEof(token);
- }
- }
-
- void handleLiteralInt(Token token) {
- pushNode(new LiteralInt(token, (t, e) => handleOnError(t, e)));
- }
-
- void handleLiteralDouble(Token token) {
- pushNode(new LiteralDouble(token, (t, e) => handleOnError(t, e)));
- }
-
- void handleLiteralBool(Token token) {
- pushNode(new LiteralBool(token, (t, e) => handleOnError(t, e)));
- }
-
- void handleLiteralNull(Token token) {
- pushNode(new LiteralNull(token));
- }
-
- void endLiteralSymbol(Token hashToken, int identifierCount) {
- NodeList identifiers = makeNodeList(identifierCount, null, null, '.');
- pushNode(new LiteralSymbol(hashToken, identifiers));
- }
-
- void handleBinaryExpression(Token token) {
- Node argument = popNode();
- Node receiver = popNode();
- String tokenString = token.stringValue;
- if (identical(tokenString, '.') ||
- identical(tokenString, '..') ||
- identical(tokenString, '?.')) {
- Send argumentSend = argument.asSend();
- if (argumentSend == null) {
- // TODO(ahe): The parser should diagnose this problem, not
- // this listener.
- reportFatalError(argument,
- 'Expected an identifier.');
+ } else if (identical(';', string)) {
+ // When a semicolon is missing, it often leads to an error on the
+ // following line. So we try to find the token preceding the semicolon
+ // and report that something is missing *after* it.
+ Token preceding = findPrecedingToken(token);
+ if (preceding == token) {
+ reportError(
+ token, MessageKind.MISSING_TOKEN_BEFORE_THIS, {'token': string});
+ } else {
+ reportError(
+ preceding, MessageKind.MISSING_TOKEN_AFTER_THIS, {'token': string});
}
- if (argumentSend.receiver != null) internalError(node: argument);
- if (argument is SendSet) internalError(node: argument);
- pushNode(argument.asSend().copyWithReceiver(receiver,
- identical(tokenString, '?.')));
+ return token;
} else {
- NodeList arguments = new NodeList.singleton(argument);
- pushNode(new Send(receiver, new Operator(token), arguments));
- }
- if (identical(tokenString, '===')) {
- listener.reportError(token, MessageKind.UNSUPPORTED_EQ_EQ_EQ,
- {'lhs': receiver, 'rhs': argument});
- }
- if (identical(tokenString, '!==')) {
- listener.reportError(token, MessageKind.UNSUPPORTED_BANG_EQ_EQ,
- {'lhs': receiver, 'rhs': argument});
+ reportFatalError(
+ token,
+ MessageTemplate.TEMPLATES[MessageKind.MISSING_TOKEN_BEFORE_THIS]
+ .message({'token': string}, true).toString());
}
+ return skipToEof(token);
}
- void beginCascade(Token token) {
- pushNode(new CascadeReceiver(popNode(), token));
- }
-
- void endCascade() {
- pushNode(new Cascade(popNode()));
- }
-
- void handleAsOperator(Token operathor, Token endToken) {
- TypeAnnotation type = popNode();
- Expression expression = popNode();
- NodeList arguments = new NodeList.singleton(type);
- pushNode(new Send(expression, new Operator(operathor), arguments));
- }
-
- void handleAssignmentExpression(Token token) {
- Node arg = popNode();
- Node node = popNode();
- Send send = node.asSend();
- if (send == null || !(send.isPropertyAccess || send.isIndex)) {
- reportNotAssignable(node);
- }
- if (send.asSendSet() != null) internalError(node: send);
- NodeList arguments;
- if (send.isIndex) {
- Link<Node> link = const Link<Node>().prepend(arg);
- link = link.prepend(send.arguments.head);
- arguments = new NodeList(null, link);
- } else {
- arguments = new NodeList.singleton(arg);
+ /// Finds the preceding token via the begin token of the last AST node pushed
+ /// on the [nodes] stack.
+ Token findPrecedingToken(Token token) {
+ Token result;
+ Link<Node> nodes = this.nodes;
+ while (!nodes.isEmpty) {
+ result = findPrecedingTokenFromNode(nodes.head, token);
+ if (result != null) {
+ return result;
+ }
+ nodes = nodes.tail;
}
- Operator op = new Operator(token);
- pushNode(new SendSet(send.receiver, send.selector, op, arguments,
- send.isConditional));
- }
-
- void reportNotAssignable(Node node) {
- // TODO(ahe): The parser should diagnose this problem, not this
- // listener.
- reportFatalError(node,
- 'Not assignable.');
- }
-
- void handleConditionalExpression(Token question, Token colon) {
- Node elseExpression = popNode();
- Node thenExpression = popNode();
- Node condition = popNode();
- pushNode(new Conditional(
- condition, thenExpression, elseExpression, question, colon));
- }
-
- void endSend(Token token) {
- NodeList arguments = popNode();
- Node selector = popNode();
- // TODO(ahe): Handle receiver.
- pushNode(new Send(null, selector, arguments));
- }
-
- void endFunctionBody(int count, Token beginToken, Token endToken) {
- if (count == 0 && beginToken == null) {
- pushNode(new EmptyStatement(endToken));
- } else {
- pushNode(new Block(makeNodeList(count, beginToken, endToken, null)));
+ if (compilationUnitElement != null) {
+ if (compilationUnitElement is CompilationUnitElementX) {
+ CompilationUnitElementX unit = compilationUnitElement;
+ Link<Element> members = unit.localMembers;
+ while (!members.isEmpty) {
+ ElementX member = members.head;
+ DeclarationSite site = member.declarationSite;
+ if (site is PartialElement) {
+ result = findPrecedingTokenFromToken(site.endToken, token);
+ if (result != null) {
+ return result;
+ }
+ }
+ members = members.tail;
+ }
+ result =
+ findPrecedingTokenFromNode(compilationUnitElement.partTag, token);
+ if (result != null) {
+ return result;
+ }
+ }
}
+ return token;
}
- void handleAsyncModifier(Token asyncToken, Token starToken) {
- if (asyncToken != null) {
- pushNode(new AsyncModifier(asyncToken, starToken));
- } else {
- pushNode(null);
+ Token findPrecedingTokenFromNode(Node node, Token token) {
+ if (node != null) {
+ return findPrecedingTokenFromToken(node.getBeginToken(), token);
}
+ return null;
}
- void skippedFunctionBody(Token token) {
- pushNode(new Block(new NodeList.empty()));
- }
-
- void handleNoFunctionBody(Token token) {
- pushNode(new EmptyStatement(token));
- }
-
- void endFunction(Token getOrSet, Token endToken) {
- Statement body = popNode();
- AsyncModifier asyncModifier = popNode();
- NodeList initializers = popNode();
- NodeList formals = popNode();
- // The name can be an identifier or a send in case of named constructors.
- Expression name = popNode();
- TypeAnnotation type = popNode();
- Modifiers modifiers = popNode();
- pushNode(new FunctionExpression(name, formals, body, type,
- modifiers, initializers, getOrSet,
- asyncModifier));
- }
-
- void endFunctionDeclaration(Token endToken) {
- pushNode(new FunctionDeclaration(popNode()));
- }
-
- void endVariablesDeclaration(int count, Token endToken) {
- // TODO(ahe): Pick one name for this concept, either
- // VariablesDeclaration or VariableDefinitions.
- NodeList variables = makeNodeList(count, null, endToken, ",");
- TypeAnnotation type = popNode();
- Modifiers modifiers = popNode();
- pushNode(new VariableDefinitions(type, modifiers, variables));
- }
-
- void endInitializer(Token assignmentOperator) {
- Expression initializer = popNode();
- NodeList arguments =
- initializer == null ? null : new NodeList.singleton(initializer);
- Expression name = popNode();
- Operator op = new Operator(assignmentOperator);
- pushNode(new SendSet(null, name, op, arguments));
- }
-
- void endIfStatement(Token ifToken, Token elseToken) {
- Statement elsePart = (elseToken == null) ? null : popNode();
- Statement thenPart = popNode();
- ParenthesizedExpression condition = popNode();
- pushNode(new If(condition, thenPart, elsePart, ifToken, elseToken));
- }
-
- void endForStatement(int updateExpressionCount,
- Token beginToken, Token endToken) {
- Statement body = popNode();
- NodeList updates = makeNodeList(updateExpressionCount, null, null, ',');
- Statement condition = popNode();
- Node initializer = popNode();
- pushNode(new For(initializer, condition, updates, body, beginToken));
- }
-
- void handleNoExpression(Token token) {
- pushNode(null);
- }
-
- void endDoWhileStatement(Token doKeyword, Token whileKeyword,
- Token endToken) {
- Expression condition = popNode();
- Statement body = popNode();
- pushNode(new DoWhile(body, condition, doKeyword, whileKeyword, endToken));
- }
-
- void endWhileStatement(Token whileKeyword, Token endToken) {
- Statement body = popNode();
- Expression condition = popNode();
- pushNode(new While(condition, body, whileKeyword));
- }
-
- void endBlock(int count, Token beginToken, Token endToken) {
- pushNode(new Block(makeNodeList(count, beginToken, endToken, null)));
- }
-
- void endThrowExpression(Token throwToken, Token endToken) {
- Expression expression = popNode();
- pushNode(new Throw(expression, throwToken, endToken));
- }
-
- void endAwaitExpression(Token awaitToken, Token endToken) {
- Expression expression = popNode();
- pushNode(new Await(awaitToken, expression));
- }
-
- void endRethrowStatement(Token throwToken, Token endToken) {
- pushNode(new Rethrow(throwToken, endToken));
- if (identical(throwToken.stringValue, 'throw')) {
- listener.reportError(throwToken,
- MessageKind.UNSUPPORTED_THROW_WITHOUT_EXP);
+ Token findPrecedingTokenFromToken(Token start, Token token) {
+ if (start != null) {
+ Token current = start;
+ while (current.kind != Tokens.EOF_TOKEN && current.next != token) {
+ current = current.next;
+ }
+ if (current.kind != Tokens.EOF_TOKEN) {
+ return current;
+ }
}
+ return null;
}
- void handleUnaryPrefixExpression(Token token) {
- pushNode(new Send.prefix(popNode(), new Operator(token)));
- }
-
- void handleSuperExpression(Token token) {
- pushNode(new Identifier(token));
- }
-
- void handleThisExpression(Token token) {
- pushNode(new Identifier(token));
- }
-
- void handleUnaryAssignmentExpression(Token token, bool isPrefix) {
- Node node = popNode();
- Send send = node.asSend();
- if (send == null) {
- reportNotAssignable(node);
- }
- if (!(send.isPropertyAccess || send.isIndex)) {
- reportNotAssignable(node);
- }
- if (send.asSendSet() != null) internalError(node: send);
- Node argument = null;
- if (send.isIndex) argument = send.arguments.head;
- Operator op = new Operator(token);
-
- if (isPrefix) {
- pushNode(new SendSet.prefix(send.receiver, send.selector, op, argument,
- send.isConditional));
+ Token expectedIdentifier(Token token) {
+ if (token is KeywordToken) {
+ reportError(
+ token, MessageKind.EXPECTED_IDENTIFIER_NOT_RESERVED_WORD,
+ {'keyword': token.value});
+ } else if (token is ErrorToken) {
+ reportErrorToken(token);
+ return synthesizeIdentifier(token);
} else {
- pushNode(new SendSet.postfix(send.receiver, send.selector, op, argument,
- send.isConditional));
- }
- }
-
- void handleUnaryPostfixAssignmentExpression(Token token) {
- handleUnaryAssignmentExpression(token, false);
- }
-
- void handleUnaryPrefixAssignmentExpression(Token token) {
- handleUnaryAssignmentExpression(token, true);
- }
-
- void endInitializers(int count, Token beginToken, Token endToken) {
- pushNode(makeNodeList(count, beginToken, null, ','));
- }
-
- void handleNoInitializers() {
- pushNode(null);
- }
-
- void endFields(int count, Token beginToken, Token endToken) {
- NodeList variables = makeNodeList(count, null, endToken, ",");
- TypeAnnotation type = popNode();
- Modifiers modifiers = popNode();
- pushNode(new VariableDefinitions(type, modifiers, variables));
- }
-
- void endMethod(Token getOrSet, Token beginToken, Token endToken) {
- Statement body = popNode();
- AsyncModifier asyncModifier = popNode();
- NodeList initializers = popNode();
- NodeList formalParameters = popNode();
- Expression name = popNode();
- TypeAnnotation returnType = popNode();
- Modifiers modifiers = popNode();
- pushNode(new FunctionExpression(name, formalParameters, body, returnType,
- modifiers, initializers, getOrSet,
- asyncModifier));
- }
-
- void handleLiteralMap(int count, Token beginToken, Token constKeyword,
- Token endToken) {
- NodeList entries = makeNodeList(count, beginToken, endToken, ',');
- NodeList typeArguments = popNode();
- pushNode(new LiteralMap(typeArguments, entries, constKeyword));
- }
-
- void endLiteralMapEntry(Token colon, Token endToken) {
- Expression value = popNode();
- Expression key = popNode();
- pushNode(new LiteralMapEntry(key, colon, value));
- }
-
- void handleLiteralList(int count, Token beginToken, Token constKeyword,
- Token endToken) {
- NodeList elements = makeNodeList(count, beginToken, endToken, ',');
- pushNode(new LiteralList(popNode(), elements, constKeyword));
- }
-
- void handleIndexedExpression(Token openSquareBracket,
- Token closeSquareBracket) {
- NodeList arguments =
- makeNodeList(1, openSquareBracket, closeSquareBracket, null);
- Node receiver = popNode();
- Token token = new StringToken.fromString(INDEX_INFO, '[]',
- openSquareBracket.charOffset);
- Node selector = new Operator(token);
- pushNode(new Send(receiver, selector, arguments));
- }
-
- void handleNewExpression(Token token) {
- NodeList arguments = popNode();
- Node name = popNode();
- pushNode(new NewExpression(token, new Send(null, name, arguments)));
- }
-
- void handleConstExpression(Token token) {
- // [token] carries the 'const' information.
- handleNewExpression(token);
- }
-
- void handleOperator(Token token) {
- pushNode(new Operator(token));
- }
-
- void handleOperatorName(Token operatorKeyword, Token token) {
- Operator op = new Operator(token);
- pushNode(new Send(new Identifier(operatorKeyword), op, null));
- }
-
- void handleNamedArgument(Token colon) {
- Expression expression = popNode();
- Identifier name = popNode();
- pushNode(new NamedArgument(name, colon, expression));
- }
-
- void endOptionalFormalParameters(int count,
- Token beginToken, Token endToken) {
- pushNode(makeNodeList(count, beginToken, endToken, ','));
- }
-
- void handleFunctionTypedFormalParameter(Token endToken) {
- NodeList formals = popNode();
- Identifier name = popNode();
- TypeAnnotation returnType = popNode();
- pushNode(null); // Signal "no type" to endFormalParameter.
- pushNode(new FunctionExpression(name, formals, null, returnType,
- Modifiers.EMPTY, null, null, null));
- }
-
- void handleValuedFormalParameter(Token equals, Token token) {
- Expression defaultValue = popNode();
- Expression parameterName = popNode();
- pushNode(new SendSet(null, parameterName, new Operator(equals),
- new NodeList.singleton(defaultValue)));
- }
-
- void endTryStatement(int catchCount, Token tryKeyword, Token finallyKeyword) {
- Block finallyBlock = null;
- if (finallyKeyword != null) {
- finallyBlock = popNode();
- }
- NodeList catchBlocks = makeNodeList(catchCount, null, null, null);
- Block tryBlock = popNode();
- pushNode(new TryStatement(tryBlock, catchBlocks, finallyBlock,
- tryKeyword, finallyKeyword));
- }
-
- void handleCaseMatch(Token caseKeyword, Token colon) {
- pushNode(new CaseMatch(caseKeyword, popNode(), colon));
- }
-
- void handleCatchBlock(Token onKeyword, Token catchKeyword) {
- Block block = popNode();
- NodeList formals = catchKeyword != null? popNode(): null;
- TypeAnnotation type = onKeyword != null ? popNode() : null;
- pushNode(new CatchBlock(type, formals, block, onKeyword, catchKeyword));
- }
-
- void endSwitchStatement(Token switchKeyword, Token endToken) {
- NodeList cases = popNode();
- ParenthesizedExpression expression = popNode();
- pushNode(new SwitchStatement(expression, cases, switchKeyword));
- }
-
- void endSwitchBlock(int caseCount, Token beginToken, Token endToken) {
- Link<Node> caseNodes = const Link<Node>();
- while (caseCount > 0) {
- SwitchCase switchCase = popNode();
- caseNodes = caseNodes.prepend(switchCase);
- caseCount--;
- }
- pushNode(new NodeList(beginToken, caseNodes, endToken, null));
- }
-
- void handleSwitchCase(int labelCount, int caseCount,
- Token defaultKeyword, int statementCount,
- Token firstToken, Token endToken) {
- NodeList statements = makeNodeList(statementCount, null, null, null);
- NodeList labelsAndCases =
- makeNodeList(labelCount + caseCount, null, null, null);
- pushNode(new SwitchCase(labelsAndCases, defaultKeyword, statements,
- firstToken));
- }
-
- void handleBreakStatement(bool hasTarget,
- Token breakKeyword, Token endToken) {
- Identifier target = null;
- if (hasTarget) {
- target = popNode();
- }
- pushNode(new BreakStatement(target, breakKeyword, endToken));
- }
-
- void handleContinueStatement(bool hasTarget,
- Token continueKeyword, Token endToken) {
- Identifier target = null;
- if (hasTarget) {
- target = popNode();
+ reportFatalError(token,
+ "Expected identifier, but got '${token.value}'.");
}
- pushNode(new ContinueStatement(target, continueKeyword, endToken));
- }
-
- void handleEmptyStatement(Token token) {
- pushNode(new EmptyStatement(token));
+ return token;
}
- void endFactoryMethod(Token beginToken, Token endToken) {
- super.endFactoryMethod(beginToken, endToken);
- Statement body = popNode();
- AsyncModifier asyncModifier = popNode();
- NodeList formals = popNode();
- Node name = popNode();
-
- // TODO(ahe): Move this parsing to the parser.
- int modifierCount = 0;
- Token modifier = beginToken;
- if (modifier.stringValue == "external") {
- handleModifier(modifier);
- modifierCount++;
- modifier = modifier.next;
- }
- if (modifier.stringValue == "const") {
- handleModifier(modifier);
- modifierCount++;
- modifier = modifier.next;
+ Token expectedType(Token token) {
+ pushNode(null);
+ if (token is ErrorToken) {
+ reportErrorToken(token);
+ return synthesizeIdentifier(token);
+ } else {
+ reportFatalError(
+ token, "Expected a type, but got '${token.value}'.");
+ return skipToEof(token);
}
- assert(modifier.stringValue == "factory");
- handleModifier(modifier);
- modifierCount++;
- handleModifiers(modifierCount);
- Modifiers modifiers = popNode();
-
- pushNode(new FunctionExpression(name, formals, body, null,
- modifiers, null, null, asyncModifier));
}
- void endForIn(Token awaitToken, Token forToken,
- Token inKeyword, Token endToken) {
- Statement body = popNode();
- Expression expression = popNode();
- Node declaredIdentifier = popNode();
- if (awaitToken == null) {
- pushNode(new SyncForIn(declaredIdentifier, expression, body,
- forToken, inKeyword));
+ Token expectedExpression(Token token) {
+ if (token is ErrorToken) {
+ reportErrorToken(token);
+ pushNode(new ErrorExpression(token));
+ return token.next;
} else {
- pushNode(new AsyncForIn(declaredIdentifier, expression, body, awaitToken,
- forToken, inKeyword));
+ reportFatalError(token,
+ "Expected an expression, but got '${token.value}'.");
+ pushNode(null);
+ return skipToEof(token);
}
}
- void endMetadataStar(int count, bool forParameter) {
- // TODO(johnniwinther): Handle metadata for all node kinds.
- if (forParameter) {
- if (0 == count) {
- pushNode(null);
- } else {
- pushNode(makeNodeList(count, null, null, ' '));
+ Token unexpected(Token token) {
+ if (token is ErrorToken) {
+ reportErrorToken(token);
+ } else {
+ String message = "Unexpected token '${token.value}'.";
+ if (token.info == Precedence.BAD_INPUT_INFO) {
+ message = token.value;
}
+ reportFatalError(token, message);
}
+ return skipToEof(token);
}
- void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
- NodeList arguments = popNode();
- if (arguments == null) {
- // This is a constant expression.
- Identifier name;
- if (periodBeforeName != null) {
- name = popNode();
- }
- NodeList typeArguments = popNode();
- Node receiver = popNode();
- if (typeArguments != null) {
- receiver = new TypeAnnotation(receiver, typeArguments);
- recoverableError(typeArguments,
- 'Type arguments are not allowed here.');
- } else {
- Identifier identifier = receiver.asIdentifier();
- Send send = receiver.asSend();
- if (identifier != null) {
- receiver = new Send(null, identifier);
- } else if (send == null) {
- internalError(node: receiver);
- }
- }
- Send send = receiver;
- if (name != null) {
- send = new Send(receiver, name);
- }
- pushNode(new Metadata(beginToken, send));
+ Token expectedBlockToSkip(Token token) {
+ if (identical(token.stringValue, 'native')) {
+ return native.handleNativeBlockToSkip(this, token);
} else {
- // This is a const constructor call.
- endConstructorReference(beginToken, periodBeforeName, endToken);
- Node constructor = popNode();
- pushNode(new Metadata(beginToken,
- new NewExpression(null,
- new Send(null, constructor, arguments))));
+ return unexpected(token);
}
}
- void handleAssertStatement(Token assertKeyword, Token semicolonToken) {
- NodeList arguments = popNode();
- Node selector = new Identifier(assertKeyword);
- Node send = new Send(null, selector, arguments);
- pushNode(new ExpressionStatement(send, semicolonToken));
- }
-
- void endUnnamedFunction(Token token) {
- Statement body = popNode();
- AsyncModifier asyncModifier = popNode();
- NodeList formals = popNode();
- pushNode(new FunctionExpression(null, formals, body, null,
- Modifiers.EMPTY, null, null,
- asyncModifier));
+ Token expectedFunctionBody(Token token) {
+ if (token is ErrorToken) {
+ reportErrorToken(token);
+ } else {
+ String printString = token.value;
+ reportFatalError(token,
+ "Expected a function body, but got '$printString'.");
+ }
+ return skipToEof(token);
}
- void handleIsOperator(Token operathor, Token not, Token endToken) {
- TypeAnnotation type = popNode();
- Expression expression = popNode();
- Node argument;
- if (not != null) {
- argument = new Send.prefix(type, new Operator(not));
+ Token expectedClassBody(Token token) {
+ if (token is ErrorToken) {
+ reportErrorToken(token);
} else {
- argument = type;
+ reportFatalError(token,
+ "Expected a class body, but got '${token.value}'.");
}
-
- NodeList arguments = new NodeList.singleton(argument);
- pushNode(new Send(expression, new Operator(operathor), arguments));
+ return skipToEof(token);
}
- void handleLabel(Token colon) {
- Identifier name = popNode();
- pushNode(new Label(name, colon));
+ Token expectedClassBodyToSkip(Token token) {
+ return unexpected(token);
}
- void endLabeledStatement(int labelCount) {
- Statement statement = popNode();
- NodeList labels = makeNodeList(labelCount, null, null, null);
- pushNode(new LabeledStatement(labels, statement));
+ Token expectedDeclaration(Token token) {
+ if (token is ErrorToken) {
+ reportErrorToken(token);
+ } else {
+ reportFatalError(token,
+ "Expected a declaration, but got '${token.value}'.");
+ }
+ return skipToEof(token);
}
- void log(message) {
- listener.log(message);
+ Token unmatched(Token token) {
+ if (token is ErrorToken) {
+ reportErrorToken(token);
+ } else {
+ String begin = token.value;
+ String end = closeBraceFor(begin);
+ reportError(
+ token, MessageKind.UNMATCHED_TOKEN, {'begin': begin, 'end': end});
+ }
+ Token next = token.next;
+ while (next is ErrorToken) {
+ next = next.next;
+ }
+ return next;
}
- void internalError({Token token, Node node}) {
- // TODO(ahe): This should call listener.internalError.
- Spannable spannable = (token == null) ? node : token;
- throw new SpannableAssertionFailure(spannable, 'Internal error in parser.');
+ void recoverableError(Spannable node, String message) {
+ // TODO(johnniwinther): Make recoverable errors non-fatal.
+ reportFatalError(node, message);
}
-}
-abstract class PartialElement implements DeclarationSite {
- Token beginToken;
- Token endToken;
-
- bool hasParseError = false;
-
- bool get isErroneous => hasParseError;
-
- DeclarationSite get declarationSite => this;
-}
+ void pushElement(Element element) {
+ popMetadata(element);
+ compilationUnitElement.addMember(element, listener);
+ }
-abstract class PartialFunctionMixin implements BaseFunctionElementX {
- FunctionExpression cachedNode;
- Modifiers get modifiers;
- Token beginToken;
- Token getOrSet;
- Token endToken;
-
- /**
- * The position is computed in the constructor using [findMyName]. Computing
- * it on demand fails in case tokens are GC'd.
- */
- Token _position;
-
- void init(Token beginToken, Token getOrSet, Token endToken) {
- this.beginToken = beginToken;
- this.getOrSet = getOrSet;
- this.endToken = endToken;
- _position = ElementX.findNameToken(
- beginToken,
- modifiers.isFactory || isGenerativeConstructor,
- name, enclosingElement.name);
- }
-
- bool get hasNode => cachedNode != null;
-
- FunctionExpression get node {
- assert(invariant(this, cachedNode != null,
- message: "Node has not been computed for $this."));
- return cachedNode;
- }
-
- FunctionExpression parseNode(DiagnosticListener listener) {
- if (cachedNode != null) return cachedNode;
- parseFunction(Parser p) {
- if (isClassMember && modifiers.isFactory) {
- p.parseFactoryMethod(beginToken);
- } else {
- p.parseFunction(beginToken, getOrSet);
- }
+ Link<MetadataAnnotation> popMetadata(ElementX element) {
+ var result = const Link<MetadataAnnotation>();
+ for (Link link = metadata; !link.isEmpty; link = link.tail) {
+ element.addMetadata(link.head);
+ // Reverse the list as is implicitly done by addMetadata.
+ result = result.prepend(link.head);
}
- cachedNode = parse(listener, this, declarationSite, parseFunction);
- return cachedNode;
+ metadata = const Link<MetadataAnnotation>();
+ return result;
}
- Token get position => _position;
-
- void reusePartialFunctionMixin() {
- cachedNode = null;
+ void pushMetadata(MetadataAnnotation annotation) {
+ metadata = metadata.prepend(annotation);
}
- DeclarationSite get declarationSite;
-}
-
-abstract class PartialFunctionElement
- implements PartialElement, PartialFunctionMixin {
-
- factory PartialFunctionElement(
- String name,
- Token beginToken,
- Token getOrSet,
- Token endToken,
- Modifiers modifiers,
- Element enclosingElement,
- {bool hasBody: true}) {
- if (getOrSet == null) {
- return new PartialMethodElement(
- name, beginToken, endToken, modifiers,
- enclosingElement, hasBody: hasBody);
- } else if (identical(getOrSet.stringValue, 'get')) {
- return new PartialGetterElement(
- name, beginToken, getOrSet, endToken, modifiers,
- enclosingElement, hasBody: hasBody);
- } else {
- assert(identical(getOrSet.stringValue, 'set'));
- return new PartialSetterElement(
- name, beginToken, getOrSet, endToken, modifiers,
- enclosingElement, hasBody: hasBody);
+ void addLibraryTag(LibraryTag tag) {
+ if (!allowLibraryTags()) {
+ recoverableError(tag, 'Library tags not allowed here.');
}
+ LibraryElementX implementationLibrary =
+ compilationUnitElement.implementationLibrary;
+ implementationLibrary.addTag(tag, listener);
}
- PartialFunctionElement copyWithEnclosing(Element enclosing);
-}
-
-
-class PartialMethodElement extends MethodElementX
- with PartialElement, PartialFunctionMixin
- implements PartialFunctionElement {
- PartialMethodElement(String name,
- Token beginToken,
- Token endToken,
- Modifiers modifiers,
- Element enclosing,
- {bool hasBody: true})
- : super(name, ElementKind.FUNCTION, modifiers, enclosing, hasBody) {
- init(beginToken, null, endToken);
- }
-
- void reuseElement() {
- super.reuseElement();
- reusePartialFunctionMixin();
+ void pushNode(Node node) {
+ nodes = nodes.prepend(node);
+ if (VERBOSE) log("push $nodes");
}
- PartialMethodElement copyWithEnclosing(Element enclosing) {
- return new PartialMethodElement(
- name, beginToken, endToken, modifiers, enclosing, hasBody: hasBody);
+ Node popNode() {
+ assert(!nodes.isEmpty);
+ Node node = nodes.head;
+ nodes = nodes.tail;
+ if (VERBOSE) log("pop $nodes");
+ return node;
}
-}
-class PartialGetterElement extends GetterElementX
- with PartialElement, PartialFunctionMixin
- implements GetterElement, PartialFunctionElement {
- PartialGetterElement(String name,
- Token beginToken,
- Token getToken,
- Token endToken,
- Modifiers modifiers,
- Element enclosing,
- {bool hasBody: true})
- : super(name, modifiers, enclosing, hasBody) {
- init(beginToken, getToken, endToken);
+ void log(message) {
+ print(message);
}
- @override
- SetterElement get setter => abstractField.setter;
-
- void reuseElement() {
- super.reuseElement();
- reusePartialFunctionMixin();
+ NodeList makeNodeList(int count, Token beginToken, Token endToken,
+ String delimiter) {
+ Link<Node> poppedNodes = const Link<Node>();
+ for (; count > 0; --count) {
+ // This effectively reverses the order of nodes so they end up
+ // in correct (source) order.
+ poppedNodes = poppedNodes.prepend(popNode());
+ }
+ return new NodeList(beginToken, poppedNodes, endToken, delimiter);
}
- PartialGetterElement copyWithEnclosing(Element enclosing) {
- return new PartialGetterElement(
- name, beginToken, getOrSet, endToken, modifiers, enclosing,
- hasBody: hasBody);
+ void beginLiteralString(Token token) {
+ String source = token.value;
+ StringQuoting quoting = StringValidator.quotingFromString(source);
+ pushQuoting(quoting);
+ // Just wrap the token for now. At the end of the interpolation,
+ // when we know how many there are, go back and validate the tokens.
+ pushNode(new LiteralString(token, null));
}
-}
-class PartialSetterElement extends SetterElementX
- with PartialElement, PartialFunctionMixin
- implements SetterElement, PartialFunctionElement {
- PartialSetterElement(String name,
- Token beginToken,
- Token setToken,
- Token endToken,
- Modifiers modifiers,
- Element enclosing,
- {bool hasBody: true})
- : super(name, modifiers, enclosing, hasBody) {
- init(beginToken, setToken, endToken);
+ void handleStringPart(Token token) {
+ // Just push an unvalidated token now, and replace it when we know the
+ // end of the interpolation.
+ pushNode(new LiteralString(token, null));
}
- @override
- GetterElement get getter => abstractField.getter;
+ void endLiteralString(int count) {
+ StringQuoting quoting = popQuoting();
- void reuseElement() {
- super.reuseElement();
- reusePartialFunctionMixin();
- }
+ Link<StringInterpolationPart> parts =
+ const Link<StringInterpolationPart>();
+ // Parts of the string interpolation are popped in reverse order,
+ // starting with the last literal string part.
+ bool isLast = true;
+ for (int i = 0; i < count; i++) {
+ LiteralString string = popNode();
+ DartString validation =
+ stringValidator.validateInterpolationPart(string.token, quoting,
+ isFirst: false,
+ isLast: isLast);
+ // Replace the unvalidated LiteralString with a new LiteralString
+ // object that has the validation result included.
+ string = new LiteralString(string.token, validation);
+ Expression expression = popNode();
+ parts = parts.prepend(new StringInterpolationPart(expression, string));
+ isLast = false;
+ }
- PartialSetterElement copyWithEnclosing(Element enclosing) {
- return new PartialSetterElement(
- name, beginToken, getOrSet, endToken, modifiers, enclosing,
- hasBody: hasBody);
+ LiteralString string = popNode();
+ DartString validation =
+ stringValidator.validateInterpolationPart(string.token, quoting,
+ isFirst: true,
+ isLast: isLast);
+ string = new LiteralString(string.token, validation);
+ if (isLast) {
+ pushNode(string);
+ } else {
+ NodeList partNodes = new NodeList(null, parts, null, "");
+ pushNode(new StringInterpolation(string, partNodes));
+ }
}
-}
-class PartialConstructorElement extends ConstructorElementX
- with PartialElement, PartialFunctionMixin {
- PartialConstructorElement(String name,
- Token beginToken,
- Token endToken,
- ElementKind kind,
- Modifiers modifiers,
- Element enclosing)
- : super(name, kind, modifiers, enclosing) {
- init(beginToken, null, endToken);
+ void handleStringJuxtaposition(int stringCount) {
+ assert(stringCount != 0);
+ Expression accumulator = popNode();
+ stringCount--;
+ while (stringCount > 0) {
+ Expression expression = popNode();
+ accumulator = new StringJuxtaposition(expression, accumulator);
+ stringCount--;
+ }
+ pushNode(accumulator);
}
- void reuseElement() {
- super.reuseElement();
- reusePartialFunctionMixin();
+ void beginMember(Token token) {
+ memberErrors = memberErrors.prepend(false);
}
-}
-class PartialFieldList extends VariableList with PartialElement {
- PartialFieldList(Token beginToken,
- Token endToken,
- Modifiers modifiers,
- bool hasParseError)
- : super(modifiers) {
- super.beginToken = beginToken;
- super.endToken = endToken;
- super.hasParseError = hasParseError;
- }
-
- VariableDefinitions parseNode(Element element, DiagnosticListener listener) {
- if (definitions != null) return definitions;
- listener.withCurrentElement(element, () {
- definitions = parse(
- listener, element, declarationSite,
- (Parser parser) => parser.parseMember(beginToken));
-
- if (!hasParseError &&
- !definitions.modifiers.isVar &&
- !definitions.modifiers.isFinal &&
- !definitions.modifiers.isConst &&
- definitions.type == null &&
- !definitions.isErroneous) {
- listener.reportError(
- definitions,
- MessageKind.GENERIC,
- { 'text': 'A field declaration must start with var, final, '
- 'const, or a type annotation.' });
- }
- });
- return definitions;
+ void beginTopLevelMember(Token token) {
+ beginMember(token);
}
- computeType(Element element, Compiler compiler) {
- if (type != null) return type;
- // TODO(johnniwinther): Compute this in the resolver.
- compiler.withCurrentElement(element, () {
- VariableDefinitions node = parseNode(element, compiler);
- if (node.type != null) {
- type = compiler.resolver.resolveTypeAnnotation(element, node.type);
- } else {
- type = const DynamicType();
- }
- });
- assert(type != null);
- return type;
+ void endFields(fieldCount, start, token) {
+ memberErrors = memberErrors.tail;
}
-}
-class PartialTypedefElement extends TypedefElementX with PartialElement {
-
- PartialTypedefElement(
- String name,
- Element enclosing,
- Token beginToken,
- Token endToken)
- : super(name, enclosing) {
- this.beginToken = beginToken;
- this.endToken = endToken;
+ void endMethod(getOrSet, start, token) {
+ memberErrors = memberErrors.tail;
}
- Token get token => beginToken;
-
- Node parseNode(DiagnosticListener listener) {
- if (cachedNode != null) return cachedNode;
- cachedNode = parse(
- listener, this, declarationSite,
- (p) => p.parseTopLevelDeclaration(token));
- return cachedNode;
+ void beginFactoryMethod(Token token) {
+ memberErrors = memberErrors.prepend(false);
}
- Token get position => findMyName(token);
-}
-
-/// A [MetadataAnnotation] which is constructed on demand.
-class PartialMetadataAnnotation extends MetadataAnnotationX
- implements PartialElement {
- Token beginToken; // TODO(ahe): Make this final when issue 22065 is fixed.
-
- final Token tokenAfterEndToken;
-
- Expression cachedNode;
-
- bool hasParseError = false;
-
- PartialMetadataAnnotation(this.beginToken, this.tokenAfterEndToken);
-
- bool get isErroneous => hasParseError;
-
- DeclarationSite get declarationSite => this;
-
- Token get endToken {
- Token token = beginToken;
- while (token.kind != EOF_TOKEN) {
- if (identical(token.next, tokenAfterEndToken)) break;
- token = token.next;
- }
- assert(token != null);
- return token;
+ void endFactoryMethod(Token beginToken, Token endToken) {
+ memberErrors = memberErrors.tail;
}
- void set endToken(_) {
- throw new UnsupportedError("endToken=");
+ /// Don't call this method. Should only be used as a last resort when there
+ /// is no feasible way to recover from a parser error.
+ void reportFatalError(Spannable spannable, String message) {
+ reportError(spannable, MessageKind.GENERIC, {'text': message});
+ // Some parse errors are infeasible to recover from, so we throw an error.
+ throw new ParserError(message);
}
- Node parseNode(DiagnosticListener listener) {
- if (cachedNode != null) return cachedNode;
- var metadata = parse(listener,
- annotatedElement,
- declarationSite,
- (p) => p.parseMetadata(beginToken));
- if (metadata is Metadata) {
- cachedNode = metadata.expression;
- return cachedNode;
- } else {
- assert (metadata is ErrorNode);
- return metadata;
+ void reportError(Spannable spannable,
+ MessageKind errorCode,
+ [Map arguments = const {}]) {
+ if (currentMemberHasParseError) return; // Error already reported.
+ if (suppressParseErrors) return;
+ if (!memberErrors.isEmpty) {
+ memberErrors = memberErrors.tail.prepend(true);
}
+ listener.reportError(spannable, errorCode, arguments);
}
-
- bool get hasNode => cachedNode != null;
-
- Node get node {
- assert(invariant(this, hasNode));
- return cachedNode;
- }
-}
-
-Node parse(
- DiagnosticListener diagnosticListener,
- ElementX element,
- PartialElement partial,
- doParse(Parser parser)) {
- CompilationUnitElement unit = element.compilationUnit;
- NodeListener listener = new NodeListener(diagnosticListener, unit);
- listener.memberErrors = listener.memberErrors.prepend(false);
- try {
- if (partial.hasParseError) {
- listener.suppressParseErrors = true;
- }
- doParse(new Parser(listener));
- } on ParserError catch (e) {
- partial.hasParseError = true;
- return new ErrorNode(element.position, e.reason);
- }
- Node node = listener.popNode();
- assert(listener.nodes.isEmpty);
- return node;
}

Powered by Google App Engine
This is Rietveld 408576698