| // Copyright (c) 2018, 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 fasta.type_promotion_look_ahead_listener; |
| |
| import 'package:_fe_analyzer_shared/src/messages/severity.dart' show Severity; |
| |
| import 'package:_fe_analyzer_shared/src/parser/parser.dart' |
| show |
| Assert, |
| BlockKind, |
| DeclarationKind, |
| FormalParameterKind, |
| IdentifierContext, |
| Listener, |
| MemberKind; |
| |
| import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' show Token; |
| |
| import '../builder/builder.dart'; |
| |
| import '../messages.dart' show LocatedMessage, Message, MessageCode; |
| |
| import '../problems.dart' as problems show unhandled; |
| |
| import '../scope.dart' show Scope; |
| |
| final NoArguments noArgumentsSentinel = new NoArguments(); |
| |
| abstract class TypePromotionState { |
| final Uri uri; |
| |
| final List<Scope> scopes = <Scope>[new Scope.top(isModifiable: true)]; |
| |
| final List<Builder> stack = <Builder>[]; |
| |
| TypePromotionState(this.uri); |
| |
| Scope get currentScope => scopes.last; |
| |
| void enterScope(String debugName) { |
| scopes.add(new Scope.nested(currentScope, "block")); |
| } |
| |
| Scope exitScope(Token token) { |
| return scopes.removeLast(); |
| } |
| |
| void declareIdentifier(Token token) { |
| String name = token.lexeme; |
| LocatedMessage error = currentScope.declare( |
| name, new UnspecifiedDeclaration(name, uri, token.charOffset), uri); |
| if (error != null) { |
| report(error, Severity.error); |
| } |
| pushNull(token.lexeme, token); |
| } |
| |
| void registerWrite(UnspecifiedDeclaration declaration, Token token) {} |
| |
| void registerPromotionCandidate( |
| UnspecifiedDeclaration declaration, Token token) {} |
| |
| void pushReference(Token token) { |
| String name = token.lexeme; |
| Builder declaration = currentScope.lookup(name, token.charOffset, uri); |
| stack.add(declaration); |
| } |
| |
| Builder pop() => stack.removeLast(); |
| |
| void push(Builder declaration) { |
| stack.add(declaration); |
| } |
| |
| Builder popPushNull(String name, Token token) { |
| int last = stack.length - 1; |
| Builder declaration = stack[last]; |
| stack[last] = nullValue(name, token); |
| return declaration; |
| } |
| |
| void discard(int count) { |
| stack.length = stack.length - count; |
| } |
| |
| void pushNull(String name, Token token) { |
| stack.add(nullValue(name, token)); |
| } |
| |
| Builder nullValue(String name, Token token) => null; |
| |
| void report(LocatedMessage message, Severity severity, |
| {List<LocatedMessage> context}); |
| |
| void trace(String message, Token token) {} |
| |
| void checkEmpty(Token token) {} |
| } |
| |
| class UnspecifiedDeclaration extends BuilderImpl { |
| final String name; |
| |
| @override |
| final Uri fileUri; |
| |
| @override |
| int charOffset; |
| |
| UnspecifiedDeclaration(this.name, this.fileUri, this.charOffset); |
| |
| @override |
| Builder get parent => null; |
| |
| @override |
| String get fullNameForErrors => name; |
| |
| @override |
| String toString() => "UnspecifiedDeclaration($name)"; |
| } |
| |
| class NoArguments extends BuilderImpl { |
| NoArguments(); |
| |
| @override |
| Uri get fileUri => null; |
| |
| @override |
| int get charOffset => -1; |
| |
| @override |
| Builder get parent => null; |
| |
| @override |
| String get fullNameForErrors => "<<no arguments>>"; |
| |
| @override |
| String toString() => fullNameForErrors; |
| } |
| |
| class TypePromotionLookAheadListener extends Listener { |
| final TypePromotionState state; |
| |
| TypePromotionLookAheadListener(this.state); |
| |
| Uri get uri => state.uri; |
| |
| void logEvent(String name) { |
| throw new UnimplementedError(name); |
| } |
| |
| void debugEvent(String name, Token token) { |
| // state.trace(name, token); |
| } |
| |
| @override |
| void endArguments(int count, Token beginToken, Token endToken) { |
| debugEvent("Arguments", beginToken); |
| state.discard(count); |
| state.pushNull("%Arguments%", endToken); |
| } |
| |
| @override |
| void handleNoArguments(Token token) { |
| debugEvent("NoArguments", token); |
| state.push(noArgumentsSentinel); |
| } |
| |
| @override |
| void handleAsOperator(Token operator) { |
| debugEvent("AsOperator", operator); |
| state.popPushNull(operator.lexeme, operator); |
| } |
| |
| @override |
| void endAssert(Token assertKeyword, Assert kind, Token leftParenthesis, |
| Token commaToken, Token semicolonToken) { |
| debugEvent("Assert", assertKeyword); |
| if (commaToken != null) { |
| state.pop(); // Message. |
| } |
| state.pop(); // Condition. |
| switch (kind) { |
| case Assert.Expression: |
| state.pushNull("%AssertExpression%", assertKeyword); |
| break; |
| |
| case Assert.Initializer: |
| state.pushNull("%AssertInitializer%", assertKeyword); |
| break; |
| |
| case Assert.Statement: |
| break; |
| } |
| } |
| |
| @override |
| void handleAssignmentExpression(Token token) { |
| debugEvent("AssignmentExpression", token); |
| state.pop(); // Right-hand side. |
| Builder lhs = state.popPushNull(token.lexeme, token); |
| if (lhs is UnspecifiedDeclaration) { |
| state.registerWrite(lhs, token); |
| } |
| } |
| |
| @override |
| void handleAsyncModifier(Token asyncToken, Token starToken) { |
| debugEvent("AsyncModifier", asyncToken); |
| } |
| |
| @override |
| void endAwaitExpression(Token beginToken, Token endToken) { |
| debugEvent("AwaitExpression", beginToken); |
| state.popPushNull(beginToken.lexeme, beginToken); // Expression. |
| } |
| |
| @override |
| void endInvalidAwaitExpression( |
| Token beginToken, Token endToken, MessageCode errorCode) { |
| debugEvent("InvalidAwaitExpression", beginToken); |
| state.popPushNull(beginToken.lexeme, beginToken); // Expression. |
| } |
| |
| @override |
| void endBinaryExpression(Token token) { |
| debugEvent("BinaryExpression", token); |
| state.pop(); // Right-hand side. |
| state.popPushNull(token.lexeme, token); // Left-hand side. |
| } |
| |
| @override |
| void beginBlock(Token token, BlockKind blockKind) { |
| debugEvent("beginBlock", token); |
| state.enterScope("block"); |
| } |
| |
| @override |
| void endBlock( |
| int count, Token beginToken, Token endToken, BlockKind blockKind) { |
| debugEvent("Block", beginToken); |
| state.exitScope(endToken); |
| } |
| |
| @override |
| void beginBlockFunctionBody(Token token) { |
| debugEvent("beginBlockFunctionBody", token); |
| state.enterScope("block-function-body"); |
| } |
| |
| @override |
| void endBlockFunctionBody(int count, Token beginToken, Token endToken) { |
| debugEvent("BlockFunctionBody", beginToken); |
| state.exitScope(endToken); |
| } |
| |
| @override |
| void handleBreakStatement( |
| bool hasTarget, Token breakKeyword, Token endToken) { |
| debugEvent("BreakStatement", breakKeyword); |
| if (hasTarget) { |
| state.pop(); // Target. |
| } |
| } |
| |
| @override |
| void endCascade() { |
| debugEvent("Cascade", null); |
| state.popPushNull("%Cascade%", null); |
| } |
| |
| @override |
| void endCaseExpression(Token colon) { |
| debugEvent("CaseExpression", colon); |
| state.pop(); // Expression. |
| } |
| |
| @override |
| void handleCaseMatch(Token caseKeyword, Token colon) { |
| debugEvent("CaseMatch", caseKeyword); |
| } |
| |
| @override |
| void handleCatchBlock(Token onKeyword, Token catchKeyword, Token comma) { |
| debugEvent("CatchBlock", catchKeyword); |
| } |
| |
| @override |
| void endCatchClause(Token token) { |
| debugEvent("CatchClause", token); |
| } |
| |
| @override |
| void endClassDeclaration(Token beginToken, Token endToken) { |
| debugEvent("ClassDeclaration", beginToken); |
| state.checkEmpty(endToken); |
| } |
| |
| @override |
| void handleClassExtends(Token extendsKeyword) { |
| debugEvent("ClassExtends", extendsKeyword); |
| } |
| |
| @override |
| void handleClassHeader(Token begin, Token classKeyword, Token nativeToken) { |
| debugEvent("ClassHeader", begin); |
| state.pop(); // Class name. |
| state.checkEmpty(classKeyword); |
| } |
| |
| @override |
| void handleClassNoWithClause() { |
| debugEvent("ClassNoWithClause", null); |
| } |
| |
| @override |
| void endClassOrMixinBody( |
| DeclarationKind kind, int memberCount, Token beginToken, Token endToken) { |
| debugEvent("ClassOrMixinBody", beginToken); |
| state.checkEmpty(endToken); |
| } |
| |
| @override |
| void handleClassOrMixinImplements( |
| Token implementsKeyword, int interfacesCount) { |
| debugEvent("ClassOrMixinImplements", implementsKeyword); |
| } |
| |
| @override |
| void handleClassWithClause(Token withKeyword) { |
| debugEvent("ClassWithClause", withKeyword); |
| } |
| |
| @override |
| void endCombinators(int count) { |
| debugEvent("Combinators", null); |
| } |
| |
| @override |
| void handleCommentReference( |
| Token newKeyword, Token prefix, Token period, Token token) { |
| debugEvent("CommentReference", newKeyword); |
| unhandled("CommentReference", newKeyword); |
| } |
| |
| @override |
| void handleNoCommentReference() { |
| debugEvent("NoCommentReference", null); |
| unhandled("NoCommentReference", null); |
| } |
| |
| @override |
| void handleCommentReferenceText(String referenceSource, int referenceOffset) { |
| debugEvent("CommentReferenceText", null); |
| unhandled("CommentReferenceText", null); |
| } |
| |
| @override |
| void endCompilationUnit(int count, Token token) { |
| debugEvent("CompilationUnit", token); |
| print(state.stack); |
| } |
| |
| @override |
| void endConditionalExpression(Token question, Token colon) { |
| debugEvent("ConditionalExpression", question); |
| state.pop(); // Otherwise expression. |
| state.pop(); // Then expression. |
| state.popPushNull(question.lexeme, question); // Condition. |
| } |
| |
| @override |
| void handleConditionalExpressionColon() { |
| debugEvent("ConditionalExpressionColon", null); |
| // TODO(ahe): Rename this event. This is not handling any colons as it |
| // isn't being passed a colon. One alternative is |
| // handleConditionalThenExpression, but check the specification for naming |
| // conventions. Kernel uses "then" and "otherwise". |
| } |
| |
| @override |
| void endConditionalUri(Token ifKeyword, Token leftParen, Token equalSign) { |
| debugEvent("ConditionalUri", ifKeyword); |
| unhandled("ConditionalUri", ifKeyword); |
| } |
| |
| @override |
| void endConditionalUris(int count) { |
| debugEvent("ConditionalUris", null); |
| } |
| |
| @override |
| void endConstExpression(Token token) { |
| debugEvent("ConstExpression", token); |
| doConstuctorInvocation(token, true); |
| } |
| |
| @override |
| void endForControlFlow(Token token) { |
| // TODO(danrubel) add support for for control flow collection entries |
| // but for now this is ignored and an error reported in the body builder. |
| } |
| |
| @override |
| void endForInControlFlow(Token token) { |
| // TODO(danrubel) add support for for control flow collection entries |
| // but for now this is ignored and an error reported in the body builder. |
| } |
| |
| @override |
| void handleElseControlFlow(Token token) {} |
| |
| @override |
| void endIfControlFlow(Token token) { |
| state.pop(); // Element. |
| state.pop(); // Condition. |
| state.pushNull("%IfControlFlow%", token); |
| } |
| |
| @override |
| void endIfElseControlFlow(Token token) { |
| state.pop(); // Else element. |
| state.pop(); // Then element. |
| state.pop(); // Condition. |
| state.pushNull("%IfElseControlFlow%", token); |
| } |
| |
| @override |
| void handleSpreadExpression(Token spreadToken) { |
| // TODO(danrubel) add support for spread collections |
| // but for now this is ignored and an error reported in the body builder. |
| // The top of stack is the spread collection expression. |
| } |
| |
| void doConstuctorInvocation(Token token, bool isConst) { |
| state.pop(); // Arguments. |
| state.popPushNull(token.lexeme, token); // Constructor reference. |
| } |
| |
| @override |
| void endConstLiteral(Token token) { |
| debugEvent("ConstLiteral", token); |
| state.popPushNull("%ConstLiteral%", token); |
| } |
| |
| @override |
| void endConstructorReference( |
| Token start, Token periodBeforeName, Token endToken) { |
| debugEvent("ConstructorReference", start); |
| if (periodBeforeName != null) { |
| state.pop(); // Prefix. |
| } |
| state.popPushNull("%ConstructorReference%", start); |
| } |
| |
| @override |
| void handleNoConstructorReferenceContinuationAfterTypeArguments(Token token) { |
| debugEvent("NoConstructorReferenceContinuationAfterTypeArguments", token); |
| } |
| |
| @override |
| void handleContinueStatement( |
| bool hasTarget, Token continueKeyword, Token endToken) { |
| debugEvent("ContinueStatement", continueKeyword); |
| if (hasTarget) { |
| state.pop(); // Target. |
| } |
| } |
| |
| @override |
| void handleDirectivesOnly() { |
| debugEvent("DirectivesOnly", null); |
| unhandled("DirectivesOnly", null); |
| } |
| |
| @override |
| void endDoWhileStatement( |
| Token doKeyword, Token whileKeyword, Token endToken) { |
| debugEvent("DoWhileStatement", doKeyword); |
| state.pop(); // Condition. |
| } |
| |
| @override |
| void endDoWhileStatementBody(Token token) { |
| debugEvent("DoWhileStatementBody", token); |
| } |
| |
| @override |
| void handleDottedName(int count, Token firstIdentifier) { |
| debugEvent("DottedName", firstIdentifier); |
| unhandled("DottedName", firstIdentifier); |
| } |
| |
| @override |
| void endElseStatement(Token token) { |
| debugEvent("ElseStatement", token); |
| } |
| |
| @override |
| void handleEmptyFunctionBody(Token semicolon) { |
| debugEvent("EmptyFunctionBody", semicolon); |
| } |
| |
| @override |
| void handleEmptyStatement(Token token) { |
| debugEvent("EmptyStatement", token); |
| } |
| |
| @override |
| void beginEnum(Token enumKeyword) { |
| debugEvent("beginEnum", enumKeyword); |
| state.checkEmpty(enumKeyword); |
| } |
| |
| @override |
| void endEnum(Token enumKeyword, Token leftBrace, int count) { |
| debugEvent("endEnum", enumKeyword); |
| state.discard(count); // Enum values. |
| state.pop(); // Enum name. |
| state.checkEmpty(enumKeyword); |
| } |
| |
| @override |
| void endExport(Token exportKeyword, Token semicolon) { |
| debugEvent("Export", exportKeyword); |
| state.pop(); // Export URI. |
| state.checkEmpty(semicolon); |
| } |
| |
| @override |
| void handleExpressionFunctionBody(Token arrowToken, Token endToken) { |
| debugEvent("ExpressionFunctionBody", arrowToken); |
| state.pop(); |
| } |
| |
| @override |
| void handleExpressionStatement(Token token) { |
| debugEvent("ExpressionStatement", token); |
| state.pop(); |
| } |
| |
| @override |
| void handleExtraneousExpression(Token token, Message message) { |
| debugEvent("ExtraneousExpression", token); |
| unhandled("ExtraneousExpression", token); |
| } |
| |
| @override |
| void endClassFactoryMethod( |
| Token beginToken, Token factoryKeyword, Token endToken) { |
| debugEvent("ClassFactoryMethod", beginToken); |
| state.pop(); // Name. |
| state.checkEmpty(endToken); |
| } |
| |
| @override |
| void endFieldInitializer(Token assignment, Token token) { |
| debugEvent("FieldInitializer", assignment); |
| state.pop(); // Initializer. |
| } |
| |
| @override |
| void handleNoFieldInitializer(Token token) { |
| debugEvent("NoFieldInitializer", token); |
| } |
| |
| @override |
| void endClassFields(Token staticToken, Token covariantToken, Token lateToken, |
| Token varFinalOrConst, int count, Token beginToken, Token endToken) { |
| debugEvent("Fields", staticToken); |
| state.discard(count); // Field names. |
| state.checkEmpty(endToken); |
| } |
| |
| @override |
| void handleFinallyBlock(Token finallyKeyword) { |
| debugEvent("FinallyBlock", finallyKeyword); |
| } |
| |
| @override |
| void endForIn(Token endToken) { |
| debugEvent("ForIn", endToken); |
| } |
| |
| @override |
| void endForInBody(Token token) { |
| debugEvent("ForInBody", token); |
| } |
| |
| @override |
| void endForInExpression(Token token) { |
| debugEvent("ForInExpression", token); |
| state.pop(); // Expression. |
| } |
| |
| @override |
| void handleForInitializerEmptyStatement(Token token) { |
| debugEvent("ForInitializerEmptyStatement", token); |
| } |
| |
| @override |
| void handleForInitializerExpressionStatement(Token token, bool forIn) { |
| debugEvent("ForInitializerExpressionStatement", token); |
| state.pop(); // Expression. |
| } |
| |
| @override |
| void handleForInitializerLocalVariableDeclaration(Token token, bool forIn) { |
| debugEvent("ForInitializerLocalVariableDeclaration", token); |
| } |
| |
| @override |
| void handleForLoopParts(Token forKeyword, Token leftParen, |
| Token leftSeparator, int updateExpressionCount) { |
| debugEvent("handleForLoopParts", forKeyword); |
| state.discard(updateExpressionCount); |
| } |
| |
| @override |
| void endForStatement(Token endToken) { |
| debugEvent("ForStatement", endToken); |
| } |
| |
| @override |
| void endForStatementBody(Token token) { |
| debugEvent("ForStatementBody", token); |
| } |
| |
| @override |
| void endFormalParameter( |
| Token thisKeyword, |
| Token periodAfterThis, |
| Token nameToken, |
| Token initializerStart, |
| Token initializerEnd, |
| FormalParameterKind kind, |
| MemberKind memberKind) { |
| debugEvent("FormalParameter", thisKeyword); |
| state.pop(); // Parameter name. |
| } |
| |
| @override |
| void endFormalParameterDefaultValueExpression() { |
| debugEvent("FormalParameterDefaultValueExpression", null); |
| state.pop(); |
| } |
| |
| @override |
| void handleFormalParameterWithoutValue(Token token) { |
| debugEvent("FormalParameterWithoutValue", token); |
| } |
| |
| @override |
| void endFormalParameters( |
| int count, Token beginToken, Token endToken, MemberKind kind) { |
| debugEvent("FormalParameters", beginToken); |
| } |
| |
| @override |
| void handleNoFormalParameters(Token token, MemberKind kind) { |
| debugEvent("NoFormalParameters", token); |
| } |
| |
| @override |
| void handleNoFunctionBody(Token token) { |
| debugEvent("NoFunctionBody", token); |
| unhandled("NoFunctionBody", token); |
| } |
| |
| @override |
| void handleFunctionBodySkipped(Token token, bool isExpressionBody) { |
| debugEvent("FunctionBodySkipped", token); |
| unhandled("FunctionBodySkipped", token); |
| } |
| |
| @override |
| void endFunctionExpression(Token beginToken, Token token) { |
| debugEvent("FunctionExpression", beginToken); |
| state.pushNull("%function%", token); |
| } |
| |
| @override |
| void endFunctionName(Token beginToken, Token token) { |
| debugEvent("FunctionName", beginToken); |
| } |
| |
| @override |
| void endFunctionType(Token functionToken, Token questionMark) { |
| debugEvent("FunctionType", functionToken); |
| } |
| |
| @override |
| void endFunctionTypeAlias( |
| Token typedefKeyword, Token equals, Token endToken) { |
| debugEvent("FunctionTypeAlias", typedefKeyword); |
| state.pop(); // Name. |
| state.checkEmpty(endToken); |
| } |
| |
| @override |
| void endFunctionTypedFormalParameter(Token nameToken, Token question) { |
| debugEvent("FunctionTypedFormalParameter", nameToken); |
| } |
| |
| @override |
| void endHide(Token hideKeyword) { |
| debugEvent("Hide", hideKeyword); |
| } |
| |
| @override |
| void handleIdentifier(Token token, IdentifierContext context) { |
| debugEvent("Identifier ${context}", token); |
| if (context.inSymbol) { |
| // Do nothing. |
| } else if (context.inDeclaration) { |
| if (identical(IdentifierContext.localVariableDeclaration, context) || |
| identical(IdentifierContext.formalParameterDeclaration, context)) { |
| state.declareIdentifier(token); |
| } else { |
| state.pushNull(token.lexeme, token); |
| } |
| } else if (context.isContinuation) { |
| state.pushNull(token.lexeme, token); |
| } else if (context.isScopeReference) { |
| state.pushReference(token); |
| } else { |
| state.pushNull(token.lexeme, token); |
| } |
| } |
| |
| @override |
| void handleIdentifierList(int count) { |
| debugEvent("IdentifierList", null); |
| state.discard(count); |
| } |
| |
| @override |
| void endIfStatement(Token ifToken, Token elseToken) { |
| debugEvent("IfStatement", ifToken); |
| state.pop(); // Condition. |
| } |
| |
| @override |
| void endImplicitCreationExpression(Token token) { |
| debugEvent("ImplicitCreationExpression", token); |
| doConstuctorInvocation(token, false); |
| } |
| |
| @override |
| void endImport(Token importKeyword, Token semicolon) { |
| debugEvent("Import", importKeyword); |
| state.pop(); // Import URI. |
| state.checkEmpty(semicolon); |
| } |
| |
| @override |
| void handleImportPrefix(Token deferredKeyword, Token asKeyword) { |
| debugEvent("ImportPrefix", deferredKeyword); |
| if (asKeyword != null) { |
| state.pop(); // Prefix name. |
| } |
| } |
| |
| @override |
| void handleIndexedExpression( |
| Token openSquareBracket, Token closeSquareBracket) { |
| debugEvent("IndexedExpression", openSquareBracket); |
| state.pop(); // Index. |
| state.popPushNull("%indexed%", closeSquareBracket); // Expression. |
| } |
| |
| @override |
| void endInitializedIdentifier(Token nameToken) { |
| debugEvent("InitializedIdentifier", nameToken); |
| } |
| |
| @override |
| void endInitializer(Token token) { |
| debugEvent("Initializer", token); |
| state.pop(); // Initializer. |
| } |
| |
| @override |
| void endInitializers(int count, Token beginToken, Token endToken) { |
| debugEvent("Initializers", beginToken); |
| } |
| |
| @override |
| void handleNoInitializers() { |
| debugEvent("NoInitializers", null); |
| } |
| |
| @override |
| void handleInterpolationExpression(Token leftBracket, Token rightBracket) { |
| debugEvent("InterpolationExpression", leftBracket); |
| state.popPushNull(r"$", leftBracket); |
| } |
| |
| @override |
| void handleInvalidExpression(Token token) { |
| // TODO(ahe): The parser doesn't generate this event anymore. |
| debugEvent("InvalidExpression", token); |
| unhandled("InvalidExpression", token); |
| } |
| |
| @override |
| void handleInvalidFunctionBody(Token token) { |
| debugEvent("InvalidFunctionBody", token); |
| } |
| |
| @override |
| void handleInvalidMember(Token endToken) { |
| debugEvent("InvalidMember", endToken); |
| state.checkEmpty(endToken); |
| } |
| |
| @override |
| void handleInvalidOperatorName(Token operatorKeyword, Token token) { |
| debugEvent("InvalidOperatorName", operatorKeyword); |
| state.checkEmpty(operatorKeyword); |
| } |
| |
| @override |
| void handleInvalidStatement(Token token, Message message) { |
| debugEvent("InvalidStatement", token); |
| } |
| |
| @override |
| void handleInvalidTopLevelBlock(Token token) { |
| debugEvent("InvalidTopLevelBlock", token); |
| state.checkEmpty(token); |
| } |
| |
| @override |
| void handleInvalidTopLevelDeclaration(Token endToken) { |
| debugEvent("InvalidTopLevelDeclaration", endToken); |
| state.checkEmpty(endToken); |
| } |
| |
| @override |
| void handleInvalidTypeArguments(Token token) { |
| debugEvent("InvalidTypeArguments", token); |
| } |
| |
| @override |
| void handleInvalidTypeReference(Token token) { |
| debugEvent("InvalidTypeReference", token); |
| unhandled("InvalidTypeReference", token); |
| } |
| |
| @override |
| void handleIsOperator(Token isOperator, Token not) { |
| debugEvent("IsOperator", isOperator); |
| Builder lhs = state.popPushNull(isOperator.lexeme, isOperator); |
| if (not == null && lhs is UnspecifiedDeclaration) { |
| state.registerPromotionCandidate(lhs, isOperator); |
| } |
| } |
| |
| @override |
| void handleLabel(Token token) { |
| debugEvent("Label", token); |
| state.pop(); // Label. |
| } |
| |
| @override |
| void endLabeledStatement(int labelCount) { |
| debugEvent("LabeledStatement", null); |
| } |
| |
| @override |
| void endLibraryName(Token libraryKeyword, Token semicolon) { |
| debugEvent("LibraryName", libraryKeyword); |
| state.pop(); // Library name. |
| state.checkEmpty(semicolon); |
| } |
| |
| @override |
| void handleLiteralBool(Token token) { |
| debugEvent("LiteralBool", token); |
| state.pushNull(token.lexeme, token); |
| } |
| |
| @override |
| void handleLiteralDouble(Token token) { |
| debugEvent("LiteralDouble", token); |
| state.pushNull(token.lexeme, token); |
| } |
| |
| @override |
| void handleLiteralInt(Token token) { |
| debugEvent("LiteralInt", token); |
| state.pushNull(token.lexeme, token); |
| } |
| |
| @override |
| void handleLiteralList( |
| int count, Token leftBracket, Token constKeyword, Token rightBracket) { |
| debugEvent("LiteralList", leftBracket); |
| state.discard(count); |
| state.pushNull("[]", leftBracket); |
| } |
| |
| @override |
| void handleLiteralSetOrMap( |
| int count, |
| Token leftBrace, |
| Token constKeyword, |
| Token rightBrace, |
| // TODO(danrubel): hasSetEntry parameter exists for replicating existing |
| // behavior and will be removed once unified collection has been enabled |
| bool hasSetEntry, |
| ) { |
| debugEvent("LiteralSetOrMap", leftBrace); |
| state.discard(count); |
| state.pushNull("{}", leftBrace); |
| } |
| |
| @override |
| void handleLiteralMapEntry(Token colon, Token endToken) { |
| debugEvent("LiteralMapEntry", colon); |
| state.pop(); // Value. |
| state.popPushNull("%LiteralMapEntry%", colon); // Key. |
| } |
| |
| @override |
| void handleLiteralNull(Token token) { |
| debugEvent("LiteralNull", token); |
| state.pushNull(token.lexeme, token); |
| } |
| |
| @override |
| void beginLiteralString(Token token) { |
| debugEvent("beginLiteralString", token); |
| state.pushNull(token.lexeme, token); |
| } |
| |
| @override |
| void endLiteralString(int interpolationCount, Token endToken) { |
| debugEvent("LiteralString", endToken); |
| state.discard(interpolationCount * 2); |
| state.popPushNull("%string%", endToken); |
| } |
| |
| @override |
| void endLiteralSymbol(Token hashToken, int identifierCount) { |
| debugEvent("LiteralSymbol", hashToken); |
| state.pushNull(hashToken.lexeme, hashToken); |
| } |
| |
| @override |
| void endLocalFunctionDeclaration(Token endToken) { |
| debugEvent("LocalFunctionDeclaration", endToken); |
| state.pop(); // Function name. |
| } |
| |
| @override |
| void endMember() { |
| debugEvent("Member", null); |
| state.checkEmpty(null); |
| } |
| |
| @override |
| void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) { |
| debugEvent("Metadata", beginToken); |
| state.pop(); // Arguments. |
| if (periodBeforeName != null) { |
| state.pop(); // Suffix. |
| } |
| state.pop(); // Qualifier. |
| } |
| |
| @override |
| void endMetadataStar(int count) { |
| debugEvent("MetadataStar", null); |
| } |
| |
| @override |
| void beginMethod(Token externalToken, Token staticToken, Token covariantToken, |
| Token varFinalOrConst, Token getOrSet, Token name) { |
| debugEvent("beginMethod", name); |
| state.checkEmpty(name); |
| } |
| |
| @override |
| void endClassMethod(Token getOrSet, Token beginToken, Token beginParam, |
| Token beginInitializers, Token endToken) { |
| debugEvent("endMethod", endToken); |
| state.pop(); // Method name. |
| state.checkEmpty(endToken); |
| } |
| |
| @override |
| void endMixinDeclaration(Token mixinKeyword, Token endToken) { |
| debugEvent("MixinDeclaration", mixinKeyword); |
| state.checkEmpty(endToken); |
| } |
| |
| @override |
| void handleMixinHeader(Token mixinKeyword) { |
| debugEvent("MixinHeader", mixinKeyword); |
| state.pop(); // Mixin name. |
| state.checkEmpty(mixinKeyword); |
| } |
| |
| @override |
| void handleMixinOn(Token onKeyword, int typeCount) { |
| debugEvent("MixinOn", onKeyword); |
| } |
| |
| @override |
| void handleNoName(Token token) { |
| debugEvent("NoName", token); |
| state.pushNull("%NoName%", token); |
| } |
| |
| @override |
| void handleNamedArgument(Token colon) { |
| debugEvent("NamedArgument", colon); |
| state.pop(); // Expression. |
| state.popPushNull("%NamedArgument%", colon); // Identifier. |
| } |
| |
| @override |
| void endNamedFunctionExpression(Token endToken) { |
| debugEvent("NamedFunctionExpression", endToken); |
| state.popPushNull( |
| "%named function expression%", endToken); // Function name. |
| } |
| |
| @override |
| void endNamedMixinApplication(Token begin, Token classKeyword, Token equals, |
| Token implementsKeyword, Token endToken) { |
| debugEvent("NamedMixinApplication", begin); |
| state.pop(); // Mixin application name. |
| state.checkEmpty(endToken); |
| } |
| |
| @override |
| void handleNamedMixinApplicationWithClause(Token withKeyword) { |
| debugEvent("NamedMixinApplicationWithClause", withKeyword); |
| } |
| |
| @override |
| void handleNativeClause(Token nativeToken, bool hasName) { |
| debugEvent("NativeClause", nativeToken); |
| if (hasName) { |
| state.pop(); // Name. |
| } |
| } |
| |
| @override |
| void handleNativeFunctionBody(Token nativeToken, Token semicolon) { |
| debugEvent("NativeFunctionBody", nativeToken); |
| } |
| |
| @override |
| void handleNativeFunctionBodyIgnored(Token nativeToken, Token semicolon) { |
| debugEvent("NativeFunctionBodyIgnored", nativeToken); |
| } |
| |
| @override |
| void handleNativeFunctionBodySkipped(Token nativeToken, Token semicolon) { |
| debugEvent("NativeFunctionBodySkipped", nativeToken); |
| } |
| |
| @override |
| void endNewExpression(Token token) { |
| debugEvent("NewExpression", token); |
| doConstuctorInvocation(token, false); |
| } |
| |
| @override |
| void handleOperator(Token token) { |
| debugEvent("Operator", token); |
| unhandled("Operator", token); |
| } |
| |
| @override |
| void handleOperatorName(Token operatorKeyword, Token token) { |
| debugEvent("OperatorName", operatorKeyword); |
| state.pushNull(token.lexeme, token); |
| } |
| |
| @override |
| void endOptionalFormalParameters( |
| int count, Token beginToken, Token endToken) { |
| debugEvent("OptionalFormalParameters", beginToken); |
| } |
| |
| @override |
| void handleParenthesizedCondition(Token token) { |
| debugEvent("ParenthesizedCondition", token); |
| } |
| |
| @override |
| void handleParenthesizedExpression(Token token) { |
| debugEvent("ParenthesizedExpression", token); |
| state.popPushNull("%(expr)%", token); |
| } |
| |
| @override |
| void endPart(Token partKeyword, Token semicolon) { |
| debugEvent("Part", partKeyword); |
| state.pop(); // URI. |
| state.checkEmpty(semicolon); |
| } |
| |
| @override |
| void endPartOf( |
| Token partKeyword, Token ofKeyword, Token semicolon, bool hasName) { |
| debugEvent("PartOf", partKeyword); |
| state.pop(); // Name or URI. |
| state.checkEmpty(semicolon); |
| } |
| |
| @override |
| void handleQualified(Token period) { |
| debugEvent("Qualified", period); |
| state.pop(); // Suffix. |
| state.popPushNull("%Qualified%", period); // Qualifier. |
| } |
| |
| @override |
| void handleRecoverClassHeader() { |
| debugEvent("RecoverClassHeader", null); |
| state.checkEmpty(null); |
| } |
| |
| @override |
| void handleRecoverImport(Token semicolon) { |
| debugEvent("RecoverImport", semicolon); |
| unhandled("RecoverImport", semicolon); |
| } |
| |
| @override |
| void handleRecoverMixinHeader() { |
| debugEvent("RecoverMixinHeader", null); |
| state.checkEmpty(null); |
| } |
| |
| @override |
| void handleRecoverableError( |
| Message message, Token startToken, Token endToken) { |
| debugEvent("RecoverableError ${message.message}", startToken); |
| } |
| |
| @override |
| void endRedirectingFactoryBody(Token beginToken, Token endToken) { |
| debugEvent("RedirectingFactoryBody", beginToken); |
| state.pop(); // Constructor reference. |
| } |
| |
| @override |
| void endRethrowStatement(Token rethrowToken, Token endToken) { |
| debugEvent("RethrowStatement", rethrowToken); |
| } |
| |
| @override |
| void endReturnStatement( |
| bool hasExpression, Token beginToken, Token endToken) { |
| debugEvent("ReturnStatement", beginToken); |
| if (hasExpression) { |
| state.pop(); // Expression. |
| } |
| } |
| |
| @override |
| void handleScript(Token token) { |
| debugEvent("Script", token); |
| unhandled("Script", token); |
| } |
| |
| @override |
| void handleSend(Token beginToken, Token endToken) { |
| debugEvent("Send", beginToken); |
| Builder arguments = state.pop(); |
| if (identical(arguments, noArgumentsSentinel)) { |
| // Leave the receiver on the stack. |
| } else { |
| state.popPushNull("%send%", beginToken); |
| } |
| } |
| |
| @override |
| void endShow(Token showKeyword) { |
| debugEvent("Show", showKeyword); |
| } |
| |
| @override |
| void handleStringJuxtaposition(int literalCount) { |
| debugEvent("StringJuxtaposition", null); |
| state.discard(literalCount); |
| state.pushNull("%StringJuxtaposition%", null); |
| } |
| |
| @override |
| void handleStringPart(Token token) { |
| debugEvent("StringPart", token); |
| state.pushNull(token.lexeme, token); |
| } |
| |
| @override |
| void handleSuperExpression(Token token, IdentifierContext context) { |
| debugEvent("SuperExpression", token); |
| state.pushNull(token.lexeme, token); |
| } |
| |
| @override |
| void endSwitchBlock(int caseCount, Token beginToken, Token endToken) { |
| debugEvent("SwitchBlock", beginToken); |
| state.pop(); // Expression. |
| } |
| |
| @override |
| void endSwitchCase( |
| int labelCount, |
| int expressionCount, |
| Token defaultKeyword, |
| Token colonAfterDefault, |
| int statementCount, |
| Token firstToken, |
| Token endToken) { |
| debugEvent("SwitchCase", defaultKeyword); |
| } |
| |
| @override |
| void endSwitchStatement(Token switchKeyword, Token endToken) { |
| debugEvent("SwitchStatement", switchKeyword); |
| } |
| |
| @override |
| void handleSymbolVoid(Token token) { |
| debugEvent("SymbolVoid", token); |
| unhandled("SymbolVoid", token); |
| } |
| |
| @override |
| void endThenStatement(Token token) { |
| debugEvent("ThenStatement", token); |
| } |
| |
| @override |
| void handleThisExpression(Token token, IdentifierContext context) { |
| debugEvent("ThisExpression", token); |
| state.pushNull(token.lexeme, token); |
| } |
| |
| @override |
| void handleThrowExpression(Token throwToken, Token endToken) { |
| debugEvent("ThrowExpression", throwToken); |
| state.popPushNull(throwToken.lexeme, throwToken); |
| } |
| |
| @override |
| void endTopLevelDeclaration(Token token) { |
| debugEvent("TopLevelDeclaration", token); |
| state.checkEmpty(token); |
| } |
| |
| @override |
| void endTopLevelFields( |
| Token staticToken, |
| Token covariantToken, |
| Token lateToken, |
| Token varFinalOrConst, |
| int count, |
| Token beginToken, |
| Token endToken) { |
| debugEvent("TopLevelFields", staticToken); |
| state.discard(count); // Field names. |
| state.checkEmpty(endToken); |
| } |
| |
| @override |
| void beginTopLevelMethod(Token lastConsumed, Token externalToken) { |
| debugEvent("beginTopLevelMethod", lastConsumed.next); |
| state.checkEmpty(lastConsumed.next); |
| } |
| |
| @override |
| void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) { |
| debugEvent("endTopLevelMethod", beginToken); |
| state.pop(); // Method name. |
| state.checkEmpty(endToken); |
| } |
| |
| @override |
| void endTryStatement(int catchCount, Token tryKeyword, Token finallyKeyword) { |
| debugEvent("TryStatement", tryKeyword); |
| } |
| |
| @override |
| void handleType(Token beginToken, Token questionMark) { |
| debugEvent("Type", beginToken); |
| state.pop(); |
| } |
| |
| @override |
| void handleNoType(Token lastConsumed) { |
| debugEvent("NoType", lastConsumed); |
| } |
| |
| @override |
| void endTypeArguments(int count, Token beginToken, Token endToken) { |
| debugEvent("TypeArguments", beginToken); |
| } |
| |
| @override |
| void handleNoTypeArguments(Token token) { |
| debugEvent("NoTypeArguments", token); |
| } |
| |
| @override |
| void endTypeList(int count) { |
| debugEvent("TypeList", null); |
| } |
| |
| @override |
| void endTypeVariable( |
| Token token, int index, Token extendsOrSuper, Token variance) { |
| debugEvent("TypeVariable", token); |
| state.pop(); // Name. |
| } |
| |
| @override |
| void endTypeVariables(Token beginToken, Token endToken) { |
| debugEvent("TypeVariables", beginToken); |
| } |
| |
| @override |
| void handleNoTypeVariables(Token token) { |
| debugEvent("NoTypeVariables", token); |
| } |
| |
| @override |
| void handleTypeVariablesDefined(Token token, int count) { |
| debugEvent("TypeVariablesDefined", token); |
| } |
| |
| @override |
| void handleUnaryPostfixAssignmentExpression(Token token) { |
| debugEvent("UnaryPostfixAssignmentExpression", token); |
| Builder expr = state.popPushNull(token.lexeme, token); |
| if (expr is UnspecifiedDeclaration) { |
| state.registerWrite(expr, token); |
| } |
| } |
| |
| @override |
| void handleUnaryPrefixAssignmentExpression(Token token) { |
| debugEvent("UnaryPrefixAssignmentExpression", token); |
| Builder expr = state.popPushNull(token.lexeme, token); |
| if (expr is UnspecifiedDeclaration) { |
| state.registerWrite(expr, token); |
| } |
| } |
| |
| @override |
| void handleUnaryPrefixExpression(Token token) { |
| debugEvent("UnaryPrefixExpression", token); |
| state.popPushNull("%UnaryPrefixExpression%", token); |
| } |
| |
| @override |
| void handleNonNullAssertExpression(Token token) { |
| debugEvent("NonNullAssertExpression", token); |
| state.popPushNull("%NonNullAssertExpression%", token); |
| } |
| |
| @override |
| void handleUnescapeError( |
| Message message, Token location, int stringOffset, int length) { |
| debugEvent("UnescapeError", location); |
| unhandled("UnescapeError", location); |
| } |
| |
| @override |
| void handleValuedFormalParameter(Token equals, Token token) { |
| debugEvent("ValuedFormalParameter", equals); |
| } |
| |
| @override |
| void endVariableInitializer(Token assignmentOperator) { |
| debugEvent("VariableInitializer", assignmentOperator); |
| state.pop(); // Initializer. |
| } |
| |
| @override |
| void handleNoVariableInitializer(Token token) { |
| debugEvent("NoVariableInitializer", token); |
| } |
| |
| @override |
| void endVariablesDeclaration(int count, Token endToken) { |
| debugEvent("VariablesDeclaration", endToken); |
| state.discard(count); // Variable names. |
| } |
| |
| @override |
| void handleVoidKeyword(Token token) { |
| debugEvent("VoidKeyword", token); |
| } |
| |
| @override |
| void endWhileStatement(Token whileKeyword, Token endToken) { |
| debugEvent("WhileStatement", whileKeyword); |
| state.pop(); // Condition. |
| } |
| |
| @override |
| void endWhileStatementBody(Token token) { |
| debugEvent("WhileStatementBody", token); |
| } |
| |
| @override |
| void endYieldStatement(Token yieldToken, Token starToken, Token endToken) { |
| debugEvent("YieldStatement", yieldToken); |
| state.pop(); // Expression. |
| } |
| |
| void unhandled(String event, Token token) { |
| problems.unhandled( |
| event, "TypePromotionLookAheadListener", token?.charOffset ?? -1, uri); |
| } |
| } |