Chromium Code Reviews| Index: pkg/compiler/lib/src/parser/partial_elements.dart |
| diff --git a/pkg/compiler/lib/src/parser/partial_elements.dart b/pkg/compiler/lib/src/parser/partial_elements.dart |
| index 145264193a261e5d5027e7b42d86fad0e4548b78..0b489a128a970b69623a60041798b99ea9bf53fd 100644 |
| --- a/pkg/compiler/lib/src/parser/partial_elements.dart |
| +++ b/pkg/compiler/lib/src/parser/partial_elements.dart |
| @@ -1,8 +1,8 @@ |
| -// 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.partial_elements; |
| import '../compiler.dart' show |
| Compiler; |
| @@ -11,9 +11,6 @@ import '../diagnostics/diagnostic_listener.dart'; |
| import '../diagnostics/invariant.dart' show |
| invariant; |
| import '../diagnostics/messages.dart'; |
| -import '../diagnostics/spannable.dart' show |
| - Spannable, |
| - SpannableAssertionFailure; |
| import '../elements/elements.dart' show |
| CompilationUnitElement, |
| ConstructorElement, |
| @@ -23,2308 +20,47 @@ import '../elements/elements.dart' show |
| LibraryElement, |
| MetadataAnnotation, |
| MethodElement, |
| - SetterElement; |
| + SetterElement, |
| + STATE_NOT_STARTED, |
| + STATE_DONE; |
| import '../elements/modelx.dart' show |
| BaseFunctionElementX, |
| + ClassElementX, |
| 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 '../elements/visitor.dart' show |
| + ElementVisitor; |
| import '../tokens/token.dart' show |
| - BAD_INPUT_INFO, |
| BadInputToken, |
| BeginGroupToken, |
| - EOF_INFO, |
| - EOF_TOKEN, |
| ErrorToken, |
| - IDENTIFIER_INFO, |
| - INDEX_INFO, |
| KeywordToken, |
| StringToken, |
| Token, |
| UnmatchedToken, |
| UnterminatedToken; |
| +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; |
| + ClassElementParser; |
| import 'parser.dart' show |
| Parser; |
| - |
| -const bool VERBOSE = false; |
| - |
| -/** |
| - * A parser event listener that does nothing except throw exceptions |
| - * on parser errors. |
| - */ |
| -class Listener { |
| - set suppressParseErrors(bool value) { |
| - } |
| - |
| - void beginArguments(Token token) { |
| - } |
| - |
| - void endArguments(int count, Token beginToken, Token endToken) { |
| - } |
| - |
| - /// Handle async modifiers `async`, `async*`, `sync`. |
| - void handleAsyncModifier(Token asyncToken, Token startToken) { |
| - } |
| - |
| - void beginAwaitExpression(Token token) { |
| - } |
| - |
| - void endAwaitExpression(Token beginToken, Token endToken) { |
| - } |
| - |
| - void beginBlock(Token token) { |
| - } |
| - |
| - void endBlock(int count, Token beginToken, Token endToken) { |
| - } |
| - |
| - void beginCascade(Token token) { |
| - } |
| - |
| - void endCascade() { |
| - } |
| - |
| - void beginClassBody(Token token) { |
| - } |
| - |
| - void endClassBody(int memberCount, Token beginToken, Token endToken) { |
| - } |
| - |
| - void beginClassDeclaration(Token token) { |
| - } |
| - |
| - void endClassDeclaration(int interfacesCount, Token beginToken, |
| - Token extendsKeyword, Token implementsKeyword, |
| - Token endToken) { |
| - } |
| - |
| - void beginCombinators(Token token) { |
| - } |
| - |
| - void endCombinators(int count) { |
| - } |
| - |
| - void beginCompilationUnit(Token token) { |
| - } |
| - |
| - void endCompilationUnit(int count, Token token) { |
| - } |
| - |
| - void beginConstructorReference(Token start) { |
| - } |
| - |
| - void endConstructorReference(Token start, Token periodBeforeName, |
| - Token endToken) { |
| - } |
| - |
| - void beginDoWhileStatement(Token token) { |
| - } |
| - |
| - void endDoWhileStatement(Token doKeyword, Token whileKeyword, |
| - Token endToken) { |
| - } |
| - |
| - void beginEnum(Token enumKeyword) { |
| - } |
| - |
| - void endEnum(Token enumKeyword, Token endBrace, int count) { |
| - } |
| - |
| - void beginExport(Token token) { |
| - } |
| - |
| - void endExport(Token exportKeyword, Token semicolon) { |
| - } |
| - |
| - void beginExpressionStatement(Token token) { |
| - } |
| - |
| - void endExpressionStatement(Token token) { |
| - } |
| - |
| - void beginFactoryMethod(Token token) { |
| - } |
| - |
| - void endFactoryMethod(Token beginToken, Token endToken) { |
| - } |
| - |
| - void beginFormalParameter(Token token) { |
| - } |
| - |
| - void endFormalParameter(Token thisKeyword) { |
| - } |
| - |
| - void handleNoFormalParameters(Token token) { |
| - } |
| - |
| - void beginFormalParameters(Token token) { |
| - } |
| - |
| - void endFormalParameters(int count, Token beginToken, Token endToken) { |
| - } |
| - |
| - void endFields(int count, Token beginToken, Token endToken) { |
| - } |
| - |
| - void beginForStatement(Token token) { |
| - } |
| - |
| - void endForStatement(int updateExpressionCount, |
| - Token beginToken, Token endToken) { |
| - } |
| - |
| - void endForIn(Token awaitToken, Token forToken, |
| - Token inKeyword, Token endToken) { |
| - } |
| - |
| - void beginFunction(Token token) { |
| - } |
| - |
| - void endFunction(Token getOrSet, Token endToken) { |
| - } |
| - |
| - void beginFunctionDeclaration(Token token) { |
| - } |
| - |
| - void endFunctionDeclaration(Token token) { |
| - } |
| - |
| - void beginFunctionBody(Token token) { |
| - } |
| - |
| - void endFunctionBody(int count, Token beginToken, Token endToken) { |
| - } |
| - |
| - void handleNoFunctionBody(Token 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}"); |
| - } |
| - |
| - Token expectedFunctionBody(Token token) { |
| - if (identical(token.stringValue, 'native')) { |
| - return native.handleNativeFunctionBody(this, token); |
| - } else if (token is ErrorToken) { |
| - pushNode(null); |
| - reportErrorToken(token); |
| - } else { |
| - reportFatalError(token, |
| - "Expected a function body, but got '${token.value}'."); |
| - } |
| - return skipToEof(token); |
| - } |
| - |
| - Token expectedClassBody(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.'); |
| - } |
| - if (argumentSend.receiver != null) internalError(node: argument); |
| - if (argument is SendSet) internalError(node: argument); |
| - pushNode(argument.asSend().copyWithReceiver(receiver, |
| - identical(tokenString, '?.'))); |
| - } 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}); |
| - } |
| - } |
| - |
| - 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); |
| - } |
| - 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))); |
| - } |
| - } |
| - |
| - void handleAsyncModifier(Token asyncToken, Token starToken) { |
| - if (asyncToken != null) { |
| - pushNode(new AsyncModifier(asyncToken, starToken)); |
| - } else { |
| - pushNode(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); |
| - } |
| - } |
| - |
| - 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)); |
| - } 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(); |
| - } |
| - pushNode(new ContinueStatement(target, continueKeyword, endToken)); |
| - } |
| - |
| - void handleEmptyStatement(Token token) { |
| - pushNode(new EmptyStatement(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; |
| - } |
| - 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)); |
| - } else { |
| - pushNode(new AsyncForIn(declaredIdentifier, expression, body, awaitToken, |
| - forToken, inKeyword)); |
| - } |
| - } |
| - |
| - 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, ' ')); |
| - } |
| - } |
| - } |
| - |
| - 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)); |
| - } 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)))); |
| - } |
| - } |
| - |
| - 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)); |
| - } |
| - |
| - 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)); |
| - } else { |
| - argument = type; |
| - } |
| - |
| - NodeList arguments = new NodeList.singleton(argument); |
| - pushNode(new Send(expression, new Operator(operathor), arguments)); |
| - } |
| - |
| - void handleLabel(Token colon) { |
| - Identifier name = popNode(); |
| - pushNode(new Label(name, colon)); |
| - } |
| - |
| - void endLabeledStatement(int labelCount) { |
| - Statement statement = popNode(); |
| - NodeList labels = makeNodeList(labelCount, null, null, null); |
| - pushNode(new LabeledStatement(labels, statement)); |
| - } |
| - |
| - void log(message) { |
| - listener.log(message); |
| - } |
| - |
| - 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.'); |
| - } |
| -} |
| +import 'listener.dart' show |
| + ParserError; |
| +import 'member_listener.dart' show |
| + MemberListener; |
| +import 'node_listener.dart' show |
| + NodeListener; |
| abstract class PartialElement implements DeclarationSite { |
| Token beginToken; |
| @@ -2615,7 +351,7 @@ class PartialMetadataAnnotation extends MetadataAnnotationX |
| Token get endToken { |
| Token token = beginToken; |
| - while (token.kind != EOF_TOKEN) { |
| + while (token.kind != Tokens.EOF_TOKEN) { |
| if (identical(token.next, tokenAfterEndToken)) break; |
| token = token.next; |
| } |
| @@ -2650,6 +386,96 @@ class PartialMetadataAnnotation extends MetadataAnnotationX |
| } |
| } |
| +class PartialClassElement extends ClassElementX with PartialElement { |
|
Johnni Winther
2015/09/02 13:14:41
Moved from class_element_parser.dart
|
| + ClassNode cachedNode; |
| + |
| + PartialClassElement(String name, |
| + Token beginToken, |
| + Token endToken, |
| + Element enclosing, |
| + int id) |
| + : super(name, enclosing, id, STATE_NOT_STARTED) { |
| + this.beginToken = beginToken; |
| + this.endToken = endToken; |
| + } |
| + |
| + void set supertypeLoadState(int state) { |
| + assert(state == STATE_NOT_STARTED || state == supertypeLoadState + 1); |
| + assert(state <= STATE_DONE); |
| + super.supertypeLoadState = state; |
| + } |
| + |
| + void set resolutionState(int state) { |
| + assert(state == STATE_NOT_STARTED || state == resolutionState + 1); |
| + assert(state <= STATE_DONE); |
| + super.resolutionState = state; |
| + } |
| + |
| + bool get hasNode => cachedNode != null; |
| + |
| + ClassNode get node { |
| + assert(invariant(this, cachedNode != null, |
| + message: "Node has not been computed for $this.")); |
| + return cachedNode; |
| + } |
| + |
| + ClassNode parseNode(Compiler compiler) { |
| + if (cachedNode != null) return cachedNode; |
| + compiler.withCurrentElement(this, () { |
| + compiler.parser.measure(() { |
| + MemberListener listener = new MemberListener(compiler, this); |
| + Parser parser = new ClassElementParser(listener); |
| + try { |
| + Token token = parser.parseTopLevelDeclaration(beginToken); |
| + assert(identical(token, endToken.next)); |
| + cachedNode = listener.popNode(); |
| + assert( |
| + invariant( |
| + beginToken, listener.nodes.isEmpty, |
| + message: "Non-empty listener stack: ${listener.nodes}")); |
| + } on ParserError { |
| + // TODO(ahe): Often, a ParserError is thrown while parsing the class |
| + // body. This means that the stack actually contains most of the |
| + // information synthesized below. Consider rewriting the parser so |
| + // endClassDeclaration is called before parsing the class body. |
| + Identifier name = new Identifier(findMyName(beginToken)); |
| + NodeList typeParameters = null; |
| + Node supertype = null; |
| + NodeList interfaces = listener.makeNodeList(0, null, null, ","); |
| + Token extendsKeyword = null; |
| + NodeList body = listener.makeNodeList(0, beginToken, endToken, null); |
| + cachedNode = new ClassNode( |
| + Modifiers.EMPTY, name, typeParameters, supertype, interfaces, |
| + beginToken, extendsKeyword, body, endToken); |
| + hasParseError = true; |
| + } |
| + }); |
| + compiler.patchParser.measure(() { |
| + if (isPatched) { |
| + // TODO(lrn): Perhaps extract functionality so it doesn't |
| + // need compiler. |
| + compiler.patchParser.parsePatchClassNode(patch); |
| + } |
| + }); |
| + }); |
| + return cachedNode; |
| + } |
| + |
| + Token get position => beginToken; |
| + |
| + // TODO(johnniwinther): Ensure that modifiers are always available. |
| + Modifiers get modifiers => |
| + cachedNode != null ? cachedNode.modifiers : Modifiers.EMPTY; |
| + |
| + accept(ElementVisitor visitor, arg) { |
| + return visitor.visitClassElement(this, arg); |
| + } |
| + |
| + PartialClassElement copyWithEnclosing(CompilationUnitElement enclosing) { |
| + return new PartialClassElement(name, beginToken, endToken, enclosing, id); |
| + } |
| +} |
| + |
| Node parse( |
| DiagnosticListener diagnosticListener, |
| ElementX element, |