| // 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. |
| |
| import 'package:analyzer/dart/ast/ast.dart' hide Identifier; |
| import 'package:analyzer/dart/ast/token.dart'; |
| import 'package:analyzer/src/dart/ast/ast_factory.dart'; |
| import 'package:analyzer/src/fasta/analyzer_expression_generator.dart'; |
| import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; |
| import 'package:front_end/src/fasta/kernel/body_builder.dart' show LabelTarget; |
| import 'package:front_end/src/fasta/kernel/forest.dart'; |
| import 'package:kernel/ast.dart' as kernel; |
| |
| /// A data holder used to conform to the [Forest] API. |
| class Arguments { |
| List<TypeAnnotation> typeArguments = <TypeAnnotation>[]; |
| List<Expression> positionalArguments = <Expression>[]; |
| List<Expression> namedArguments = <Expression>[]; |
| } |
| |
| /// An implementation of a [Forest] that can be used to build an AST structure. |
| class AstBuildingForest |
| implements Forest<Expression, Statement, Token, Arguments> { |
| /// The type provider used to resolve the types of literal nodes, or `null` if |
| /// type resolution is not being performed. |
| final TypeProvider _typeProvider; |
| |
| /// The factory used to create AST nodes. |
| AstFactoryImpl astFactory = new AstFactoryImpl(); |
| |
| /// Initialize a newly created AST-building forest. |
| AstBuildingForest(this._typeProvider); |
| |
| @override |
| Arguments arguments(List<Expression> positional, Token location, |
| {covariant List types, covariant List named}) { |
| Arguments arguments = new Arguments(); |
| if (types != null) { |
| arguments.typeArguments = types.cast<TypeAnnotation>(); |
| } |
| arguments.positionalArguments = positional.cast<Expression>(); |
| if (named != null) { |
| arguments.namedArguments = named.cast<Expression>(); |
| } |
| return arguments; |
| } |
| |
| @override |
| Arguments argumentsEmpty(Token location) => new Arguments(); |
| |
| @override |
| List argumentsNamed(Arguments arguments) => arguments.namedArguments; |
| |
| @override |
| List<Expression> argumentsPositional(Arguments arguments) => |
| arguments.positionalArguments; |
| |
| @override |
| void argumentsSetTypeArguments(Arguments arguments, covariant List types) { |
| arguments.typeArguments = types.cast<TypeAnnotation>(); |
| } |
| |
| @override |
| List argumentsTypeArguments(Arguments arguments) => arguments.typeArguments; |
| |
| @override |
| Expression asExpression(Expression expression, type, Token location) => |
| astFactory.asExpression(expression, location, type); |
| |
| @override |
| Expression asLiteralString(Expression value) => value; |
| |
| @override |
| ConstructorInitializer assertInitializer( |
| Token assertKeyword, |
| Token leftParenthesis, |
| Expression condition, |
| Token comma, |
| Expression message) => |
| astFactory.assertInitializer(assertKeyword, leftParenthesis, condition, |
| comma, message, leftParenthesis.endGroup); |
| |
| @override |
| Statement assertStatement( |
| Token assertKeyword, |
| Token leftParenthesis, |
| Expression condition, |
| Token comma, |
| Expression message, |
| Token semicolon) => |
| astFactory.assertStatement(assertKeyword, leftParenthesis, condition, |
| comma, message, leftParenthesis.endGroup, semicolon); |
| |
| @override |
| Expression awaitExpression(Expression operand, Token awaitKeyword) => |
| astFactory.awaitExpression(awaitKeyword, operand); |
| |
| @override |
| Block block(Token openBrace, List<Statement> statements, Token closeBrace) => |
| astFactory.block(openBrace, statements, closeBrace); |
| |
| @override |
| Statement breakStatement( |
| Token breakKeyword, Identifier label, Token semicolon) => |
| astFactory.breakStatement( |
| breakKeyword, |
| label == null ? null : astFactory.simpleIdentifier(label.token), |
| semicolon); |
| |
| @override |
| kernel.Arguments castArguments(Arguments arguments) { |
| // TODO(brianwilkerson) Implement this or remove it from the API. |
| throw new UnimplementedError(); |
| } |
| |
| @override |
| CatchClause catchClause( |
| Token onKeyword, |
| TypeAnnotation exceptionType, |
| Token catchKeyword, |
| SimpleIdentifier exceptionParameter, |
| SimpleIdentifier stackTraceParameter, |
| TypeAnnotation stackTraceType, |
| Statement body) { |
| // TODO(brianwilkerson) The following is not reliable in the presence of |
| // recovery. Consider passing the required tokens from the Parser to the |
| // BodyBuilder to here. |
| Token leftParenthesis; |
| if (catchKeyword != null) { |
| leftParenthesis = catchKeyword.next; |
| } |
| Token comma; |
| if (stackTraceParameter != null) { |
| comma = exceptionParameter.endToken.next; |
| } |
| Token rightParenthesis; |
| if (catchKeyword != null) { |
| if (stackTraceParameter != null) { |
| rightParenthesis = stackTraceParameter.endToken.next; |
| } else if (comma != null) { |
| rightParenthesis = comma.next; |
| } else { |
| rightParenthesis = exceptionParameter.endToken.next; |
| } |
| } |
| return astFactory.catchClause( |
| onKeyword, |
| exceptionType, |
| catchKeyword, |
| leftParenthesis, |
| exceptionParameter, |
| comma, |
| stackTraceParameter, |
| rightParenthesis, |
| body); |
| } |
| |
| @override |
| Expression checkLibraryIsLoaded(dependency) { |
| // TODO(brianwilkerson) Implement this. |
| throw new UnimplementedError(); |
| } |
| |
| @override |
| Expression conditionalExpression(Expression condition, Token question, |
| Expression thenExpression, Token colon, Expression elseExpression) => |
| astFactory.conditionalExpression( |
| condition, question, thenExpression, colon, elseExpression); |
| |
| @override |
| Statement continueStatement( |
| Token continueKeyword, Identifier label, Token semicolon) => |
| astFactory.continueStatement( |
| continueKeyword, |
| label == null ? null : astFactory.simpleIdentifier(label.token), |
| semicolon); |
| |
| @override |
| Generator<Expression, Statement, Arguments> deferredAccessGenerator( |
| ExpressionGeneratorHelper<Expression, Statement, Arguments> helper, |
| Token token, |
| PrefixBuilder builder, |
| Generator<Expression, Statement, Arguments> generator) { |
| return new AnalyzerDeferredAccessGenerator( |
| helper, astFactory, token, builder, generator); |
| } |
| |
| @override |
| Generator<Expression, Statement, Arguments> delayedAssignment( |
| ExpressionGeneratorHelper<Expression, Statement, Arguments> helper, |
| Token token, |
| Generator<Expression, Statement, Arguments> generator, |
| Expression value, |
| String assignmentOperator) { |
| return new AnalyzerDelayedAssignmentGenerator( |
| helper, astFactory, token, generator, assignmentOperator, value); |
| } |
| |
| @override |
| Generator<Expression, Statement, Arguments> delayedPostfixIncrement( |
| ExpressionGeneratorHelper<Expression, Statement, Arguments> helper, |
| Token token, |
| Generator<Expression, Statement, Arguments> generator, |
| kernel.Name binaryOperator, |
| kernel.Procedure interfaceTarget) { |
| return new AnalyzerDelayedPostfixIncrementGenerator( |
| helper, astFactory, token, generator, binaryOperator, interfaceTarget); |
| } |
| |
| @override |
| Statement doStatement(Token doKeyword, Statement body, Token whileKeyword, |
| ParenthesizedExpression condition, Token semicolon) => |
| astFactory.doStatement( |
| doKeyword, |
| body, |
| whileKeyword, |
| condition.leftParenthesis, |
| condition.expression, |
| condition.rightParenthesis, |
| semicolon); |
| |
| @override |
| Statement emptyStatement(Token semicolon) => |
| astFactory.emptyStatement(semicolon); |
| |
| @override |
| Statement expressionStatement(Expression expression, Token semicolon) => |
| astFactory.expressionStatement(expression, semicolon); |
| |
| @override |
| Statement forStatement( |
| Token forKeyword, |
| Token leftParenthesis, |
| covariant variableList, |
| covariant initialization, |
| Token leftSeparator, |
| Expression condition, |
| Statement conditionStatement, |
| List<Expression> updaters, |
| Token rightParenthesis, |
| Statement body) => |
| astFactory.forStatement( |
| forKeyword, |
| leftParenthesis, |
| variableList, |
| initialization, |
| leftSeparator, |
| condition, |
| getSemicolon(conditionStatement), |
| updaters, |
| rightParenthesis, |
| body); |
| |
| @override |
| Expression getExpressionFromExpressionStatement(Statement statement) => |
| (statement as ExpressionStatement).expression; |
| |
| String getLabelName(Label label) => label.label.name; |
| |
| @override |
| int getLabelOffset(Label label) => label.offset; |
| |
| /// Return the semicolon at the end of the given [statement], or `null` if the |
| /// statement is not terminated by a semicolon. |
| Token getSemicolon(Statement statement) { |
| if (statement is ExpressionStatement) { |
| return statement.semicolon; |
| } |
| if (statement is EmptyStatement) { |
| return statement.semicolon; |
| } |
| return null; |
| } |
| |
| @override |
| kernel.DartType getTypeAt(TypeArgumentList typeArguments, int index) { |
| return null; // typeArguments.arguments[index].type.kernelType; |
| } |
| |
| @override |
| int getTypeCount(TypeArgumentList typeArguments) => |
| typeArguments.arguments.length; |
| |
| @override |
| String getVariableDeclarationName(VariableDeclaration declaration) { |
| return declaration.name.name; |
| } |
| |
| @override |
| Statement ifStatement( |
| Token ifKeyword, |
| ParenthesizedExpression condition, |
| Statement thenStatement, |
| Token elseKeyword, |
| Statement elseStatement) => |
| astFactory.ifStatement( |
| ifKeyword, |
| condition.leftParenthesis, |
| condition.expression, |
| condition.rightParenthesis, |
| thenStatement, |
| elseKeyword, |
| elseStatement); |
| |
| @override |
| Generator<Expression, Statement, Arguments> indexedAccessGenerator( |
| ExpressionGeneratorHelper<Expression, Statement, Arguments> helper, |
| Token token, |
| Expression receiver, |
| Expression index, |
| kernel.Procedure getter, |
| kernel.Procedure setter) { |
| return new AnalyzerIndexedAccessGenerator( |
| helper, astFactory, receiver, token, index, token.endGroup); |
| } |
| |
| @override |
| bool isBlock(Object node) => node is Block; |
| |
| @override |
| bool isEmptyStatement(Statement statement) => statement is EmptyStatement; |
| |
| @override |
| bool isErroneousNode(Object node) => false /* ??? */; |
| |
| @override |
| Expression isExpression(Expression expression, Token isOperator, |
| Token notOperator, Object type) => |
| astFactory.isExpression(expression, isOperator, notOperator, type); |
| |
| @override |
| bool isExpressionStatement(Statement statement) => |
| statement is ExpressionStatement; |
| |
| @override |
| bool isLabel(covariant node) => node is Label; |
| |
| @override |
| bool isThisExpression(Object node) => node is ThisExpression; |
| |
| @override |
| bool isVariablesDeclaration(Object node) => |
| node is VariableDeclarationStatement && node.variables != 1; |
| |
| @override |
| Label label(Token identifier, Token colon) => astFactory.label( |
| astFactory.simpleIdentifier(identifier, isDeclaration: true), colon); |
| |
| @override |
| Statement labeledStatement( |
| LabelTarget<Statement> target, Statement statement) => |
| astFactory.labeledStatement(target.labels.cast<Label>(), statement); |
| |
| @override |
| Generator<Expression, Statement, Arguments> largeIntAccessGenerator( |
| ExpressionGeneratorHelper<Expression, Statement, Arguments> helper, |
| Token token) { |
| return new AnalyzerLargeIntAccessGenerator(helper, astFactory, token); |
| } |
| |
| @override |
| Expression literalBool(bool value, Token location) => |
| astFactory.booleanLiteral(location, value) |
| ..staticType = _typeProvider?.boolType; |
| |
| @override |
| Expression literalDouble(double value, Token location) => |
| astFactory.doubleLiteral(location, value) |
| ..staticType = _typeProvider?.doubleType; |
| |
| @override |
| Expression literalInt(int value, Token location) => |
| astFactory.integerLiteral(location, value) |
| ..staticType = _typeProvider?.intType; |
| |
| @override |
| Expression literalList( |
| Token constKeyword, |
| bool isConst, |
| Object typeArgument, |
| Object typeArguments, |
| Token leftBracket, |
| List<Expression> expressions, |
| Token rightBracket) => |
| astFactory.listLiteral( |
| constKeyword, typeArguments, leftBracket, expressions, rightBracket); |
| |
| @override |
| Expression literalMap( |
| Token constKeyword, |
| bool isConst, |
| covariant keyType, |
| covariant valueType, |
| Object typeArguments, |
| Token leftBracket, |
| covariant List entries, |
| Token rightBracket) => |
| astFactory.mapLiteral( |
| constKeyword, typeArguments, leftBracket, entries, rightBracket); |
| |
| @override |
| Expression literalNull(Token location) => |
| astFactory.nullLiteral(location)..staticType = _typeProvider?.nullType; |
| |
| @override |
| Expression literalString(String value, Token location) => |
| astFactory.simpleStringLiteral(location, value) |
| ..staticType = _typeProvider?.stringType; |
| |
| @override |
| Expression literalSymbolMultiple( |
| String value, Token hash, List<Identifier> components) => |
| astFactory.symbolLiteral( |
| hash, components.map((identifier) => identifier.token).toList()) |
| ..staticType = _typeProvider?.symbolType; |
| |
| @override |
| Expression literalSymbolSingluar(String value, Token hash, Object component) { |
| Token token; |
| if (component is Identifier) { |
| token = component.token; |
| } else if (component is Operator) { |
| token = component.token; |
| } else { |
| throw new ArgumentError( |
| 'Unexpected class of component: ${component.runtimeType}'); |
| } |
| return astFactory.symbolLiteral(hash, <Token>[token]) |
| ..staticType = _typeProvider?.symbolType; |
| } |
| |
| @override |
| Expression literalType(covariant type, Token location) { |
| // TODO(brianwilkerson) Capture the type information. |
| return astFactory.simpleIdentifier(location) |
| ..staticType = _typeProvider?.typeType; |
| } |
| |
| @override |
| Expression loadLibrary(dependency) { |
| // TODO(brianwilkerson) Implement this. |
| throw new UnimplementedError(); |
| } |
| |
| @override |
| Generator<Expression, Statement, Arguments> loadLibraryGenerator( |
| ExpressionGeneratorHelper<Expression, Statement, Arguments> helper, |
| Token token, |
| LoadLibraryBuilder builder) { |
| return new AnalyzerLoadLibraryGenerator(helper, astFactory, token, builder); |
| } |
| |
| @override |
| Expression logicalExpression( |
| Expression leftOperand, Token operator, Expression rightOperand) => |
| astFactory.binaryExpression(leftOperand, operator, rightOperand); |
| |
| @override |
| Object mapEntry(Expression key, Token colon, Expression value) => |
| astFactory.mapLiteralEntry(key, colon, value); |
| |
| @override |
| List mapEntryList(int length) => new List<MapLiteralEntry>(length); |
| |
| @override |
| Expression notExpression(Expression operand, Token operator) => |
| astFactory.prefixExpression(operator, operand) |
| ..staticType = _typeProvider?.boolType; |
| |
| @override |
| Generator<Expression, Statement, Arguments> nullAwarePropertyAccessGenerator( |
| ExpressionGeneratorHelper<Expression, Statement, Arguments> helper, |
| Token token, |
| Expression receiverExpression, |
| kernel.Name name, |
| kernel.Member getter, |
| kernel.Member setter, |
| kernel.DartType type) { |
| return new AnalyzerNullAwarePropertyAccessGenerator( |
| helper, astFactory, receiverExpression, token, null /*name*/); |
| } |
| |
| @override |
| Object parenthesizedCondition(Token leftParenthesis, Expression expression, |
| Token rightParenthesis) => |
| astFactory.parenthesizedExpression( |
| leftParenthesis, expression, rightParenthesis); |
| |
| @override |
| Generator<Expression, Statement, Arguments> propertyAccessGenerator( |
| ExpressionGeneratorHelper<Expression, Statement, Arguments> helper, |
| Token token, |
| Expression receiver, |
| kernel.Name name, |
| kernel.Member getter, |
| kernel.Member setter) { |
| return new AnalyzerPropertyAccessGenerator( |
| helper, astFactory, token, receiver, name, getter, setter); |
| } |
| |
| @override |
| int readOffset(AstNode node) => node.offset; |
| |
| @override |
| Generator<Expression, Statement, Arguments> readOnlyAccessGenerator( |
| ExpressionGeneratorHelper<Expression, Statement, Arguments> helper, |
| Token token, |
| Expression expression, |
| String plainNameForRead) { |
| return new AnalyzerReadOnlyAccessGenerator( |
| helper, astFactory, token, expression, plainNameForRead); |
| } |
| |
| @override |
| void resolveBreak(Statement target, BreakStatement user) { |
| user.target = target; |
| } |
| |
| @override |
| void resolveContinue(Statement target, ContinueStatement user) { |
| user.target = target; |
| } |
| |
| @override |
| void resolveContinueInSwitch(SwitchStatement target, ContinueStatement user) { |
| user.target = target; |
| } |
| |
| @override |
| Statement rethrowStatement(Token rethrowKeyword, Token semicolon) => |
| astFactory.expressionStatement( |
| astFactory.rethrowExpression(rethrowKeyword), semicolon); |
| |
| @override |
| Statement returnStatement( |
| Token returnKeyword, Expression expression, Token semicolon) => |
| astFactory.returnStatement(returnKeyword, expression, semicolon); |
| |
| @override |
| void setParameterType(FormalParameter parameter, TypeAnnotation type) { |
| parameter.identifier.staticType = type.type; |
| } |
| |
| @override |
| Generator<Expression, Statement, Arguments> staticAccessGenerator( |
| ExpressionGeneratorHelper<Expression, Statement, Arguments> helper, |
| Token token, |
| kernel.Member getter, |
| kernel.Member setter) { |
| return new AnalyzerStaticAccessGenerator( |
| helper, astFactory, token, getter, setter); |
| } |
| |
| @override |
| Expression stringConcatenationExpression( |
| List<Expression> strings, Token location) => |
| astFactory.adjacentStrings(strings.cast<StringLiteral>()); |
| |
| @override |
| Generator<Expression, Statement, Arguments> superIndexedAccessGenerator( |
| ExpressionGeneratorHelper<Expression, Statement, Arguments> helper, |
| Token token, |
| Expression index, |
| kernel.Member getter, |
| kernel.Member setter) { |
| // TODO(brianwilkerson) Figure out how to get the token for `super`. |
| return new AnalyzerIndexedAccessGenerator( |
| helper, astFactory, null, token, index, token.endGroup); |
| } |
| |
| @override |
| Generator<Expression, Statement, Arguments> superPropertyAccessGenerator( |
| ExpressionGeneratorHelper<Expression, Statement, Arguments> helper, |
| Token token, |
| kernel.Name name, |
| kernel.Member getter, |
| kernel.Member setter) { |
| // TODO(brianwilkerson) Figure out how to get the token for the name. |
| return new AnalyzerSuperPropertyAccessGenerator( |
| helper, astFactory, null, null, null /*name*/); |
| } |
| |
| @override |
| Statement syntheticLabeledStatement(Statement statement) => statement; |
| |
| @override |
| Expression thisExpression(Token thisKeyword) => |
| astFactory.thisExpression(thisKeyword); |
| |
| @override |
| Generator<Expression, Statement, Arguments> thisIndexedAccessGenerator( |
| ExpressionGeneratorHelper<Expression, Statement, Arguments> helper, |
| Token token, |
| Expression index, |
| kernel.Procedure getter, |
| kernel.Procedure setter) { |
| // TODO(brianwilkerson) Figure out how to get the token for `this`. |
| return new AnalyzerIndexedAccessGenerator( |
| helper, astFactory, null, token, index, token.endGroup); |
| } |
| |
| @override |
| Generator<Expression, Statement, Arguments> thisPropertyAccessGenerator( |
| ExpressionGeneratorHelper<Expression, Statement, Arguments> helper, |
| Token location, |
| kernel.Name name, |
| kernel.Member getter, |
| kernel.Member setter) { |
| // TODO(brianwilkerson) Figure out how to get the token for the name. |
| return new AnalyzerThisPropertyAccessGenerator( |
| helper, astFactory, location, name, getter, setter); |
| } |
| |
| @override |
| Expression throwExpression(Token throwKeyword, Expression expression) => |
| astFactory.throwExpression(throwKeyword, expression); |
| |
| @override |
| Statement tryStatement( |
| Token tryKeyword, |
| Statement body, |
| List<CatchClause> catchClauses, |
| Token finallyKeyword, |
| Statement finallyBlock) => |
| astFactory.tryStatement( |
| tryKeyword, body, catchClauses, finallyKeyword, finallyBlock); |
| |
| @override |
| Generator<Expression, Statement, Arguments> typeUseGenerator( |
| ExpressionGeneratorHelper<Expression, Statement, Arguments> helper, |
| Token token, |
| PrefixBuilder prefix, |
| int declarationReferenceOffset, |
| TypeDeclarationBuilder declaration, |
| String plainNameForRead) { |
| return new AnalyzerTypeUseGenerator(helper, astFactory, token, prefix, |
| declarationReferenceOffset, declaration, plainNameForRead); |
| } |
| |
| @override |
| Generator<Expression, Statement, Arguments> unlinkedGenerator( |
| ExpressionGeneratorHelper<Expression, Statement, Arguments> helper, |
| Token token, |
| UnlinkedDeclaration declaration) { |
| return new AnalyzerUnlinkedNameGenerator( |
| helper, astFactory, token, declaration); |
| } |
| |
| @override |
| Generator<Expression, Statement, Arguments> unresolvedNameGenerator( |
| ExpressionGeneratorHelper<Expression, Statement, Arguments> helper, |
| Token token, |
| kernel.Name name) { |
| return new AnalyzerUnresolvedNameGenerator(helper, astFactory, token, name); |
| } |
| |
| @override |
| VariableDeclarationStatement variablesDeclaration( |
| List<VariableDeclaration> declarations, Uri uri) { |
| // TODO(brianwilkerson) Implement this. |
| throw new UnimplementedError(); |
| } |
| |
| @override |
| NodeList<VariableDeclaration> variablesDeclarationExtractDeclarations( |
| VariableDeclarationStatement variablesDeclaration) => |
| variablesDeclaration.variables.variables; |
| |
| @override |
| Generator<Expression, Statement, Arguments> variableUseGenerator( |
| ExpressionGeneratorHelper<Expression, Statement, Arguments> helper, |
| Token token, |
| VariableDeclarationStatement variable, |
| kernel.DartType promotedType) { |
| return new AnalyzerVariableUseGenerator(helper, astFactory, token); |
| } |
| |
| Statement whileStatement(Token whileKeyword, |
| ParenthesizedExpression condition, Statement body) => |
| astFactory.whileStatement(whileKeyword, condition.leftParenthesis, |
| condition.expression, condition.rightParenthesis, body); |
| |
| @override |
| Statement wrapVariables(Statement statement) => statement; |
| |
| @override |
| Statement yieldStatement(Token yieldKeyword, Token star, |
| Expression expression, Token semicolon) => |
| astFactory.yieldStatement(yieldKeyword, star, expression, semicolon); |
| } |