Chromium Code Reviews| Index: pkg/analyzer/tool/summary/mini_ast.dart |
| diff --git a/pkg/analyzer/tool/summary/mini_ast.dart b/pkg/analyzer/tool/summary/mini_ast.dart |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..3d6a09a73f5058c28e78dae69be63fbaaa9ed371 |
| --- /dev/null |
| +++ b/pkg/analyzer/tool/summary/mini_ast.dart |
| @@ -0,0 +1,481 @@ |
| +// Copyright (c) 2017, 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:front_end/src/fasta/errors.dart'; |
| +import 'package:front_end/src/fasta/parser/identifier_context.dart'; |
| +import 'package:front_end/src/fasta/parser/parser.dart'; |
| +import 'package:front_end/src/fasta/scanner/token.dart'; |
| +import 'package:front_end/src/fasta/source/stack_listener.dart'; |
| + |
| +/// "Mini AST" representation of a declaration which can accept annotations. |
| +class AnnotatedNode { |
| + final Comment documentationComment; |
| + |
| + final List<Annotation> metadata; |
| + |
| + AnnotatedNode(this.documentationComment, List<Annotation> metadata) |
| + : metadata = metadata ?? const []; |
| +} |
| + |
| +/// "Mini AST" representation of an annotation. |
| +class Annotation { |
| + final String name; |
| + |
| + final String constructorName; |
| + |
| + final List<Expression> arguments; |
| + |
| + Annotation(this.name, this.constructorName, this.arguments); |
| +} |
| + |
| +/// "Mini AST" representation of a class declaration. |
| +class ClassDeclaration extends CompilationUnitMember { |
| + final String name; |
| + |
| + final TypeName superclass; |
| + |
| + final List<ClassMember> members; |
| + |
| + ClassDeclaration(Comment documentationComment, List<Annotation> metadata, |
| + this.name, this.superclass, this.members) |
| + : super(documentationComment, metadata); |
| +} |
| + |
| +/// "Mini AST" representation of a class member. |
| +class ClassMember extends AnnotatedNode { |
| + ClassMember(Comment documentationComment, List<Annotation> metadata) |
| + : super(documentationComment, metadata); |
| +} |
| + |
| +/// "Mini AST" representation of a comment. |
| +class Comment { |
| + final bool isDocumentation; |
| + |
| + final List<Token> tokens; |
| + |
| + factory Comment(Token commentToken) { |
| + var tokens = <Token>[]; |
| + bool isDocumentation = false; |
| + while (commentToken != null) { |
| + if (commentToken.lexeme.startsWith('/**') || |
| + commentToken.lexeme.startsWith('///')) { |
| + isDocumentation = true; |
| + } |
| + tokens.add(commentToken); |
| + commentToken = commentToken.next; |
| + } |
| + return new Comment._(isDocumentation, tokens); |
| + } |
| + |
| + Comment._(this.isDocumentation, this.tokens); |
| +} |
| + |
| +/// "Mini AST" representation of a CompilationUnit. |
| +class CompilationUnit { |
| + final declarations = <CompilationUnitMember>[]; |
| +} |
| + |
| +/// "Mini AST" representation of a top level member of a compilation unit. |
| +class CompilationUnitMember extends AnnotatedNode { |
| + CompilationUnitMember(Comment documentationComment, List<Annotation> metadata) |
| + : super(documentationComment, metadata); |
| +} |
| + |
| +/// "Mini AST" representation of a constructor declaration. |
| +class ConstructorDeclaration extends ClassMember { |
| + final ConstructorReference name; |
| + |
| + ConstructorDeclaration( |
| + Comment documentationComment, List<Annotation> metadata, this.name) |
| + : super(documentationComment, metadata); |
| +} |
| + |
| +/// "Mini AST" representation of a constructor reference. |
| +class ConstructorReference { |
| + final String name; |
| + |
| + final String constructorName; |
| + |
| + ConstructorReference(this.name, this.constructorName); |
| +} |
| + |
| +/// "Mini AST" representation of an individual enum constant in an enum |
| +/// declaration. |
| +class EnumConstantDeclaration extends AnnotatedNode { |
| + final String name; |
| + |
| + EnumConstantDeclaration( |
| + Comment documentationComment, List<Annotation> metadata, this.name) |
| + : super(documentationComment, metadata); |
| +} |
| + |
| +/// "Mini AST" representation of an enum declaration. |
| +class EnumDeclaration extends CompilationUnitMember { |
| + final String name; |
| + |
| + final List<EnumConstantDeclaration> constants; |
| + |
| + EnumDeclaration(Comment documentationComment, List<Annotation> metadata, |
| + this.name, this.constants) |
| + : super(documentationComment, metadata); |
| +} |
| + |
| +/// "Mini AST" representation of an expression. |
| +class Expression {} |
| + |
| +/// "Mini AST" representation of an integer literal. |
| +class IntegerLiteral extends Expression { |
| + final int value; |
| + |
| + IntegerLiteral(this.value); |
| +} |
| + |
| +/// "Mini AST" representation of a method declaration. |
| +class MethodDeclaration extends ClassMember { |
| + final bool isGetter; |
| + |
| + final String name; |
| + |
| + final TypeName returnType; |
| + |
| + MethodDeclaration(Comment documentationComment, List<Annotation> metadata, |
| + this.isGetter, this.name, this.returnType) |
| + : super(documentationComment, metadata); |
| +} |
| + |
| +/// Parser listener which generates a "mini AST" representation of the source |
| +/// code. This representation is just sufficient for summary code generation. |
| +class MiniAstBuilder extends StackListener { |
| + bool inMetadata = false; |
| + |
| + final compilationUnit = new CompilationUnit(); |
| + |
| + @override |
| + Uri get uri => null; |
| + |
| + @override |
| + void beginMetadata(Token token) { |
| + inMetadata = true; |
| + } |
| + |
| + @override |
| + void beginMetadataStar(Token token) { |
| + debugEvent("beginMetadataStar"); |
| + if (token.precedingComments != null) { |
| + push(new Comment(token.precedingComments)); |
| + } else { |
| + push(NullValue.Comments); |
| + } |
| + } |
| + |
| + @override |
| + void endArguments(int count, Token beginToken, Token endToken) { |
| + debugEvent("Arguments"); |
| + push(popList(count)); |
| + } |
| + |
| + @override |
| + void endClassBody(int memberCount, Token beginToken, Token endToken) { |
| + debugEvent("ClassBody"); |
| + push(popList(memberCount)); |
| + } |
| + |
| + void endClassDeclaration( |
| + int interfacesCount, |
| + Token beginToken, |
| + Token classKeyword, |
| + Token extendsKeyword, |
| + Token implementsKeyword, |
| + Token endToken) { |
| + debugEvent("ClassDeclaration"); |
| + // ignore: strong_mode_down_cast_composite |
| + List<ClassMember> members = pop(); |
|
scheglov
2017/03/14 17:22:40
Would this be better?
var members = pop() as List<
Paul Berry
2017/03/14 17:31:36
Personally, I like it better. But IIRC, Peter has
scheglov
2017/03/14 17:35:37
OK
Probably performance is not a concern for gener
|
| + TypeName superclass = pop(); |
| + pop(); // Type variables |
| + String name = pop(); |
| + // ignore: strong_mode_down_cast_composite |
| + List<Annotation> metadata = pop(); |
| + Comment comment = pop(); |
| + compilationUnit.declarations.add( |
| + new ClassDeclaration(comment, metadata, name, superclass, members)); |
| + } |
| + |
| + @override |
| + void endCombinators(int count) { |
| + debugEvent("Combinators"); |
| + } |
| + |
| + @override |
| + void endConditionalUris(int count) { |
| + debugEvent("ConditionalUris"); |
| + if (count != 0) { |
| + internalError('Conditional URIs are not supported by summary codegen'); |
| + } |
| + } |
| + |
| + @override |
| + void endConstructorReference( |
| + Token start, Token periodBeforeName, Token endToken) { |
| + debugEvent("ConstructorReference"); |
| + String constructorName = popIfNotNull(periodBeforeName); |
| + pop(); // Type arguments |
| + String name = pop(); |
| + push(new ConstructorReference(name, constructorName)); |
| + } |
| + |
| + void endEnum(Token enumKeyword, Token endBrace, int count) { |
| + debugEvent("Enum"); |
| + // ignore: strong_mode_down_cast_composite |
| + List<EnumConstantDeclaration> constants = popList(count); |
| + String name = pop(); |
| + // ignore: strong_mode_down_cast_composite |
| + List<Annotation> metadata = pop(); |
| + Comment comment = pop(); |
| + compilationUnit.declarations |
| + .add(new EnumDeclaration(comment, metadata, name, constants)); |
| + } |
| + |
| + @override |
| + void endFactoryMethod( |
| + Token beginToken, Token factoryKeyword, Token endToken) { |
| + debugEvent("FactoryMethod"); |
| + pop(); // Body |
| + ConstructorReference name = pop(); |
| + // ignore: strong_mode_down_cast_composite |
| + List<Annotation> metadata = pop(); |
| + Comment comment = pop(); |
| + push(new ConstructorDeclaration(comment, metadata, name)); |
| + } |
| + |
| + @override |
| + void endFieldInitializer(Token assignment) { |
| + debugEvent("FieldInitializer"); |
| + pop(); // Expression |
| + } |
| + |
| + @override |
| + void endFormalParameter( |
| + Token covariantKeyword, Token thisKeyword, FormalParameterType kind) { |
| + debugEvent("FormalParameter"); |
| + pop(); // Name |
| + pop(); // Type |
| + pop(); // Metadata |
| + pop(); // Comment |
| + } |
| + |
| + @override |
| + void endFormalParameters(int count, Token beginToken, Token endToken) { |
| + debugEvent("FormalParameters"); |
| + } |
| + |
| + @override |
| + void endIdentifierList(int count) { |
| + debugEvent("IdentifierList"); |
| + push(popList(count)); |
| + } |
| + |
| + @override |
| + void endImport(Token importKeyword, Token deferredKeyword, Token asKeyword, |
| + Token semicolon) { |
| + debugEvent("Import"); |
| + popIfNotNull(asKeyword); // Prefix identifier |
| + pop(); // URI |
| + pop(); // Metadata |
| + pop(); // Comment |
| + } |
| + |
| + @override |
| + void endLibraryName(Token libraryKeyword, Token semicolon) { |
| + debugEvent("LibraryName"); |
| + pop(); // Library name |
| + pop(); // Metadata |
| + pop(); // Comment |
| + } |
| + |
| + @override |
| + void endLiteralString(int interpolationCount, Token endToken) { |
| + super.endLiteralString(interpolationCount, endToken); |
| + String value = pop(); |
| + push(new StringLiteral(value)); |
| + } |
| + |
| + @override |
| + void endMember() { |
| + debugEvent("Member"); |
| + } |
| + |
| + @override |
| + void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) { |
| + debugEvent("Metadata"); |
| + inMetadata = false; |
| + // ignore: strong_mode_down_cast_composite |
| + List<Expression> arguments = pop(); |
| + String constructorName = popIfNotNull(periodBeforeName); |
| + pop(); // Type arguments |
| + String name = pop(); |
| + push(new Annotation(name, constructorName, arguments)); |
| + } |
| + |
| + @override |
| + void endMetadataStar(int count, bool forParameter) { |
| + debugEvent("MetadataStar"); |
| + push(popList(count) ?? NullValue.Metadata); |
| + } |
| + |
| + void endMethod(Token getOrSet, Token beginToken, Token endToken) { |
| + debugEvent("Method"); |
| + pop(); // Body |
| + pop(); // Initializers |
| + pop(); // Formal parameters |
| + pop(); // Type variables |
| + String name = pop(); |
| + TypeName returnType = pop(); |
| + // ignore: strong_mode_down_cast_composite |
| + List<Annotation> metadata = pop(); |
| + Comment comment = pop(); |
| + push(new MethodDeclaration( |
| + comment, metadata, getOrSet?.lexeme == 'get', name, returnType)); |
| + } |
| + |
| + @override |
| + void endSend(Token beginToken, Token endToken) { |
| + debugEvent("Send"); |
| + // ignore: strong_mode_down_cast_composite |
| + pop(); // Arguments |
| + pop(); // Type arguments |
| + pop(); // Receiver |
| + push(new UnknownExpression()); |
| + } |
| + |
| + @override |
| + void endShow(Token showKeyword) { |
| + debugEvent("Show"); |
| + pop(); // Shown names |
| + } |
| + |
| + @override |
| + void endTopLevelFields(int count, Token beginToken, Token endToken) { |
| + // We ignore top level variable declarations; they are present just to make |
| + // the IDL analyze without warnings. |
| + debugEvent("TopLevelFields"); |
| + popList(count); // Fields |
| + pop(); // Type |
| + pop(); // Metadata |
| + pop(); // Comment |
| + } |
| + |
| + @override |
| + void endTypeArguments(int count, Token beginToken, Token endToken) { |
| + debugEvent("TypeArguments"); |
| + push(popList(count)); |
| + } |
| + |
| + @override |
| + void handleAsyncModifier(Token asyncToken, Token starToken) { |
| + debugEvent("AsyncModifier"); |
| + } |
| + |
| + @override |
| + void handleBinaryExpression(Token token) { |
| + debugEvent("BinaryExpression"); |
| + pop(); // RHS |
| + pop(); // LHS |
| + push(new UnknownExpression()); |
| + } |
| + |
| + @override |
| + void handleFormalParameterWithoutValue(Token token) { |
| + debugEvent("FormalParameterWithoutValue"); |
| + } |
| + |
| + @override |
| + void handleFunctionBodySkipped(Token token, bool isExpressionBody) { |
| + if (isExpressionBody) pop(); |
| + push(NullValue.FunctionBody); |
| + } |
| + |
| + void handleIdentifier(Token token, IdentifierContext context) { |
| + if (context == IdentifierContext.enumValueDeclaration) { |
| + var comment = new Comment(token.precedingComments); |
| + push(new EnumConstantDeclaration(comment, null, token.lexeme)); |
| + } else { |
| + push(token.lexeme); |
| + } |
| + } |
| + |
| + void handleLiteralInt(Token token) { |
| + debugEvent("LiteralInt"); |
| + push(new IntegerLiteral(int.parse(token.lexeme))); |
| + } |
| + |
| + void handleLiteralNull(Token token) { |
| + debugEvent("LiteralNull"); |
| + push(new UnknownExpression()); |
| + } |
| + |
| + @override |
| + void handleModifier(Token token) { |
| + debugEvent("Modifier"); |
| + } |
| + |
| + @override |
| + void handleModifiers(int count) { |
| + debugEvent("Modifiers"); |
| + } |
| + |
| + @override |
| + void handleQualified(Token period) { |
| + debugEvent("Qualified"); |
| + String suffix = pop(); |
| + String prefix = pop(); |
| + push('$prefix.$suffix'); |
| + } |
| + |
| + @override |
| + void handleType(Token beginToken, Token endToken) { |
| + debugEvent("Type"); |
| + // ignore: strong_mode_down_cast_composite |
| + List<TypeName> typeArguments = pop(); |
| + String name = pop(); |
| + push(new TypeName(name, typeArguments)); |
| + } |
| +} |
| + |
| +/// Parser intended for use with [MiniAstBuilder]. |
| +class MiniAstParser extends Parser { |
| + MiniAstParser(MiniAstBuilder listener) : super(listener); |
| + |
| + Token parseArgumentsOpt(Token token) { |
| + MiniAstBuilder listener = this.listener; |
| + if (listener.inMetadata) { |
| + return super.parseArgumentsOpt(token); |
| + } else { |
| + return skipArgumentsOpt(token); |
| + } |
| + } |
| + |
| + Token parseFunctionBody(Token token, bool isExpression, bool allowAbstract) { |
| + return skipFunctionBody(token, isExpression, allowAbstract); |
| + } |
| +} |
| + |
| +/// "Mini AST" representation of a string literal. |
| +class StringLiteral extends Expression { |
| + final String stringValue; |
| + |
| + StringLiteral(this.stringValue); |
| +} |
| + |
| +/// "Mini AST" representation of a type name. |
| +class TypeName { |
| + final String name; |
| + |
| + final List<TypeName> typeArguments; |
| + |
| + TypeName(this.name, this.typeArguments); |
| +} |
| + |
| +/// "Mini AST" representation of an expression which summary code generation |
| +/// need not be concerned about. |
| +class UnknownExpression extends Expression {} |