From 8af83b19d6326994ba5c3dc5362cd37462c1d526 Mon Sep 17 00:00:00 2001 From: Paul Berry Date: Thu, 28 Feb 2019 12:48:16 +0000 Subject: [PATCH] Sort declarations in ast_builder.dart. No functional change. Change-Id: If695a7437482aef1de7013aa404260f3602bdc93 Reviewed-on: https://dart-review.googlesource.com/c/94642 Auto-Submit: Paul Berry Commit-Queue: Dan Rubel Reviewed-by: Dan Rubel --- pkg/analyzer/lib/src/fasta/ast_builder.dart | 4921 ++++++++++--------- 1 file changed, 2462 insertions(+), 2459 deletions(-) diff --git a/pkg/analyzer/lib/src/fasta/ast_builder.dart b/pkg/analyzer/lib/src/fasta/ast_builder.dart index 950d78dac464..52709f40cea4 100644 --- a/pkg/analyzer/lib/src/fasta/ast_builder.dart +++ b/pkg/analyzer/lib/src/fasta/ast_builder.dart @@ -119,293 +119,194 @@ class AstBuilder extends StackListener { : this.errorReporter = new FastaErrorReporter(errorReporter), uri = uri ?? fileUri; - void beginLiteralString(Token literalString) { - assert(identical(literalString.kind, STRING_TOKEN)); - debugEvent("beginLiteralString"); - - push(literalString); + @override + void addProblem(Message message, int charOffset, int length, + {bool wasHandled: false, List context}) { + if (directives.isEmpty && + (message.code.analyzerCodes + ?.contains('NON_PART_OF_DIRECTIVE_IN_PART') ?? + false)) { + message = messageDirectiveAfterDeclaration; + } + errorReporter.reportMessage(message, charOffset, length); } - void handleNamedArgument(Token colon) { - assert(optional(':', colon)); - debugEvent("NamedArgument"); + void beginCascade(Token token) { + assert(optional('..', token)); + debugEvent("beginCascade"); Expression expression = pop(); - SimpleIdentifier name = pop(); - push(ast.namedExpression(ast.label(name, colon), expression)); + push(token); + if (expression is CascadeExpression) { + push(expression); + } else { + push(ast.cascadeExpression(expression, [])); + } + push(NullValue.CascadeReceiver); } @override - void handleNoConstructorReferenceContinuationAfterTypeArguments(Token token) { - debugEvent("NoConstructorReferenceContinuationAfterTypeArguments"); - - push(NullValue.ConstructorReferenceContinuationAfterTypeArguments); + void beginClassDeclaration(Token begin, Token abstractToken, Token name) { + assert(classDeclaration == null && mixinDeclaration == null); + push(new _Modifiers()..abstractKeyword = abstractToken); } @override - void endConstructorReference( - Token start, Token periodBeforeName, Token endToken) { - assert(optionalOrNull('.', periodBeforeName)); - debugEvent("ConstructorReference"); - - SimpleIdentifier constructorName = pop(); - TypeArgumentList typeArguments = pop(); - Identifier typeNameIdentifier = pop(); - push(ast.constructorName(ast.typeName(typeNameIdentifier, typeArguments), - periodBeforeName, constructorName)); + void beginCompilationUnit(Token token) { + push(token); } @override - void endConstExpression(Token constKeyword) { - assert(optional('const', constKeyword)); - debugEvent("ConstExpression"); - - _handleInstanceCreation(constKeyword); + void beginFactoryMethod( + Token lastConsumed, Token externalToken, Token constToken) { + push(new _Modifiers() + ..externalKeyword = externalToken + ..finalConstOrVarKeyword = constToken); } @override - void endConstLiteral(Token token) { - debugEvent("endConstLiteral"); - } - - void _handleInstanceCreation(Token token) { - MethodInvocation arguments = pop(); - ConstructorName constructorName; - TypeArgumentList typeArguments; - var object = pop(); - if (object is _ConstructorNameWithInvalidTypeArgs) { - constructorName = object.name; - typeArguments = object.invalidTypeArgs; - } else { - constructorName = object; - } - push(ast.instanceCreationExpression( - token, constructorName, arguments.argumentList, - typeArguments: typeArguments)); + void beginFormalParameter(Token token, MemberKind kind, Token covariantToken, + Token varFinalOrConst) { + push(new _Modifiers() + ..covariantKeyword = covariantToken + ..finalConstOrVarKeyword = varFinalOrConst); } @override - void endImplicitCreationExpression(Token token) { - debugEvent("ImplicitCreationExpression"); + void beginFormalParameterDefaultValueExpression() {} - _handleInstanceCreation(null); + void beginIfControlFlow(Token ifToken) { + push(ifToken); } - @override - void endNewExpression(Token newKeyword) { - assert(optional('new', newKeyword)); - debugEvent("NewExpression"); + void beginLiteralString(Token literalString) { + assert(identical(literalString.kind, STRING_TOKEN)); + debugEvent("beginLiteralString"); - _handleInstanceCreation(newKeyword); + push(literalString); } @override - void handleParenthesizedCondition(Token leftParenthesis) { - // TODO(danrubel): Implement rather than forwarding. - handleParenthesizedExpression(leftParenthesis); + void beginMetadataStar(Token token) { + debugEvent("beginMetadataStar"); } @override - void handleParenthesizedExpression(Token leftParenthesis) { - assert(optional('(', leftParenthesis)); - debugEvent("ParenthesizedExpression"); - - Expression expression = pop(); - push(ast.parenthesizedExpression( - leftParenthesis, expression, leftParenthesis?.endGroup)); + void beginMethod(Token externalToken, Token staticToken, Token covariantToken, + Token varFinalOrConst, Token getOrSet, Token name) { + _Modifiers modifiers = new _Modifiers(); + if (externalToken != null) { + assert(externalToken.isModifier); + modifiers.externalKeyword = externalToken; + } + if (staticToken != null) { + assert(staticToken.isModifier); + String className = classDeclaration != null + ? classDeclaration.name.name + : mixinDeclaration.name.name; + if (name?.lexeme == className && getOrSet == null) { + // This error is also reported in OutlineBuilder.beginMethod + handleRecoverableError( + messageStaticConstructor, staticToken, staticToken); + } else { + modifiers.staticKeyword = staticToken; + } + } + if (covariantToken != null) { + assert(covariantToken.isModifier); + modifiers.covariantKeyword = covariantToken; + } + if (varFinalOrConst != null) { + assert(varFinalOrConst.isModifier); + modifiers.finalConstOrVarKeyword = varFinalOrConst; + } + push(modifiers); } @override - void handleStringPart(Token literalString) { - assert(identical(literalString.kind, STRING_TOKEN)); - debugEvent("StringPart"); - - push(literalString); + void beginMixinDeclaration(Token mixinKeyword, Token name) { + assert(classDeclaration == null && mixinDeclaration == null); } @override - void handleInterpolationExpression(Token leftBracket, Token rightBracket) { - Expression expression = pop(); - push(ast.interpolationExpression(leftBracket, expression, rightBracket)); + void beginNamedMixinApplication( + Token begin, Token abstractToken, Token name) { + push(new _Modifiers()..abstractKeyword = abstractToken); + } + + void beginTopLevelMethod(Token lastConsumed, Token externalToken) { + push(new _Modifiers()..externalKeyword = externalToken); } @override - void endLiteralString(int interpolationCount, Token endToken) { - debugEvent("endLiteralString"); + void beginTypeVariable(Token token) { + debugEvent("beginTypeVariable"); + SimpleIdentifier name = pop(); + List metadata = pop(); - if (interpolationCount == 0) { - Token token = pop(); - String value = unescapeString(token.lexeme, token, this); - push(ast.simpleStringLiteral(token, value)); - } else { - List parts = popTypedList(1 + interpolationCount * 2); - Token first = parts.first; - Token last = parts.last; - Quote quote = analyzeQuote(first.lexeme); - List elements = []; - elements.add(ast.interpolationString( - first, unescapeFirstStringPart(first.lexeme, quote, first, this))); - for (int i = 1; i < parts.length - 1; i++) { - var part = parts[i]; - if (part is Token) { - elements.add(ast.interpolationString( - part, unescape(part.lexeme, quote, part, this))); - } else if (part is InterpolationExpression) { - elements.add(part); - } else { - unhandled("${part.runtimeType}", "string interpolation", - first.charOffset, uri); - } - } - elements.add(ast.interpolationString( - last, unescapeLastStringPart(last.lexeme, quote, last, this))); - push(ast.stringInterpolation(elements)); - } + Comment comment = _findComment(metadata, name.beginToken); + var typeParameter = ast.typeParameter(comment, metadata, name, null, null); + localDeclarations[name.offset] = typeParameter; + push(typeParameter); } @override - void handleNativeClause(Token nativeToken, bool hasName) { - debugEvent("NativeClause"); - - if (hasName) { - nativeName = pop(); // StringLiteral + void beginVariablesDeclaration(Token token, Token varFinalOrConst) { + debugEvent("beginVariablesDeclaration"); + if (varFinalOrConst != null) { + push(new _Modifiers()..finalConstOrVarKeyword = varFinalOrConst); } else { - nativeName = null; + push(NullValue.Modifiers); } } - void handleScript(Token token) { - assert(identical(token.type, TokenType.SCRIPT_TAG)); - debugEvent("Script"); - - scriptTag = ast.scriptTag(token); - } - - void beginIfControlFlow(Token ifToken) { - push(ifToken); - } - - @override - void handleElseControlFlow(Token elseToken) { - push(elseToken); + void checkFieldFormalParameters(FormalParameterList parameters) { + if (parameters?.parameters != null) { + parameters.parameters.forEach((FormalParameter param) { + if (param is FieldFormalParameter) { + // This error is reported in the BodyBuilder.endFormalParameter. + handleRecoverableError(messageFieldInitializerOutsideConstructor, + param.thisKeyword, param.thisKeyword); + } + }); + } } @override - void endIfControlFlow(Token token) { - CollectionElement thenElement = pop(); - ParenthesizedExpression condition = pop(); - Token ifToken = pop(); - pushIfControlFlowInfo(ifToken, condition, thenElement, null, null); + void debugEvent(String name) { + // printEvent('AstBuilder: $name'); } @override - void endIfElseControlFlow(Token token) { - CollectionElement elseElement = pop(); - Token elseToken = pop(); - CollectionElement thenElement = pop(); - ParenthesizedExpression condition = pop(); - Token ifToken = pop(); - pushIfControlFlowInfo( - ifToken, condition, thenElement, elseToken, elseElement); + void discardTypeReplacedWithCommentTypeAssign() { + pop(); } - void pushIfControlFlowInfo( - Token ifToken, - ParenthesizedExpression condition, - CollectionElement thenElement, - Token elseToken, - CollectionElement elseElement) { - if (thenElement == _invalidCollectionElement || - elseElement == _invalidCollectionElement) { - push(_invalidCollectionElement); - } else if (enableControlFlowCollections) { - push(ast.ifElement( - ifKeyword: ifToken, - leftParenthesis: condition.leftParenthesis, - condition: condition.expression, - rightParenthesis: condition.rightParenthesis, - thenElement: thenElement, - elseKeyword: elseToken, - elseElement: elseElement, - )); - } else { - handleRecoverableError( - templateExperimentNotEnabled - .withArguments(EnableString.control_flow_collections), - ifToken, - ifToken); - push(_invalidCollectionElement); - } - } - - @override - void handleSpreadExpression(Token spreadToken) { - var expression = pop(); - if (enableSpreadCollections) { - push(ast.spreadElement( - spreadOperator: spreadToken, expression: expression)); - } else { - handleRecoverableError( - templateExperimentNotEnabled - .withArguments(EnableString.spread_collections), - spreadToken, - spreadToken); - push(_invalidCollectionElement); - } - } - - void handleStringJuxtaposition(int literalCount) { - debugEvent("StringJuxtaposition"); - - push(ast.adjacentStrings(popTypedList(literalCount))); - } - - void endArguments(int count, Token leftParenthesis, Token rightParenthesis) { - assert(optional('(', leftParenthesis)); - assert(optional(')', rightParenthesis)); - debugEvent("Arguments"); - - List expressions = popTypedList(count); - ArgumentList arguments = - ast.argumentList(leftParenthesis, expressions, rightParenthesis); - push(ast.methodInvocation(null, null, null, null, arguments)); - } - - void handleIdentifier(Token token, IdentifierContext context) { - assert(token.isKeywordOrIdentifier); - debugEvent("handleIdentifier"); - - if (context.inSymbol) { - push(token); - return; - } - - SimpleIdentifier identifier = - ast.simpleIdentifier(token, isDeclaration: context.inDeclaration); - if (context.inLibraryOrPartOfDeclaration) { - if (!context.isContinuation) { - push([identifier]); + void doDotExpression(Token dot) { + Expression identifierOrInvoke = pop(); + Expression receiver = pop(); + if (identifierOrInvoke is SimpleIdentifier) { + if (receiver is SimpleIdentifier && identical('.', dot.stringValue)) { + push(ast.prefixedIdentifier(receiver, dot, identifierOrInvoke)); } else { - push(identifier); + push(ast.propertyAccess(receiver, dot, identifierOrInvoke)); } - } else if (context == IdentifierContext.enumValueDeclaration) { - List metadata = pop(); - Comment comment = _findComment(null, token); - push(ast.enumConstantDeclaration(comment, metadata, identifier)); - } else { - push(identifier); - } - } - - void handleSend(Token beginToken, Token endToken) { - debugEvent("Send"); - - MethodInvocation arguments = pop(); - TypeArgumentList typeArguments = pop(); - if (arguments != null) { - doInvocation(typeArguments, arguments); + } else if (identifierOrInvoke is MethodInvocation) { + assert(identifierOrInvoke.target == null); + identifierOrInvoke + ..target = receiver + ..operator = dot; + push(identifierOrInvoke); } else { - doPropertyGet(); + // This same error is reported in BodyBuilder.doDotOrCascadeExpression + Token token = identifierOrInvoke.beginToken; + // TODO(danrubel): Consider specializing the error message based + // upon the type of expression. e.g. "x.this" -> templateThisAsIdentifier + handleRecoverableError( + templateExpectedIdentifier.withArguments(token), token, token); + SimpleIdentifier identifier = + ast.simpleIdentifier(token, isDeclaration: false); + push(ast.propertyAccess(receiver, dot, identifier)); } } @@ -426,66 +327,87 @@ class AstBuilder extends StackListener { void doPropertyGet() {} - void handleExpressionStatement(Token semicolon) { - assert(optional(';', semicolon)); - debugEvent("ExpressionStatement"); - Expression expression = pop(); - reportErrorIfSuper(expression); - if (expression is SimpleIdentifier && - expression.token?.keyword?.isBuiltInOrPseudo == false) { - // This error is also reported by the body builder. - handleRecoverableError( - messageExpectedStatement, expression.beginToken, expression.endToken); - } - if (expression is AssignmentExpression) { - if (!expression.leftHandSide.isAssignable) { - // This error is also reported by the body builder. - handleRecoverableError( - messageIllegalAssignmentToNonAssignable, - expression.leftHandSide.beginToken, - expression.leftHandSide.endToken); - } - } - push(ast.expressionStatement(expression, semicolon)); + void endArguments(int count, Token leftParenthesis, Token rightParenthesis) { + assert(optional('(', leftParenthesis)); + assert(optional(')', rightParenthesis)); + debugEvent("Arguments"); + + List expressions = popTypedList(count); + ArgumentList arguments = + ast.argumentList(leftParenthesis, expressions, rightParenthesis); + push(ast.methodInvocation(null, null, null, null, arguments)); } - void reportErrorIfSuper(Expression expression) { - if (expression is SuperExpression) { - // This error is also reported by the body builder. - handleRecoverableError(messageMissingAssignableSelector, - expression.beginToken, expression.endToken); + @override + void endAssert(Token assertKeyword, Assert kind, Token leftParenthesis, + Token comma, Token semicolon) { + assert(optional('assert', assertKeyword)); + assert(optional('(', leftParenthesis)); + assert(optionalOrNull(',', comma)); + assert(kind != Assert.Statement || optionalOrNull(';', semicolon)); + debugEvent("Assert"); + + Expression message = popIfNotNull(comma); + Expression condition = pop(); + switch (kind) { + case Assert.Expression: + // The parser has already reported an error indicating that assert + // cannot be used in an expression. Insert a placeholder. + List arguments = [condition]; + if (message != null) { + arguments.add(message); + } + push(ast.functionExpressionInvocation( + ast.simpleIdentifier(assertKeyword), + null, + ast.argumentList( + leftParenthesis, arguments, leftParenthesis?.endGroup))); + break; + case Assert.Initializer: + push(ast.assertInitializer(assertKeyword, leftParenthesis, condition, + comma, message, leftParenthesis?.endGroup)); + break; + case Assert.Statement: + push(ast.assertStatement(assertKeyword, leftParenthesis, condition, + comma, message, leftParenthesis?.endGroup, semicolon)); + break; } } - @override - void handleNativeFunctionBody(Token nativeToken, Token semicolon) { - assert(optional('native', nativeToken)); - assert(optional(';', semicolon)); - debugEvent("NativeFunctionBody"); + void endAwaitExpression(Token awaitKeyword, Token endToken) { + assert(optional('await', awaitKeyword)); + debugEvent("AwaitExpression"); - // TODO(danrubel) Change the parser to not produce these modifiers. - pop(); // star - pop(); // async - push(ast.nativeFunctionBody(nativeToken, nativeName, semicolon)); + push(ast.awaitExpression(awaitKeyword, pop())); } @override - void handleEmptyFunctionBody(Token semicolon) { - assert(optional(';', semicolon)); - debugEvent("EmptyFunctionBody"); + void endBinaryExpression(Token operatorToken) { + assert(operatorToken.isOperator || + optional('.', operatorToken) || + optional('?.', operatorToken) || + optional('..', operatorToken)); + debugEvent("BinaryExpression"); - // TODO(scheglov) Change the parser to not produce these modifiers. - pop(); // star - pop(); // async - push(ast.emptyFunctionBody(semicolon)); + if (identical(".", operatorToken.stringValue) || + identical("?.", operatorToken.stringValue) || + identical("..", operatorToken.stringValue)) { + doDotExpression(operatorToken); + } else { + Expression right = pop(); + Expression left = pop(); + reportErrorIfSuper(right); + push(ast.binaryExpression(left, operatorToken, right)); + } } - @override - void handleEmptyStatement(Token semicolon) { - assert(optional(';', semicolon)); - debugEvent("EmptyStatement"); + void endBlock(int count, Token leftBracket, Token rightBracket) { + assert(optional('{', leftBracket)); + assert(optional('}', rightBracket)); + debugEvent("Block"); - push(ast.emptyStatement(semicolon)); + List statements = popTypedList(count) ?? []; + push(ast.block(leftBracket, statements, rightBracket)); } void endBlockFunctionBody(int count, Token leftBracket, Token rightBracket) { @@ -506,38 +428,6 @@ class AstBuilder extends StackListener { } } - void finishFunction( - List annotations, formals, AsyncMarker asyncModifier, FunctionBody body) { - debugEvent("finishFunction"); - - Statement bodyStatement; - if (body is EmptyFunctionBody) { - bodyStatement = ast.emptyStatement(body.semicolon); - } else if (body is NativeFunctionBody) { - // TODO(danrubel): what do we need to do with NativeFunctionBody? - } else if (body is ExpressionFunctionBody) { - bodyStatement = ast.returnStatement(null, body.expression, null); - } else { - bodyStatement = (body as BlockFunctionBody).block; - } - // TODO(paulberry): what do we need to do with bodyStatement at this point? - bodyStatement; // Suppress "unused local variable" hint - } - - void beginCascade(Token token) { - assert(optional('..', token)); - debugEvent("beginCascade"); - - Expression expression = pop(); - push(token); - if (expression is CascadeExpression) { - push(expression); - } else { - push(ast.cascadeExpression(expression, [])); - } - push(NullValue.CascadeReceiver); - } - void endCascade() { debugEvent("Cascade"); @@ -548,420 +438,460 @@ class AstBuilder extends StackListener { push(receiver); } - void handleOperator(Token operatorToken) { - assert(operatorToken.isUserDefinableOperator); - debugEvent("Operator"); - - push(operatorToken); + @override + void endClassDeclaration(Token beginToken, Token endToken) { + debugEvent("ClassDeclaration"); + classDeclaration = null; } - void handleSymbolVoid(Token voidKeyword) { - assert(optional('void', voidKeyword)); - debugEvent("SymbolVoid"); + @override + void endClassOrMixinBody( + int memberCount, Token leftBracket, Token rightBracket) { + assert(optional('{', leftBracket)); + assert(optional('}', rightBracket)); + debugEvent("ClassOrMixinBody"); - push(voidKeyword); + ClassOrMixinDeclarationImpl declaration = + classDeclaration ?? mixinDeclaration; + declaration.leftBracket = leftBracket; + declaration.rightBracket = rightBracket; } @override - void endBinaryExpression(Token operatorToken) { - assert(operatorToken.isOperator || - optional('.', operatorToken) || - optional('?.', operatorToken) || - optional('..', operatorToken)); - debugEvent("BinaryExpression"); + void endCombinators(int count) { + debugEvent("Combinators"); + push(popTypedList(count) ?? NullValue.Combinators); + } - if (identical(".", operatorToken.stringValue) || - identical("?.", operatorToken.stringValue) || - identical("..", operatorToken.stringValue)) { - doDotExpression(operatorToken); - } else { - Expression right = pop(); - Expression left = pop(); - reportErrorIfSuper(right); - push(ast.binaryExpression(left, operatorToken, right)); - } + @override + void endCompilationUnit(int count, Token endToken) { + debugEvent("CompilationUnit"); + + Token beginToken = pop(); + checkEmpty(endToken.charOffset); + + push(ast.compilationUnit( + beginToken, scriptTag, directives, declarations, endToken)); } - void doDotExpression(Token dot) { - Expression identifierOrInvoke = pop(); - Expression receiver = pop(); - if (identifierOrInvoke is SimpleIdentifier) { - if (receiver is SimpleIdentifier && identical('.', dot.stringValue)) { - push(ast.prefixedIdentifier(receiver, dot, identifierOrInvoke)); - } else { - push(ast.propertyAccess(receiver, dot, identifierOrInvoke)); + void endConditionalExpression(Token question, Token colon) { + assert(optional('?', question)); + assert(optional(':', colon)); + debugEvent("ConditionalExpression"); + + Expression elseExpression = pop(); + Expression thenExpression = pop(); + Expression condition = pop(); + reportErrorIfSuper(elseExpression); + reportErrorIfSuper(thenExpression); + push(ast.conditionalExpression( + condition, question, thenExpression, colon, elseExpression)); + } + + void endConditionalUri(Token ifKeyword, Token leftParen, Token equalSign) { + assert(optional('if', ifKeyword)); + assert(optionalOrNull('(', leftParen)); + assert(optionalOrNull('==', equalSign)); + debugEvent("ConditionalUri"); + + StringLiteral libraryUri = pop(); + StringLiteral value = popIfNotNull(equalSign); + if (value is StringInterpolation) { + for (var child in value.childEntities) { + if (child is InterpolationExpression) { + // This error is reported in OutlineBuilder.endLiteralString + handleRecoverableError( + messageInterpolationInUri, child.beginToken, child.endToken); + break; + } } - } else if (identifierOrInvoke is MethodInvocation) { - assert(identifierOrInvoke.target == null); - identifierOrInvoke - ..target = receiver - ..operator = dot; - push(identifierOrInvoke); - } else { - // This same error is reported in BodyBuilder.doDotOrCascadeExpression - Token token = identifierOrInvoke.beginToken; - // TODO(danrubel): Consider specializing the error message based - // upon the type of expression. e.g. "x.this" -> templateThisAsIdentifier - handleRecoverableError( - templateExpectedIdentifier.withArguments(token), token, token); - SimpleIdentifier identifier = - ast.simpleIdentifier(token, isDeclaration: false); - push(ast.propertyAccess(receiver, dot, identifier)); } + DottedName name = pop(); + push(ast.configuration(ifKeyword, leftParen, name, equalSign, value, + leftParen?.endGroup, libraryUri)); } - void handleLiteralInt(Token token) { - assert(identical(token.kind, INT_TOKEN) || - identical(token.kind, HEXADECIMAL_TOKEN)); - debugEvent("LiteralInt"); + @override + void endConditionalUris(int count) { + debugEvent("ConditionalUris"); - push(ast.integerLiteral(token, int.tryParse(token.lexeme))); + push(popTypedList(count) ?? NullValue.ConditionalUris); } - void handleExpressionFunctionBody(Token arrowToken, Token semicolon) { - assert(optional('=>', arrowToken) || optional('=', arrowToken)); - assert(optionalOrNull(';', semicolon)); - debugEvent("ExpressionFunctionBody"); + @override + void endConstExpression(Token constKeyword) { + assert(optional('const', constKeyword)); + debugEvent("ConstExpression"); - Expression expression = pop(); - pop(); // star (*) - Token asyncKeyword = pop(); - if (parseFunctionBodies) { - push(ast.expressionFunctionBody( - asyncKeyword, arrowToken, expression, semicolon)); - } else { - push(ast.emptyFunctionBody(semicolon)); - } + _handleInstanceCreation(constKeyword); } - void endReturnStatement( - bool hasExpression, Token returnKeyword, Token semicolon) { - assert(optional('return', returnKeyword)); - assert(optional(';', semicolon)); - debugEvent("ReturnStatement"); + @override + void endConstLiteral(Token token) { + debugEvent("endConstLiteral"); + } - Expression expression = hasExpression ? pop() : null; - push(ast.returnStatement(returnKeyword, expression, semicolon)); + @override + void endConstructorReference( + Token start, Token periodBeforeName, Token endToken) { + assert(optionalOrNull('.', periodBeforeName)); + debugEvent("ConstructorReference"); + + SimpleIdentifier constructorName = pop(); + TypeArgumentList typeArguments = pop(); + Identifier typeNameIdentifier = pop(); + push(ast.constructorName(ast.typeName(typeNameIdentifier, typeArguments), + periodBeforeName, constructorName)); } - void endIfStatement(Token ifToken, Token elseToken) { - assert(optional('if', ifToken)); - assert(optionalOrNull('else', elseToken)); + @override + void endDoWhileStatement( + Token doKeyword, Token whileKeyword, Token semicolon) { + assert(optional('do', doKeyword)); + assert(optional('while', whileKeyword)); + assert(optional(';', semicolon)); + debugEvent("DoWhileStatement"); - Statement elsePart = popIfNotNull(elseToken); - Statement thenPart = pop(); ParenthesizedExpression condition = pop(); - push(ast.ifStatement( - ifToken, + Statement body = pop(); + push(ast.doStatement( + doKeyword, + body, + whileKeyword, condition.leftParenthesis, condition.expression, condition.rightParenthesis, - thenPart, - elseToken, - elsePart)); + semicolon)); } - void handleNoInitializers() { - debugEvent("NoInitializers"); + @override + void endDoWhileStatementBody(Token token) { + debugEvent("endDoWhileStatementBody"); + } - if (!isFullAst) return; - push(NullValue.ConstructorInitializerSeparator); - push(NullValue.ConstructorInitializers); + @override + void endElseStatement(Token token) { + debugEvent("endElseStatement"); } - void endInitializers(int count, Token colon, Token endToken) { - assert(optional(':', colon)); - debugEvent("Initializers"); + @override + void endEnum(Token enumKeyword, Token leftBrace, int count) { + assert(optional('enum', enumKeyword)); + assert(optional('{', leftBrace)); + debugEvent("Enum"); - List initializerObjects = popTypedList(count) ?? const []; - if (!isFullAst) return; + List constants = popTypedList(count); + SimpleIdentifier name = pop(); + List metadata = pop(); + Comment comment = _findComment(metadata, enumKeyword); + declarations.add(ast.enumDeclaration(comment, metadata, enumKeyword, name, + leftBrace, constants, leftBrace?.endGroup)); + } - push(colon); + void endExport(Token exportKeyword, Token semicolon) { + assert(optional('export', exportKeyword)); + assert(optional(';', semicolon)); + debugEvent("Export"); - var initializers = []; - for (Object initializerObject in initializerObjects) { - if (initializerObject is FunctionExpressionInvocation) { - Expression function = initializerObject.function; - if (function is SuperExpression) { - initializers.add(ast.superConstructorInvocation(function.superKeyword, - null, null, initializerObject.argumentList)); - } else { - initializers.add(ast.redirectingConstructorInvocation( - (function as ThisExpression).thisKeyword, - null, - null, - initializerObject.argumentList)); - } - } else if (initializerObject is MethodInvocation) { - Expression target = initializerObject.target; - if (target is SuperExpression) { - initializers.add(ast.superConstructorInvocation( - target.superKeyword, - initializerObject.operator, - initializerObject.methodName, - initializerObject.argumentList)); - } else if (target is ThisExpression) { - initializers.add(ast.redirectingConstructorInvocation( - target.thisKeyword, - initializerObject.operator, - initializerObject.methodName, - initializerObject.argumentList)); - } else { - // Invalid initializer - // TODO(danrubel): Capture this in the AST. - } - } else if (initializerObject is AssignmentExpression) { - Token thisKeyword; - Token period; - SimpleIdentifier fieldName; - Expression left = initializerObject.leftHandSide; - if (left is PropertyAccess) { - Expression target = left.target; - if (target is ThisExpression) { - thisKeyword = target.thisKeyword; - period = left.operator; - } else { - assert(target is SuperExpression); - // Recovery: - // Parser has reported FieldInitializedOutsideDeclaringClass. - } - fieldName = left.propertyName; - } else if (left is SimpleIdentifier) { - fieldName = left; - } else { - // Recovery: - // Parser has reported invalid assignment. - SuperExpression superExpression = left; - fieldName = ast.simpleIdentifier(superExpression.superKeyword); - } - initializers.add(ast.constructorFieldInitializer( - thisKeyword, - period, - fieldName, - initializerObject.operator, - initializerObject.rightHandSide)); - } else if (initializerObject is AssertInitializer) { - initializers.add(initializerObject); - } + List combinators = pop(); + List configurations = pop(); + StringLiteral uri = pop(); + List metadata = pop(); + Comment comment = _findComment(metadata, exportKeyword); + directives.add(ast.exportDirective(comment, metadata, exportKeyword, uri, + configurations, combinators, semicolon)); + } + + @override + void endFactoryMethod( + Token beginToken, Token factoryKeyword, Token endToken) { + assert(optional('factory', factoryKeyword)); + assert(optional(';', endToken) || optional('}', endToken)); + debugEvent("FactoryMethod"); + + FunctionBody body; + Token separator; + ConstructorName redirectedConstructor; + Object bodyObject = pop(); + if (bodyObject is FunctionBody) { + body = bodyObject; + } else if (bodyObject is _RedirectingFactoryBody) { + separator = bodyObject.equalToken; + redirectedConstructor = bodyObject.constructorName; + body = ast.emptyFunctionBody(endToken); + } else { + unhandled("${bodyObject.runtimeType}", "bodyObject", + beginToken.charOffset, uri); } - push(initializers); + FormalParameterList parameters = pop(); + TypeParameterList typeParameters = pop(); + Object constructorName = pop(); + _Modifiers modifiers = pop(); + List metadata = pop(); + Comment comment = _findComment(metadata, beginToken); + + assert(parameters != null); + + if (typeParameters != null) { + // TODO(danrubel): Update OutlineBuilder to report this error message. + handleRecoverableError(messageConstructorWithTypeParameters, + typeParameters.beginToken, typeParameters.endToken); + } + + // Decompose the preliminary ConstructorName into the type name and + // the actual constructor name. + SimpleIdentifier returnType; + Token period; + SimpleIdentifier name; + Identifier typeName = constructorName; + if (typeName is SimpleIdentifier) { + returnType = typeName; + } else if (typeName is PrefixedIdentifier) { + returnType = typeName.prefix; + period = typeName.period; + name = + ast.simpleIdentifier(typeName.identifier.token, isDeclaration: true); + } + + (classDeclaration ?? mixinDeclaration).members.add( + ast.constructorDeclaration( + comment, + metadata, + modifiers?.externalKeyword, + modifiers?.finalConstOrVarKeyword, + factoryKeyword, + ast.simpleIdentifier(returnType.token), + period, + name, + parameters, + separator, + null, + redirectedConstructor, + body)); } - void endVariableInitializer(Token assignmentOperator) { - assert(optionalOrNull('=', assignmentOperator)); - debugEvent("VariableInitializer"); + void endFieldInitializer(Token assignment, Token token) { + assert(optional('=', assignment)); + debugEvent("FieldInitializer"); Expression initializer = pop(); - SimpleIdentifier identifier = pop(); - // TODO(ahe): Don't push initializers, instead install them. - push(_makeVariableDeclaration(identifier, assignmentOperator, initializer)); + SimpleIdentifier name = pop(); + push(_makeVariableDeclaration(name, assignment, initializer)); } - VariableDeclaration _makeVariableDeclaration( - SimpleIdentifier name, Token equals, Expression initializer) { - var variableDeclaration = - ast.variableDeclaration(name, equals, initializer); - localDeclarations[name.offset] = variableDeclaration; - return variableDeclaration; + @override + void endFields(Token staticToken, Token covariantToken, Token varFinalOrConst, + int count, Token beginToken, Token semicolon) { + assert(optional(';', semicolon)); + debugEvent("Fields"); + + List variables = popTypedList(count); + TypeAnnotation type = pop(); + _Modifiers modifiers = new _Modifiers() + ..staticKeyword = staticToken + ..covariantKeyword = covariantToken + ..finalConstOrVarKeyword = varFinalOrConst; + var variableList = ast.variableDeclarationList( + null, null, modifiers?.finalConstOrVarKeyword, type, variables); + Token covariantKeyword = modifiers?.covariantKeyword; + List metadata = pop(); + Comment comment = _findComment(metadata, beginToken); + (classDeclaration ?? mixinDeclaration).members.add(ast.fieldDeclaration2( + comment: comment, + metadata: metadata, + covariantKeyword: covariantKeyword, + staticKeyword: modifiers?.staticKeyword, + fieldList: variableList, + semicolon: semicolon)); } @override - void endWhileStatement(Token whileKeyword, Token endToken) { - assert(optional('while', whileKeyword)); - debugEvent("WhileStatement"); + void endForControlFlow(Token token) { + debugEvent("endForControlFlow"); + var entry = pop(); + ForParts forLoopParts = pop(); + Token leftParen = pop(); + Token forToken = pop(); - Statement body = pop(); - ParenthesizedExpression condition = pop(); - push(ast.whileStatement(whileKeyword, condition.leftParenthesis, - condition.expression, condition.rightParenthesis, body)); + pushForControlFlowInfo(null, forToken, leftParen, forLoopParts, entry); } @override - void endYieldStatement(Token yieldToken, Token starToken, Token semicolon) { - assert(optional('yield', yieldToken)); - assert(optionalOrNull('*', starToken)); - assert(optional(';', semicolon)); - debugEvent("YieldStatement"); + void endForIn(Token endToken) { + debugEvent("ForInExpression"); - Expression expression = pop(); - push(ast.yieldStatement(yieldToken, starToken, expression, semicolon)); + Statement body = pop(); + ForEachParts forLoopParts = pop(); + Token leftParenthesis = pop(); + Token forToken = pop(); + Token awaitToken = pop(NullValue.AwaitToken); + + if (enableControlFlowCollections || enableSpreadCollections) { + push(ast.forStatement2( + awaitKeyword: awaitToken, + forKeyword: forToken, + leftParenthesis: leftParenthesis, + forLoopParts: forLoopParts, + rightParenthesis: leftParenthesis.endGroup, + body: body, + )); + } else if (forLoopParts is ForEachPartsWithDeclaration) { + push(ast.forEachStatementWithDeclaration( + awaitToken, + forToken, + leftParenthesis, + forLoopParts.loopVariable, + forLoopParts.inKeyword, + forLoopParts.iterable, + leftParenthesis?.endGroup, + body)); + } else { + push(ast.forEachStatementWithReference( + awaitToken, + forToken, + leftParenthesis, + (forLoopParts as ForEachPartsWithIdentifier).identifier, + forLoopParts.inKeyword, + forLoopParts.iterable, + leftParenthesis?.endGroup, + body)); + } } @override - void handleNoVariableInitializer(Token token) { - debugEvent("NoVariableInitializer"); + void endForInBody(Token token) { + debugEvent("endForInBody"); } - void endInitializedIdentifier(Token nameToken) { - debugEvent("InitializedIdentifier"); + @override + void endForInControlFlow(Token token) { + debugEvent("endForInControlFlow"); - AstNode node = pop(); - VariableDeclaration variable; - // TODO(paulberry): This seems kludgy. It would be preferable if we - // could respond to a "handleNoVariableInitializer" event by converting a - // SimpleIdentifier into a VariableDeclaration, and then when this code was - // reached, node would always be a VariableDeclaration. - if (node is VariableDeclaration) { - variable = node; - } else if (node is SimpleIdentifier) { - variable = _makeVariableDeclaration(node, null, null); - } else { - unhandled("${node.runtimeType}", "identifier", nameToken.charOffset, uri); - } - push(variable); + var entry = pop(); + ForEachParts forLoopParts = pop(); + Token leftParenthesis = pop(); + Token forToken = pop(); + Token awaitToken = pop(NullValue.AwaitToken); + + pushForControlFlowInfo( + awaitToken, forToken, leftParenthesis, forLoopParts, entry); } @override - void beginVariablesDeclaration(Token token, Token varFinalOrConst) { - debugEvent("beginVariablesDeclaration"); - if (varFinalOrConst != null) { - push(new _Modifiers()..finalConstOrVarKeyword = varFinalOrConst); - } else { - push(NullValue.Modifiers); - } + void endForInExpression(Token token) { + debugEvent("ForInExpression"); } @override - void endVariablesDeclaration(int count, Token semicolon) { - assert(optionalOrNull(';', semicolon)); - debugEvent("VariablesDeclaration"); + void endFormalParameter(Token thisKeyword, Token periodAfterThis, + Token nameToken, FormalParameterKind kind, MemberKind memberKind) { + assert(optionalOrNull('this', thisKeyword)); + assert(thisKeyword == null + ? periodAfterThis == null + : optional('.', periodAfterThis)); + debugEvent("FormalParameter"); - List variables = popTypedList(count); - _Modifiers modifiers = pop(NullValue.Modifiers); - TypeAnnotation type = pop(); + _ParameterDefaultValue defaultValue = pop(); + SimpleIdentifier name = pop(); + AstNode typeOrFunctionTypedParameter = pop(); + _Modifiers modifiers = pop(); Token keyword = modifiers?.finalConstOrVarKeyword; + Token covariantKeyword = modifiers?.covariantKeyword; List metadata = pop(); Comment comment = _findComment(metadata, - variables[0].beginToken ?? type?.beginToken ?? modifiers.beginToken); - push(ast.variableDeclarationStatement( - ast.variableDeclarationList( - comment, metadata, keyword, type, variables), - semicolon)); - } - - void handleAssignmentExpression(Token token) { - assert(token.type.isAssignmentOperator); - debugEvent("AssignmentExpression"); - - Expression rhs = pop(); - Expression lhs = pop(); - if (!lhs.isAssignable) { - // TODO(danrubel): Update the BodyBuilder to report this error. - handleRecoverableError( - messageMissingAssignableSelector, lhs.beginToken, lhs.endToken); - } - push(ast.assignmentExpression(lhs, token, rhs)); - } - - void endBlock(int count, Token leftBracket, Token rightBracket) { - assert(optional('{', leftBracket)); - assert(optional('}', rightBracket)); - debugEvent("Block"); - - List statements = popTypedList(count) ?? []; - push(ast.block(leftBracket, statements, rightBracket)); - } - - void handleInvalidTopLevelBlock(Token token) { - // TODO(danrubel): Consider improved recovery by adding this block - // as part of a synthetic top level function. - pop(); // block - } - - @override - void handleForInitializerEmptyStatement(Token token) { - debugEvent("ForInitializerEmptyStatement"); - push(NullValue.Expression); - } - - @override - void handleForInitializerExpressionStatement(Token token) { - debugEvent("ForInitializerExpressionStatement"); - } - - @override - void handleForInitializerLocalVariableDeclaration(Token token) { - debugEvent("ForInitializerLocalVariableDeclaration"); - } - - @override - void handleForLoopParts(Token forKeyword, Token leftParen, - Token leftSeparator, int updateExpressionCount) { - assert(optional('for', forKeyword)); - assert(optional('(', leftParen)); - assert(optional(';', leftSeparator)); - assert(updateExpressionCount >= 0); - - List updates = popTypedList(updateExpressionCount); - Statement conditionStatement = pop(); - Object initializerPart = pop(); + thisKeyword ?? typeOrFunctionTypedParameter?.beginToken ?? nameToken); - Expression condition; - Token rightSeparator; - if (conditionStatement is ExpressionStatement) { - condition = conditionStatement.expression; - rightSeparator = conditionStatement.semicolon; + NormalFormalParameter node; + if (typeOrFunctionTypedParameter is FunctionTypedFormalParameter) { + // This is a temporary AST node that was constructed in + // [endFunctionTypedFormalParameter]. We now deconstruct it and create + // the final AST node. + if (thisKeyword == null) { + node = ast.functionTypedFormalParameter2( + identifier: name, + comment: comment, + metadata: metadata, + covariantKeyword: covariantKeyword, + returnType: typeOrFunctionTypedParameter.returnType, + typeParameters: typeOrFunctionTypedParameter.typeParameters, + parameters: typeOrFunctionTypedParameter.parameters); + } else { + node = ast.fieldFormalParameter2( + identifier: name, + comment: comment, + metadata: metadata, + covariantKeyword: covariantKeyword, + type: typeOrFunctionTypedParameter.returnType, + thisKeyword: thisKeyword, + period: periodAfterThis, + typeParameters: typeOrFunctionTypedParameter.typeParameters, + parameters: typeOrFunctionTypedParameter.parameters); + } } else { - rightSeparator = (conditionStatement as EmptyStatement).semicolon; + TypeAnnotation type = typeOrFunctionTypedParameter; + if (thisKeyword == null) { + node = ast.simpleFormalParameter2( + comment: comment, + metadata: metadata, + covariantKeyword: covariantKeyword, + keyword: keyword, + type: type, + identifier: name); + } else { + node = ast.fieldFormalParameter2( + comment: comment, + metadata: metadata, + covariantKeyword: covariantKeyword, + keyword: keyword, + type: type, + thisKeyword: thisKeyword, + period: thisKeyword.next, + identifier: name); + } } - ForParts forLoopParts; - if (initializerPart is VariableDeclarationStatement) { - forLoopParts = ast.forPartsWithDeclarations( - variables: initializerPart.variables, - leftSeparator: leftSeparator, - condition: condition, - rightSeparator: rightSeparator, - updaters: updates, - ); - } else { - forLoopParts = ast.forPartsWithExpression( - initialization: initializerPart as Expression, - leftSeparator: leftSeparator, - condition: condition, - rightSeparator: rightSeparator, - updaters: updates, - ); + ParameterKind analyzerKind = _toAnalyzerParameterKind(kind); + FormalParameter parameter = node; + if (analyzerKind != ParameterKind.REQUIRED) { + parameter = ast.defaultFormalParameter( + node, analyzerKind, defaultValue?.separator, defaultValue?.value); + } else if (defaultValue != null) { + // An error is reported if a required parameter has a default value. + // Record it as named parameter for recovery. + parameter = ast.defaultFormalParameter(node, ParameterKind.NAMED, + defaultValue.separator, defaultValue.value); } - - push(forKeyword); - push(leftParen); - push(forLoopParts); + localDeclarations[nameToken.offset] = parameter; + push(parameter); } @override - void endForControlFlow(Token token) { - debugEvent("endForControlFlow"); - var entry = pop(); - ForParts forLoopParts = pop(); - Token leftParen = pop(); - Token forToken = pop(); - - pushForControlFlowInfo(null, forToken, leftParen, forLoopParts, entry); + void endFormalParameterDefaultValueExpression() { + debugEvent("FormalParameterDefaultValueExpression"); } - void pushForControlFlowInfo(Token awaitToken, Token forToken, - Token leftParenthesis, ForLoopParts forLoopParts, Object entry) { - if (entry == _invalidCollectionElement) { - push(_invalidCollectionElement); - } else if (enableControlFlowCollections) { - push(ast.forElement( - awaitKeyword: awaitToken, - forKeyword: forToken, - leftParenthesis: leftParenthesis, - forLoopParts: forLoopParts, - rightParenthesis: leftParenthesis.endGroup, - body: entry as CollectionElement, - )); - } else { - handleRecoverableError( - templateExperimentNotEnabled - .withArguments(EnableString.control_flow_collections), - forToken, - forToken); - push(_invalidCollectionElement); + void endFormalParameters( + int count, Token leftParen, Token rightParen, MemberKind kind) { + assert(optional('(', leftParen)); + assert(optional(')', rightParen)); + debugEvent("FormalParameters"); + + List rawParameters = popTypedList(count) ?? const []; + List parameters = []; + Token leftDelimiter; + Token rightDelimiter; + for (Object raw in rawParameters) { + if (raw is _OptionalFormalParameters) { + parameters.addAll(raw.parameters ?? const []); + leftDelimiter = raw.leftDelimiter; + rightDelimiter = raw.rightDelimiter; + } else { + parameters.add(raw as FormalParameter); + } } + push(ast.formalParameterList( + leftParen, parameters, leftDelimiter, rightDelimiter, rightParen)); } @override @@ -1002,253 +932,978 @@ class AstBuilder extends StackListener { } } - void handleLiteralList( - int count, Token leftBracket, Token constKeyword, Token rightBracket) { - assert(optional('[', leftBracket)); - assert(optionalOrNull('const', constKeyword)); - assert(optional(']', rightBracket)); - debugEvent("LiteralList"); - - if (enableControlFlowCollections || enableSpreadCollections) { - List elements = popCollectionElements(count); - TypeArgumentList typeArguments = pop(); - - // TODO(danrubel): Remove this and _InvalidCollectionElement - // once control flow and spread collection support is enabled by default - elements.removeWhere((e) => e == _invalidCollectionElement); - - push(ast.listLiteral( - constKeyword, typeArguments, leftBracket, elements, rightBracket)); - } else { - List elements = popTypedList(count); - TypeArgumentList typeArguments = pop(); + @override + void endForStatementBody(Token token) { + debugEvent("endForStatementBody"); + } - List expressions = []; - if (elements != null) { - for (var elem in elements) { - if (elem is Expression) { - expressions.add(elem); - } - } - } + @override + void endFunctionExpression(Token beginToken, Token token) { + // TODO(paulberry): set up scopes properly to resolve parameters and type + // variables. Note that this is tricky due to the handling of initializers + // in constructors, so the logic should be shared with BodyBuilder as much + // as possible. + debugEvent("FunctionExpression"); - push(ast.listLiteral( - constKeyword, typeArguments, leftBracket, expressions, rightBracket)); - } + FunctionBody body = pop(); + FormalParameterList parameters = pop(); + TypeParameterList typeParameters = pop(); + push(ast.functionExpression(typeParameters, parameters, body)); } - void handleAsyncModifier(Token asyncToken, Token starToken) { - assert(asyncToken == null || - optional('async', asyncToken) || - optional('sync', asyncToken)); - assert(optionalOrNull('*', starToken)); - debugEvent("AsyncModifier"); - - push(asyncToken ?? NullValue.FunctionBodyAsyncToken); - push(starToken ?? NullValue.FunctionBodyStarToken); + @override + void endFunctionName(Token beginToken, Token token) { + debugEvent("FunctionName"); } - void endAwaitExpression(Token awaitKeyword, Token endToken) { - assert(optional('await', awaitKeyword)); - debugEvent("AwaitExpression"); - - push(ast.awaitExpression(awaitKeyword, pop())); - } - - void handleLiteralBool(Token token) { - bool value = identical(token.stringValue, "true"); - assert(value || identical(token.stringValue, "false")); - debugEvent("LiteralBool"); - - push(ast.booleanLiteral(token, value)); - } - - void handleLiteralDouble(Token token) { - assert(token.type == TokenType.DOUBLE); - debugEvent("LiteralDouble"); - - push(ast.doubleLiteral(token, double.parse(token.lexeme))); - } - - void handleLiteralNull(Token token) { - assert(optional('null', token)); - debugEvent("LiteralNull"); + @override + void endFunctionType(Token functionToken, Token questionMark) { + assert(optional('Function', functionToken)); + debugEvent("FunctionType"); + if (!enableNonNullable) { + reportErrorIfNullableType(questionMark); + } - push(ast.nullLiteral(token)); + FormalParameterList parameters = pop(); + TypeAnnotation returnType = pop(); + TypeParameterList typeParameters = pop(); + push(ast.genericFunctionType( + returnType, functionToken, typeParameters, parameters, + question: questionMark)); } @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, - ) { - if (enableControlFlowCollections || enableSpreadCollections) { - List elements = popCollectionElements(count); - - // TODO(danrubel): Remove this and _InvalidCollectionElement - // once control flow and spread collection support is enabled by default - elements.removeWhere((e) => e == _invalidCollectionElement); + void endFunctionTypeAlias( + Token typedefKeyword, Token equals, Token semicolon) { + assert(optional('typedef', typedefKeyword)); + assert(optionalOrNull('=', equals)); + assert(optional(';', semicolon)); + debugEvent("FunctionTypeAlias"); - TypeArgumentList typeArguments = pop(); - push(ast.setOrMapLiteral( - constKeyword: constKeyword, - typeArguments: typeArguments, - leftBracket: leftBrace, - elements: elements, - rightBracket: rightBrace, - )); + if (equals == null) { + FormalParameterList parameters = pop(); + TypeParameterList typeParameters = pop(); + SimpleIdentifier name = pop(); + TypeAnnotation returnType = pop(); + List metadata = pop(); + Comment comment = _findComment(metadata, typedefKeyword); + declarations.add(ast.functionTypeAlias(comment, metadata, typedefKeyword, + returnType, name, typeParameters, parameters, semicolon)); } else { - List elements = popTypedList(count); - TypeArgumentList typeArguments = pop(); - - // Replicate existing behavior that has been removed from the parser. - // This will be removed once control flow collections - // and spread collections are enabled by default. - - // Determine if this is a set or map based on type args and content - final typeArgCount = typeArguments?.arguments?.length; - bool isSet = - typeArgCount == 1 ? true : typeArgCount != null ? false : null; - isSet ??= hasSetEntry; - - // Build the set or map - if (isSet) { - final setEntries = []; - if (elements != null) { - for (var elem in elements) { - if (elem is MapLiteralEntry) { - setEntries.add(elem.key); - handleRecoverableError( - templateUnexpectedToken.withArguments(elem.separator), - elem.separator, - elem.separator); - } else if (elem is Expression) { - setEntries.add(elem); - } - } - } - push(ast.setLiteral( - constKeyword, typeArguments, leftBrace, setEntries, rightBrace)); - } else { - final mapEntries = []; - if (elements != null) { - for (var elem in elements) { - if (elem is MapLiteralEntry) { - mapEntries.add(elem); - } else if (elem is Expression) { - Token next = elem.endToken.next; - int offset = next.offset; - handleRecoverableError( - templateExpectedButGot.withArguments(':'), next, next); - handleRecoverableError( - templateExpectedIdentifier.withArguments(next), next, next); - Token separator = SyntheticToken(TokenType.COLON, offset); - Expression value = ast.simpleIdentifier( - SyntheticStringToken(TokenType.IDENTIFIER, '', offset)); - mapEntries.add(ast.mapLiteralEntry(elem, separator, value)); - } - } - } - push(ast.mapLiteral( - constKeyword, typeArguments, leftBrace, mapEntries, rightBrace)); + TypeAnnotation type = pop(); + TypeParameterList templateParameters = pop(); + SimpleIdentifier name = pop(); + List metadata = pop(); + Comment comment = _findComment(metadata, typedefKeyword); + if (type is! GenericFunctionType) { + // This error is also reported in the OutlineBuilder. + handleRecoverableError(messageTypedefNotFunction, equals, equals); + type = null; } + declarations.add(ast.genericTypeAlias( + comment, + metadata, + typedefKeyword, + name, + templateParameters, + equals, + type as GenericFunctionType, + semicolon)); } } - void handleLiteralMapEntry(Token colon, Token endToken) { - assert(optional(':', colon)); - debugEvent("LiteralMapEntry"); - - Expression value = pop(); - Expression key = pop(); - push(ast.mapLiteralEntry(key, colon, value)); - } + @override + void endFunctionTypedFormalParameter(Token nameToken) { + debugEvent("FunctionTypedFormalParameter"); - void endLiteralSymbol(Token hashToken, int tokenCount) { - assert(optional('#', hashToken)); - debugEvent("LiteralSymbol"); + FormalParameterList formalParameters = pop(); + TypeAnnotation returnType = pop(); + TypeParameterList typeParameters = pop(); - List components = popTypedList(tokenCount); - push(ast.symbolLiteral(hashToken, components)); + // Create a temporary formal parameter that will be dissected later in + // [endFormalParameter]. + push(ast.functionTypedFormalParameter2( + identifier: null, + returnType: returnType, + typeParameters: typeParameters, + parameters: formalParameters)); } @override - void handleSuperExpression(Token superKeyword, IdentifierContext context) { - assert(optional('super', superKeyword)); - debugEvent("SuperExpression"); + void endHide(Token hideKeyword) { + assert(optional('hide', hideKeyword)); + debugEvent("Hide"); - push(ast.superExpression(superKeyword)); + List hiddenNames = pop(); + push(ast.hideCombinator(hideKeyword, hiddenNames)); } @override - void handleThisExpression(Token thisKeyword, IdentifierContext context) { - assert(optional('this', thisKeyword)); - debugEvent("ThisExpression"); - - push(ast.thisExpression(thisKeyword)); + void endIfControlFlow(Token token) { + CollectionElement thenElement = pop(); + ParenthesizedExpression condition = pop(); + Token ifToken = pop(); + pushIfControlFlowInfo(ifToken, condition, thenElement, null, null); } @override - void handleType(Token beginToken, Token questionMark) { - debugEvent("Type"); - if (!enableNonNullable) { - reportErrorIfNullableType(questionMark); - } + void endIfElseControlFlow(Token token) { + CollectionElement elseElement = pop(); + Token elseToken = pop(); + CollectionElement thenElement = pop(); + ParenthesizedExpression condition = pop(); + Token ifToken = pop(); + pushIfControlFlowInfo( + ifToken, condition, thenElement, elseToken, elseElement); + } - TypeArgumentList arguments = pop(); - Identifier name = pop(); - push(ast.typeName(name, arguments, question: questionMark)); + void endIfStatement(Token ifToken, Token elseToken) { + assert(optional('if', ifToken)); + assert(optionalOrNull('else', elseToken)); + + Statement elsePart = popIfNotNull(elseToken); + Statement thenPart = pop(); + ParenthesizedExpression condition = pop(); + push(ast.ifStatement( + ifToken, + condition.leftParenthesis, + condition.expression, + condition.rightParenthesis, + thenPart, + elseToken, + elsePart)); } @override - void handleNonNullAssertExpression(Token bang) { - debugEvent('NonNullAssertExpression'); - if (!enableNonNullable) { - reportNonNullAssertExpressionNotEnabled(bang); - } else { - push(ast.postfixExpression(pop(), bang)); - } + void endImplicitCreationExpression(Token token) { + debugEvent("ImplicitCreationExpression"); + + _handleInstanceCreation(null); } @override - void endAssert(Token assertKeyword, Assert kind, Token leftParenthesis, - Token comma, Token semicolon) { - assert(optional('assert', assertKeyword)); - assert(optional('(', leftParenthesis)); - assert(optionalOrNull(',', comma)); - assert(kind != Assert.Statement || optionalOrNull(';', semicolon)); - debugEvent("Assert"); + void endImport(Token importKeyword, Token semicolon) { + assert(optional('import', importKeyword)); + assert(optionalOrNull(';', semicolon)); + debugEvent("Import"); - Expression message = popIfNotNull(comma); - Expression condition = pop(); - switch (kind) { - case Assert.Expression: - // The parser has already reported an error indicating that assert - // cannot be used in an expression. Insert a placeholder. - List arguments = [condition]; - if (message != null) { - arguments.add(message); - } - push(ast.functionExpressionInvocation( - ast.simpleIdentifier(assertKeyword), - null, - ast.argumentList( - leftParenthesis, arguments, leftParenthesis?.endGroup))); - break; - case Assert.Initializer: - push(ast.assertInitializer(assertKeyword, leftParenthesis, condition, - comma, message, leftParenthesis?.endGroup)); - break; - case Assert.Statement: - push(ast.assertStatement(assertKeyword, leftParenthesis, condition, - comma, message, leftParenthesis?.endGroup, semicolon)); - break; + List combinators = pop(); + Token deferredKeyword = pop(NullValue.Deferred); + Token asKeyword = pop(NullValue.As); + SimpleIdentifier prefix = pop(NullValue.Prefix); + List configurations = pop(); + StringLiteral uri = pop(); + List metadata = pop(); + Comment comment = _findComment(metadata, importKeyword); + + directives.add(ast.importDirective( + comment, + metadata, + importKeyword, + uri, + configurations, + deferredKeyword, + asKeyword, + prefix, + combinators, + semicolon)); + } + + void endInitializedIdentifier(Token nameToken) { + debugEvent("InitializedIdentifier"); + + AstNode node = pop(); + VariableDeclaration variable; + // TODO(paulberry): This seems kludgy. It would be preferable if we + // could respond to a "handleNoVariableInitializer" event by converting a + // SimpleIdentifier into a VariableDeclaration, and then when this code was + // reached, node would always be a VariableDeclaration. + if (node is VariableDeclaration) { + variable = node; + } else if (node is SimpleIdentifier) { + variable = _makeVariableDeclaration(node, null, null); + } else { + unhandled("${node.runtimeType}", "identifier", nameToken.charOffset, uri); + } + push(variable); + } + + void endInitializers(int count, Token colon, Token endToken) { + assert(optional(':', colon)); + debugEvent("Initializers"); + + List initializerObjects = popTypedList(count) ?? const []; + if (!isFullAst) return; + + push(colon); + + var initializers = []; + for (Object initializerObject in initializerObjects) { + if (initializerObject is FunctionExpressionInvocation) { + Expression function = initializerObject.function; + if (function is SuperExpression) { + initializers.add(ast.superConstructorInvocation(function.superKeyword, + null, null, initializerObject.argumentList)); + } else { + initializers.add(ast.redirectingConstructorInvocation( + (function as ThisExpression).thisKeyword, + null, + null, + initializerObject.argumentList)); + } + } else if (initializerObject is MethodInvocation) { + Expression target = initializerObject.target; + if (target is SuperExpression) { + initializers.add(ast.superConstructorInvocation( + target.superKeyword, + initializerObject.operator, + initializerObject.methodName, + initializerObject.argumentList)); + } else if (target is ThisExpression) { + initializers.add(ast.redirectingConstructorInvocation( + target.thisKeyword, + initializerObject.operator, + initializerObject.methodName, + initializerObject.argumentList)); + } else { + // Invalid initializer + // TODO(danrubel): Capture this in the AST. + } + } else if (initializerObject is AssignmentExpression) { + Token thisKeyword; + Token period; + SimpleIdentifier fieldName; + Expression left = initializerObject.leftHandSide; + if (left is PropertyAccess) { + Expression target = left.target; + if (target is ThisExpression) { + thisKeyword = target.thisKeyword; + period = left.operator; + } else { + assert(target is SuperExpression); + // Recovery: + // Parser has reported FieldInitializedOutsideDeclaringClass. + } + fieldName = left.propertyName; + } else if (left is SimpleIdentifier) { + fieldName = left; + } else { + // Recovery: + // Parser has reported invalid assignment. + SuperExpression superExpression = left; + fieldName = ast.simpleIdentifier(superExpression.superKeyword); + } + initializers.add(ast.constructorFieldInitializer( + thisKeyword, + period, + fieldName, + initializerObject.operator, + initializerObject.rightHandSide)); + } else if (initializerObject is AssertInitializer) { + initializers.add(initializerObject); + } + } + + push(initializers); + } + + @override + void endLabeledStatement(int labelCount) { + debugEvent("LabeledStatement"); + + Statement statement = pop(); + List