| // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| // for details. All rights reserved. Use of this source code is governed by a |
| // BSD-style license that can be found in the LICENSE file. |
| |
| library dart2js.parser.listener; |
| |
| import '../diagnostics/messages.dart'; |
| import '../diagnostics/spannable.dart' show |
| Spannable, |
| SpannableAssertionFailure; |
| import '../tokens/precedence_constants.dart' as Precedence show |
| EOF_INFO, |
| IDENTIFIER_INFO; |
| import '../tokens/token.dart' show |
| BadInputToken, |
| BeginGroupToken, |
| ErrorToken, |
| StringToken, |
| Token, |
| UnmatchedToken, |
| UnterminatedToken; |
| import '../tree/tree.dart'; |
| |
| 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 commaToken, 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( |
| Precedence.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, Precedence.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; |
| } |