blob: 424a9aaf35f2644e97a3847b63cb994cd6945bd8 [file] [log] [blame]
// Copyright (c) 2020, 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.
// @dart = 2.9
import 'dart:typed_data' show Uint8List;
import 'dart:io' show File;
import 'package:_fe_analyzer_shared/src/scanner/scanner.dart'
show ScannerConfiguration;
import 'package:_fe_analyzer_shared/src/parser/parser.dart'
show ClassMemberParser, Parser;
import 'package:_fe_analyzer_shared/src/scanner/utf8_bytes_scanner.dart'
show Utf8BytesScanner;
import 'package:_fe_analyzer_shared/src/scanner/token.dart' show Token;
import 'package:front_end/src/fasta/util/direct_parser_ast_helper.dart';
DirectParserASTContentCompilationUnitEnd getAST(List<int> rawBytes,
{bool includeBody: true,
bool includeComments: false,
bool enableExtensionMethods: false,
bool enableNonNullable: false,
bool enableTripleShift: false}) {
Uint8List bytes = new Uint8List(rawBytes.length + 1);
bytes.setRange(0, rawBytes.length, rawBytes);
ScannerConfiguration scannerConfiguration = new ScannerConfiguration(
enableExtensionMethods: enableExtensionMethods,
enableNonNullable: enableNonNullable,
enableTripleShift: enableTripleShift);
Utf8BytesScanner scanner = new Utf8BytesScanner(
bytes,
includeComments: includeComments,
configuration: scannerConfiguration,
languageVersionChanged: (scanner, languageVersion) {
// For now don't do anything, but having it (making it non-null) means the
// configuration won't be reset.
},
);
Token firstToken = scanner.tokenize();
if (firstToken == null) {
throw "firstToken is null";
}
DirectParserASTListener listener = new DirectParserASTListener();
Parser parser;
if (includeBody) {
parser = new Parser(listener);
} else {
parser = new ClassMemberParser(listener);
}
parser.parseUnit(firstToken);
return listener.data.single;
}
/// Best-effort visitor for DirectParserASTContent that visits top-level entries
/// and class members only (i.e. no bodies, no field initializer content, no
/// names etc).
class DirectParserASTContentVisitor {
void accept(DirectParserASTContent node) {
if (node is DirectParserASTContentCompilationUnitEnd ||
node is DirectParserASTContentTopLevelDeclarationEnd ||
node is DirectParserASTContentClassOrMixinBodyEnd ||
node is DirectParserASTContentMemberEnd) {
visitChildren(node);
return;
}
if (node.type == DirectParserASTType.BEGIN) {
// Ignored. These are basically just dummy nodes anyway.
assert(node.children == null);
return;
}
if (node.type == DirectParserASTType.HANDLE) {
// Ignored at least for know.
assert(node.children == null);
return;
}
if (node is DirectParserASTContentTypeVariablesEnd ||
node is DirectParserASTContentTypeArgumentsEnd ||
node is DirectParserASTContentTypeListEnd ||
node is DirectParserASTContentFunctionTypeEnd ||
node is DirectParserASTContentBlockEnd) {
// Ignored at least for know.
return;
}
if (node is DirectParserASTContentMetadataStarEnd) {
DirectParserASTContentMetadataStarEnd metadata = node;
visitMetadataStar(metadata);
return;
}
if (node is DirectParserASTContentFunctionTypeAliasEnd) {
DirectParserASTContentFunctionTypeAliasEnd typedefDecl = node;
visitTypedef(
typedefDecl, typedefDecl.typedefKeyword, typedefDecl.endToken);
return;
}
if (node is DirectParserASTContentClassDeclarationEnd) {
DirectParserASTContentClassDeclarationEnd cls = node;
visitClass(cls, cls.beginToken, cls.endToken);
return;
}
if (node is DirectParserASTContentTopLevelMethodEnd) {
DirectParserASTContentTopLevelMethodEnd method = node;
visitTopLevelMethod(method, method.beginToken, method.endToken);
return;
}
if (node is DirectParserASTContentClassMethodEnd) {
DirectParserASTContentClassMethodEnd method = node;
visitClassMethod(method, method.beginToken, method.endToken);
return;
}
if (node is DirectParserASTContentExtensionMethodEnd) {
DirectParserASTContentExtensionMethodEnd method = node;
visitExtensionMethod(method, method.beginToken, method.endToken);
return;
}
if (node is DirectParserASTContentMixinMethodEnd) {
DirectParserASTContentMixinMethodEnd method = node;
visitMixinMethod(method, method.beginToken, method.endToken);
return;
}
if (node is DirectParserASTContentImportEnd) {
DirectParserASTContentImportEnd import = node;
visitImport(import, import.importKeyword, import.semicolon);
return;
}
if (node is DirectParserASTContentExportEnd) {
DirectParserASTContentExportEnd export = node;
visitExport(export, export.exportKeyword, export.semicolon);
return;
}
if (node is DirectParserASTContentTopLevelFieldsEnd) {
// TODO(jensj): Possibly this could go into more details too
// (e.g. to split up a field declaration).
DirectParserASTContentTopLevelFieldsEnd fields = node;
visitTopLevelFields(fields, fields.beginToken, fields.endToken);
return;
}
if (node is DirectParserASTContentClassFieldsEnd) {
// TODO(jensj): Possibly this could go into more details too
// (e.g. to split up a field declaration).
DirectParserASTContentClassFieldsEnd fields = node;
visitClassFields(fields, fields.beginToken, fields.endToken);
return;
}
if (node is DirectParserASTContentExtensionFieldsEnd) {
// TODO(jensj): Possibly this could go into more details too
// (e.g. to split up a field declaration).
DirectParserASTContentExtensionFieldsEnd fields = node;
visitExtensionFields(fields, fields.beginToken, fields.endToken);
return;
}
if (node is DirectParserASTContentMixinFieldsEnd) {
// TODO(jensj): Possibly this could go into more details too
// (e.g. to split up a field declaration).
DirectParserASTContentMixinFieldsEnd fields = node;
visitMixinFields(fields, fields.beginToken, fields.endToken);
return;
}
if (node is DirectParserASTContentNamedMixinApplicationEnd) {
DirectParserASTContentNamedMixinApplicationEnd namedMixin = node;
visitNamedMixin(namedMixin, namedMixin.begin, namedMixin.endToken);
return;
}
if (node is DirectParserASTContentMixinDeclarationEnd) {
DirectParserASTContentMixinDeclarationEnd declaration = node;
visitMixin(declaration, declaration.mixinKeyword, declaration.endToken);
return;
}
if (node is DirectParserASTContentEnumEnd) {
DirectParserASTContentEnumEnd declaration = node;
visitEnum(
declaration, declaration.enumKeyword, declaration.leftBrace.endGroup);
return;
}
if (node is DirectParserASTContentLibraryNameEnd) {
DirectParserASTContentLibraryNameEnd name = node;
visitLibraryName(name, name.libraryKeyword, name.semicolon);
return;
}
if (node is DirectParserASTContentPartEnd) {
DirectParserASTContentPartEnd part = node;
visitPart(part, part.partKeyword, part.semicolon);
return;
}
if (node is DirectParserASTContentPartOfEnd) {
DirectParserASTContentPartOfEnd partOf = node;
visitPartOf(partOf, partOf.partKeyword, partOf.semicolon);
return;
}
if (node is DirectParserASTContentExtensionDeclarationEnd) {
DirectParserASTContentExtensionDeclarationEnd ext = node;
visitExtension(ext, ext.extensionKeyword, ext.endToken);
return;
}
if (node is DirectParserASTContentClassConstructorEnd) {
DirectParserASTContentClassConstructorEnd decl = node;
visitClassConstructor(decl, decl.beginToken, decl.endToken);
return;
}
if (node is DirectParserASTContentExtensionConstructorEnd) {
DirectParserASTContentExtensionConstructorEnd decl = node;
visitExtensionConstructor(decl, decl.beginToken, decl.endToken);
return;
}
if (node is DirectParserASTContentClassFactoryMethodEnd) {
DirectParserASTContentClassFactoryMethodEnd decl = node;
visitClassFactoryMethod(decl, decl.beginToken, decl.endToken);
return;
}
if (node is DirectParserASTContentExtensionFactoryMethodEnd) {
DirectParserASTContentExtensionFactoryMethodEnd decl = node;
visitExtensionFactoryMethod(decl, decl.beginToken, decl.endToken);
return;
}
if (node is DirectParserASTContentMetadataEnd) {
DirectParserASTContentMetadataEnd decl = node;
// TODO(jensj): endToken is not part of the metadata! It's the first token
// of the next thing.
visitMetadata(decl, decl.beginToken, decl.endToken.previous);
return;
}
throw "Unknown: $node (${node.runtimeType} @ ${node.what})";
}
void visitChildren(DirectParserASTContent node) {
if (node.children == null) return;
final int numChildren = node.children.length;
for (int i = 0; i < numChildren; i++) {
DirectParserASTContent child = node.children[i];
accept(child);
}
}
/// Note: Implementers are NOT expected to call visitChildren on this node.
void visitImport(DirectParserASTContentImportEnd node, Token startInclusive,
Token endInclusive) {}
/// Note: Implementers are NOT expected to call visitChildren on this node.
void visitExport(DirectParserASTContentExportEnd node, Token startInclusive,
Token endInclusive) {}
/// Note: Implementers are NOT expected to call visitChildren on this node.
void visitTypedef(DirectParserASTContentFunctionTypeAliasEnd node,
Token startInclusive, Token endInclusive) {}
/// Note: Implementers can call visitChildren on this node.
void visitMetadataStar(DirectParserASTContentMetadataStarEnd node) {
visitChildren(node);
}
/// Note: Implementers can call visitChildren on this node.
void visitClass(DirectParserASTContentClassDeclarationEnd node,
Token startInclusive, Token endInclusive) {
visitChildren(node);
}
/// Note: Implementers are NOT expected to call visitChildren on this node.
void visitTopLevelMethod(DirectParserASTContentTopLevelMethodEnd node,
Token startInclusive, Token endInclusive) {}
/// Note: Implementers are NOT expected to call visitChildren on this node.
void visitClassMethod(DirectParserASTContentClassMethodEnd node,
Token startInclusive, Token endInclusive) {}
/// Note: Implementers are NOT expected to call visitChildren on this node.
void visitExtensionMethod(DirectParserASTContentExtensionMethodEnd node,
Token startInclusive, Token endInclusive) {}
/// Note: Implementers are NOT expected to call visitChildren on this node.
void visitMixinMethod(DirectParserASTContentMixinMethodEnd node,
Token startInclusive, Token endInclusive) {}
/// Note: Implementers are NOT expected to call visitChildren on this node.
void visitTopLevelFields(DirectParserASTContentTopLevelFieldsEnd node,
Token startInclusive, Token endInclusive) {}
/// Note: Implementers are NOT expected to call visitChildren on this node.
void visitClassFields(DirectParserASTContentClassFieldsEnd node,
Token startInclusive, Token endInclusive) {}
/// Note: Implementers are NOT expected to call visitChildren on this node.
void visitExtensionFields(DirectParserASTContentExtensionFieldsEnd node,
Token startInclusive, Token endInclusive) {}
/// Note: Implementers are NOT expected to call visitChildren on this node.
void visitMixinFields(DirectParserASTContentMixinFieldsEnd node,
Token startInclusive, Token endInclusive) {}
/// Note: Implementers can call visitChildren on this node.
void visitNamedMixin(DirectParserASTContentNamedMixinApplicationEnd node,
Token startInclusive, Token endInclusive) {
visitChildren(node);
}
/// Note: Implementers can call visitChildren on this node.
void visitMixin(DirectParserASTContentMixinDeclarationEnd node,
Token startInclusive, Token endInclusive) {
visitChildren(node);
}
/// Note: Implementers are NOT expected to call visitChildren on this node.
void visitEnum(DirectParserASTContentEnumEnd node, Token startInclusive,
Token endInclusive) {}
/// Note: Implementers are NOT expected to call visitChildren on this node.
void visitLibraryName(DirectParserASTContentLibraryNameEnd node,
Token startInclusive, Token endInclusive) {}
/// Note: Implementers are NOT expected to call visitChildren on this node.
void visitPart(DirectParserASTContentPartEnd node, Token startInclusive,
Token endInclusive) {}
/// Note: Implementers are NOT expected to call visitChildren on this node.
void visitPartOf(DirectParserASTContentPartOfEnd node, Token startInclusive,
Token endInclusive) {}
/// Note: Implementers can call visitChildren on this node.
void visitExtension(DirectParserASTContentExtensionDeclarationEnd node,
Token startInclusive, Token endInclusive) {
visitChildren(node);
}
/// Note: Implementers are NOT expected to call visitChildren on this node.
void visitClassConstructor(DirectParserASTContentClassConstructorEnd node,
Token startInclusive, Token endInclusive) {}
/// Note: Implementers are NOT expected to call visitChildren on this node.
void visitExtensionConstructor(
DirectParserASTContentExtensionConstructorEnd node,
Token startInclusive,
Token endInclusive) {}
/// Note: Implementers are NOT expected to call visitChildren on this node.
void visitClassFactoryMethod(DirectParserASTContentClassFactoryMethodEnd node,
Token startInclusive, Token endInclusive) {}
/// Note: Implementers are NOT expected to call visitChildren on this node.
void visitExtensionFactoryMethod(
DirectParserASTContentExtensionFactoryMethodEnd node,
Token startInclusive,
Token endInclusive) {}
/// Note: Implementers are NOT expected to call visitChildren on this node.
void visitMetadata(DirectParserASTContentMetadataEnd node,
Token startInclusive, Token endInclusive) {}
}
extension GeneralASTContentExtension on DirectParserASTContent {
bool isClass() {
if (this is! DirectParserASTContentTopLevelDeclarationEnd) {
return false;
}
if (children.first
is! DirectParserASTContentClassOrNamedMixinApplicationPreludeBegin) {
return false;
}
if (children.last is! DirectParserASTContentClassDeclarationEnd) {
return false;
}
return true;
}
DirectParserASTContentClassDeclarationEnd asClass() {
if (!isClass()) throw "Not class";
return children.last;
}
bool isImport() {
if (this is! DirectParserASTContentTopLevelDeclarationEnd) {
return false;
}
if (children.first
is! DirectParserASTContentUncategorizedTopLevelDeclarationBegin) {
return false;
}
if (children.last is! DirectParserASTContentImportEnd) {
return false;
}
return true;
}
DirectParserASTContentImportEnd asImport() {
if (!isImport()) throw "Not import";
return children.last;
}
bool isExport() {
if (this is! DirectParserASTContentTopLevelDeclarationEnd) {
return false;
}
if (children.first
is! DirectParserASTContentUncategorizedTopLevelDeclarationBegin) {
return false;
}
if (children.last is! DirectParserASTContentExportEnd) {
return false;
}
return true;
}
DirectParserASTContentExportEnd asExport() {
if (!isExport()) throw "Not export";
return children.last;
}
bool isEnum() {
if (this is! DirectParserASTContentTopLevelDeclarationEnd) {
return false;
}
if (children.first
is! DirectParserASTContentUncategorizedTopLevelDeclarationBegin) {
return false;
}
if (children.last is! DirectParserASTContentEnumEnd) {
return false;
}
return true;
}
DirectParserASTContentEnumEnd asEnum() {
if (!isEnum()) throw "Not enum";
return children.last;
}
bool isTypedef() {
if (this is! DirectParserASTContentTopLevelDeclarationEnd) {
return false;
}
if (children.first
is! DirectParserASTContentUncategorizedTopLevelDeclarationBegin) {
return false;
}
if (children.last is! DirectParserASTContentFunctionTypeAliasEnd) {
return false;
}
return true;
}
DirectParserASTContentFunctionTypeAliasEnd asTypedef() {
if (!isTypedef()) throw "Not typedef";
return children.last;
}
bool isScript() {
if (this is! DirectParserASTContentScriptHandle) {
return false;
}
return true;
}
DirectParserASTContentScriptHandle asScript() {
if (!isScript()) throw "Not script";
return this;
}
bool isExtension() {
if (this is! DirectParserASTContentTopLevelDeclarationEnd) {
return false;
}
if (children.first
is! DirectParserASTContentExtensionDeclarationPreludeBegin) {
return false;
}
if (children.last is! DirectParserASTContentExtensionDeclarationEnd) {
return false;
}
return true;
}
DirectParserASTContentExtensionDeclarationEnd asExtension() {
if (!isExtension()) throw "Not extension";
return children.last;
}
bool isInvalidTopLevelDeclaration() {
if (this is! DirectParserASTContentTopLevelDeclarationEnd) {
return false;
}
if (children.first is! DirectParserASTContentTopLevelMemberBegin) {
return false;
}
if (children.last
is! DirectParserASTContentInvalidTopLevelDeclarationHandle) {
return false;
}
return true;
}
bool isRecoverableError() {
if (this is! DirectParserASTContentTopLevelDeclarationEnd) {
return false;
}
if (children.first
is! DirectParserASTContentUncategorizedTopLevelDeclarationBegin) {
return false;
}
if (children.last is! DirectParserASTContentRecoverableErrorHandle) {
return false;
}
return true;
}
bool isRecoverImport() {
if (this is! DirectParserASTContentTopLevelDeclarationEnd) {
return false;
}
if (children.first
is! DirectParserASTContentUncategorizedTopLevelDeclarationBegin) {
return false;
}
if (children.last is! DirectParserASTContentRecoverImportHandle) {
return false;
}
return true;
}
bool isMixinDeclaration() {
if (this is! DirectParserASTContentTopLevelDeclarationEnd) {
return false;
}
if (children.first
is! DirectParserASTContentClassOrNamedMixinApplicationPreludeBegin) {
return false;
}
if (children.last is! DirectParserASTContentMixinDeclarationEnd) {
return false;
}
return true;
}
DirectParserASTContentMixinDeclarationEnd asMixinDeclaration() {
if (!isMixinDeclaration()) throw "Not mixin declaration";
return children.last;
}
bool isNamedMixinDeclaration() {
if (this is! DirectParserASTContentTopLevelDeclarationEnd) {
return false;
}
if (children.first
is! DirectParserASTContentClassOrNamedMixinApplicationPreludeBegin) {
return false;
}
if (children.last is! DirectParserASTContentNamedMixinApplicationEnd) {
return false;
}
return true;
}
DirectParserASTContentNamedMixinApplicationEnd asNamedMixinDeclaration() {
if (!isNamedMixinDeclaration()) throw "Not named mixin declaration";
return children.last;
}
bool isTopLevelMethod() {
if (this is! DirectParserASTContentTopLevelDeclarationEnd) {
return false;
}
if (children.first is! DirectParserASTContentTopLevelMemberBegin) {
return false;
}
if (children.last is! DirectParserASTContentTopLevelMethodEnd) {
return false;
}
return true;
}
DirectParserASTContentTopLevelMethodEnd asTopLevelMethod() {
if (!isTopLevelMethod()) throw "Not top level method";
return children.last;
}
bool isTopLevelFields() {
if (this is! DirectParserASTContentTopLevelDeclarationEnd) {
return false;
}
if (children.first is! DirectParserASTContentTopLevelMemberBegin) {
return false;
}
if (children.last is! DirectParserASTContentTopLevelFieldsEnd) {
return false;
}
return true;
}
DirectParserASTContentTopLevelFieldsEnd asTopLevelFields() {
if (!isTopLevelFields()) throw "Not top level fields";
return children.last;
}
bool isLibraryName() {
if (this is! DirectParserASTContentTopLevelDeclarationEnd) {
return false;
}
if (children.first
is! DirectParserASTContentUncategorizedTopLevelDeclarationBegin) {
return false;
}
if (children.last is! DirectParserASTContentLibraryNameEnd) {
return false;
}
return true;
}
DirectParserASTContentLibraryNameEnd asLibraryName() {
if (!isLibraryName()) throw "Not library name";
return children.last;
}
bool isPart() {
if (this is! DirectParserASTContentTopLevelDeclarationEnd) {
return false;
}
if (children.first
is! DirectParserASTContentUncategorizedTopLevelDeclarationBegin) {
return false;
}
if (children.last is! DirectParserASTContentPartEnd) {
return false;
}
return true;
}
DirectParserASTContentPartEnd asPart() {
if (!isPart()) throw "Not part";
return children.last;
}
bool isPartOf() {
if (this is! DirectParserASTContentTopLevelDeclarationEnd) {
return false;
}
if (children.first
is! DirectParserASTContentUncategorizedTopLevelDeclarationBegin) {
return false;
}
if (children.last is! DirectParserASTContentPartOfEnd) {
return false;
}
return true;
}
DirectParserASTContentPartOfEnd asPartOf() {
if (!isPartOf()) throw "Not part of";
return children.last;
}
bool isMetadata() {
if (this is! DirectParserASTContentMetadataStarEnd) {
return false;
}
if (children.first is! DirectParserASTContentMetadataStarBegin) {
return false;
}
return true;
}
DirectParserASTContentMetadataStarEnd asMetadata() {
if (!isMetadata()) throw "Not metadata";
return this;
}
bool isFunctionBody() {
if (this is DirectParserASTContentBlockFunctionBodyEnd) return true;
return false;
}
DirectParserASTContentBlockFunctionBodyEnd asFunctionBody() {
if (!isFunctionBody()) throw "Not function body";
return this;
}
List<E> recursivelyFind<E extends DirectParserASTContent>() {
Set<E> result = {};
_recursivelyFindInternal(this, result);
return result.toList();
}
static void _recursivelyFindInternal<E extends DirectParserASTContent>(
DirectParserASTContent node, Set<E> result) {
if (node is E) {
result.add(node);
return;
}
if (node.children == null) return;
for (DirectParserASTContent child in node.children) {
_recursivelyFindInternal(child, result);
}
}
void debugDumpNodeRecursively({String indent = ""}) {
print("$indent${runtimeType} (${what}) "
"(${deprecatedArguments})");
if (children == null) return;
for (DirectParserASTContent child in children) {
child.debugDumpNodeRecursively(indent: " $indent");
}
}
}
extension MetadataStarExtension on DirectParserASTContentMetadataStarEnd {
List<DirectParserASTContentMetadataEnd> getMetadataEntries() {
List<DirectParserASTContentMetadataEnd> result = [];
for (DirectParserASTContent topLevel in children) {
if (topLevel is! DirectParserASTContentMetadataEnd) continue;
result.add(topLevel);
}
return result;
}
}
extension CompilationUnitExtension on DirectParserASTContentCompilationUnitEnd {
List<DirectParserASTContentTopLevelDeclarationEnd> getClasses() {
List<DirectParserASTContentTopLevelDeclarationEnd> result = [];
for (DirectParserASTContent topLevel in children) {
if (!topLevel.isClass()) continue;
result.add(topLevel);
}
return result;
}
List<DirectParserASTContentTopLevelDeclarationEnd> getMixinDeclarations() {
List<DirectParserASTContentTopLevelDeclarationEnd> result = [];
for (DirectParserASTContent topLevel in children) {
if (!topLevel.isMixinDeclaration()) continue;
result.add(topLevel);
}
return result;
}
List<DirectParserASTContentImportEnd> getImports() {
List<DirectParserASTContentImportEnd> result = [];
for (DirectParserASTContent topLevel in children) {
if (!topLevel.isImport()) continue;
result.add(topLevel.children.last);
}
return result;
}
List<DirectParserASTContentExportEnd> getExports() {
List<DirectParserASTContentExportEnd> result = [];
for (DirectParserASTContent topLevel in children) {
if (!topLevel.isExport()) continue;
result.add(topLevel.children.last);
}
return result;
}
// List<DirectParserASTContentMetadataStarEnd> getMetadata() {
// List<DirectParserASTContentMetadataStarEnd> result = [];
// for (DirectParserASTContent topLevel in children) {
// if (!topLevel.isMetadata()) continue;
// result.add(topLevel);
// }
// return result;
// }
// List<DirectParserASTContentEnumEnd> getEnums() {
// List<DirectParserASTContentEnumEnd> result = [];
// for (DirectParserASTContent topLevel in children) {
// if (!topLevel.isEnum()) continue;
// result.add(topLevel.children.last);
// }
// return result;
// }
// List<DirectParserASTContentFunctionTypeAliasEnd> getTypedefs() {
// List<DirectParserASTContentFunctionTypeAliasEnd> result = [];
// for (DirectParserASTContent topLevel in children) {
// if (!topLevel.isTypedef()) continue;
// result.add(topLevel.children.last);
// }
// return result;
// }
// List<DirectParserASTContentMixinDeclarationEnd> getMixinDeclarations() {
// List<DirectParserASTContentMixinDeclarationEnd> result = [];
// for (DirectParserASTContent topLevel in children) {
// if (!topLevel.isMixinDeclaration()) continue;
// result.add(topLevel.children.last);
// }
// return result;
// }
// List<DirectParserASTContentTopLevelMethodEnd> getTopLevelMethods() {
// List<DirectParserASTContentTopLevelMethodEnd> result = [];
// for (DirectParserASTContent topLevel in children) {
// if (!topLevel.isTopLevelMethod()) continue;
// result.add(topLevel.children.last);
// }
// return result;
// }
DirectParserASTContentCompilationUnitBegin getBegin() {
return children.first;
}
}
extension TopLevelDeclarationExtension
on DirectParserASTContentTopLevelDeclarationEnd {
DirectParserASTContentIdentifierHandle getIdentifier() {
for (DirectParserASTContent child in children) {
if (child is DirectParserASTContentIdentifierHandle) return child;
}
throw "Not found.";
}
DirectParserASTContentClassDeclarationEnd getClassDeclaration() {
if (!isClass()) {
throw "Not a class";
}
for (DirectParserASTContent child in children) {
if (child is DirectParserASTContentClassDeclarationEnd) {
return child;
}
}
throw "Not found.";
}
}
extension MixinDeclarationExtension
on DirectParserASTContentMixinDeclarationEnd {
DirectParserASTContentClassOrMixinBodyEnd getClassOrMixinBody() {
for (DirectParserASTContent child in children) {
if (child is DirectParserASTContentClassOrMixinBodyEnd) return child;
}
throw "Not found.";
}
}
extension ClassDeclarationExtension
on DirectParserASTContentClassDeclarationEnd {
DirectParserASTContentClassOrMixinBodyEnd getClassOrMixinBody() {
for (DirectParserASTContent child in children) {
if (child is DirectParserASTContentClassOrMixinBodyEnd) return child;
}
throw "Not found.";
}
DirectParserASTContentClassExtendsHandle getClassExtends() {
for (DirectParserASTContent child in children) {
if (child is DirectParserASTContentClassExtendsHandle) return child;
}
throw "Not found.";
}
DirectParserASTContentClassOrMixinImplementsHandle getClassImplements() {
for (DirectParserASTContent child in children) {
if (child is DirectParserASTContentClassOrMixinImplementsHandle) {
return child;
}
}
throw "Not found.";
}
DirectParserASTContentClassWithClauseHandle getClassWithClause() {
for (DirectParserASTContent child in children) {
if (child is DirectParserASTContentClassWithClauseHandle) {
return child;
}
}
return null;
}
}
extension ClassOrMixinBodyExtension
on DirectParserASTContentClassOrMixinBodyEnd {
List<DirectParserASTContentMemberEnd> getMembers() {
List<DirectParserASTContentMemberEnd> members = [];
for (DirectParserASTContent child in children) {
if (child is DirectParserASTContentMemberEnd) {
members.add(child);
}
}
return members;
}
}
extension MemberExtension on DirectParserASTContentMemberEnd {
bool isClassConstructor() {
DirectParserASTContent child = children[1];
if (child is DirectParserASTContentClassConstructorEnd) return true;
return false;
}
DirectParserASTContentClassConstructorEnd getClassConstructor() {
DirectParserASTContent child = children[1];
if (child is DirectParserASTContentClassConstructorEnd) return child;
throw "Not found";
}
bool isClassFactoryMethod() {
DirectParserASTContent child = children[1];
if (child is DirectParserASTContentClassFactoryMethodEnd) return true;
return false;
}
DirectParserASTContentClassFactoryMethodEnd getClassFactoryMethod() {
DirectParserASTContent child = children[1];
if (child is DirectParserASTContentClassFactoryMethodEnd) return child;
throw "Not found";
}
bool isClassFields() {
DirectParserASTContent child = children[1];
if (child is DirectParserASTContentClassFieldsEnd) return true;
return false;
}
DirectParserASTContentClassFieldsEnd getClassFields() {
DirectParserASTContent child = children[1];
if (child is DirectParserASTContentClassFieldsEnd) return child;
throw "Not found";
}
bool isMixinFields() {
DirectParserASTContent child = children[1];
if (child is DirectParserASTContentMixinFieldsEnd) return true;
return false;
}
DirectParserASTContentMixinFieldsEnd getMixinFields() {
DirectParserASTContent child = children[1];
if (child is DirectParserASTContentMixinFieldsEnd) return child;
throw "Not found";
}
bool isMixinMethod() {
DirectParserASTContent child = children[1];
if (child is DirectParserASTContentMixinMethodEnd) return true;
return false;
}
DirectParserASTContentMixinMethodEnd getMixinMethod() {
DirectParserASTContent child = children[1];
if (child is DirectParserASTContentMixinMethodEnd) return child;
throw "Not found";
}
bool isMixinFactoryMethod() {
DirectParserASTContent child = children[1];
if (child is DirectParserASTContentMixinFactoryMethodEnd) return true;
return false;
}
DirectParserASTContentMixinFactoryMethodEnd getMixinFactoryMethod() {
DirectParserASTContent child = children[1];
if (child is DirectParserASTContentMixinFactoryMethodEnd) return child;
throw "Not found";
}
bool isMixinConstructor() {
DirectParserASTContent child = children[1];
if (child is DirectParserASTContentMixinConstructorEnd) return true;
return false;
}
DirectParserASTContentMixinConstructorEnd getMixinConstructor() {
DirectParserASTContent child = children[1];
if (child is DirectParserASTContentMixinConstructorEnd) return child;
throw "Not found";
}
bool isClassMethod() {
DirectParserASTContent child = children[1];
if (child is DirectParserASTContentClassMethodEnd) return true;
return false;
}
DirectParserASTContentClassMethodEnd getClassMethod() {
DirectParserASTContent child = children[1];
if (child is DirectParserASTContentClassMethodEnd) return child;
throw "Not found";
}
bool isClassRecoverableError() {
DirectParserASTContent child = children[1];
if (child is DirectParserASTContentRecoverableErrorHandle) return true;
return false;
}
}
extension ClassFieldsExtension on DirectParserASTContentClassFieldsEnd {
List<DirectParserASTContentIdentifierHandle> getFieldIdentifiers() {
// For now blindly assume that the last count identifiers are the names
// of the fields.
int countLeft = count;
List<DirectParserASTContentIdentifierHandle> identifiers =
new List<DirectParserASTContentIdentifierHandle>.filled(count, null);
for (int i = children.length - 1; i >= 0; i--) {
DirectParserASTContent child = children[i];
if (child is DirectParserASTContentIdentifierHandle) {
countLeft--;
identifiers[countLeft] = child;
if (countLeft == 0) break;
}
}
if (countLeft != 0) throw "Didn't find the expected number of identifiers";
return identifiers;
}
DirectParserASTContentTypeHandle getFirstType() {
for (DirectParserASTContent child in children) {
if (child is DirectParserASTContentTypeHandle) return child;
}
return null;
}
DirectParserASTContentFieldInitializerEnd getFieldInitializer() {
for (DirectParserASTContent child in children) {
if (child is DirectParserASTContentFieldInitializerEnd) return child;
}
return null;
}
}
extension ClassMethodExtension on DirectParserASTContentClassMethodEnd {
DirectParserASTContentBlockFunctionBodyEnd getBlockFunctionBody() {
for (DirectParserASTContent child in children) {
if (child is DirectParserASTContentBlockFunctionBodyEnd) {
return child;
}
}
return null;
}
}
extension ClassConstructorExtension
on DirectParserASTContentClassConstructorEnd {
DirectParserASTContentFormalParametersEnd getFormalParameters() {
for (DirectParserASTContent child in children) {
if (child is DirectParserASTContentFormalParametersEnd) {
return child;
}
}
throw "Not found";
}
DirectParserASTContentInitializersEnd getInitializers() {
for (DirectParserASTContent child in children) {
if (child is DirectParserASTContentInitializersEnd) {
return child;
}
}
return null;
}
DirectParserASTContentBlockFunctionBodyEnd getBlockFunctionBody() {
for (DirectParserASTContent child in children) {
if (child is DirectParserASTContentBlockFunctionBodyEnd) {
return child;
}
}
return null;
}
}
extension FormalParametersExtension
on DirectParserASTContentFormalParametersEnd {
List<DirectParserASTContentFormalParameterEnd> getFormalParameters() {
List<DirectParserASTContentFormalParameterEnd> result = [];
for (DirectParserASTContent child in children) {
if (child is DirectParserASTContentFormalParameterEnd) {
result.add(child);
}
}
return result;
}
DirectParserASTContentOptionalFormalParametersEnd
getOptionalFormalParameters() {
for (DirectParserASTContent child in children) {
if (child is DirectParserASTContentOptionalFormalParametersEnd) {
return child;
}
}
return null;
}
}
extension FormalParameterExtension on DirectParserASTContentFormalParameterEnd {
DirectParserASTContentFormalParameterBegin getBegin() {
return children.first;
}
}
extension OptionalFormalParametersExtension
on DirectParserASTContentOptionalFormalParametersEnd {
List<DirectParserASTContentFormalParameterEnd> getFormalParameters() {
List<DirectParserASTContentFormalParameterEnd> result = [];
for (DirectParserASTContent child in children) {
if (child is DirectParserASTContentFormalParameterEnd) {
result.add(child);
}
}
return result;
}
}
extension InitializersExtension on DirectParserASTContentInitializersEnd {
List<DirectParserASTContentInitializerEnd> getInitializers() {
List<DirectParserASTContentInitializerEnd> result = [];
for (DirectParserASTContent child in children) {
if (child is DirectParserASTContentInitializerEnd) {
result.add(child);
}
}
return result;
}
DirectParserASTContentInitializersBegin getBegin() {
return children.first;
}
}
extension InitializerExtension on DirectParserASTContentInitializerEnd {
DirectParserASTContentInitializerBegin getBegin() {
return children.first;
}
}
main(List<String> args) {
File f = new File(args[0]);
Uint8List data = f.readAsBytesSync();
DirectParserASTContent ast = getAST(data);
if (args.length > 1 && args[1] == "--benchmark") {
Stopwatch stopwatch = new Stopwatch()..start();
int numRuns = 100;
for (int i = 0; i < numRuns; i++) {
DirectParserASTContent ast2 = getAST(data);
if (ast.what != ast2.what) {
throw "Not the same result every time";
}
}
stopwatch.stop();
print("First $numRuns took ${stopwatch.elapsedMilliseconds} ms "
"(i.e. ${stopwatch.elapsedMilliseconds / numRuns}ms/iteration)");
stopwatch = new Stopwatch()..start();
numRuns = 2500;
for (int i = 0; i < numRuns; i++) {
DirectParserASTContent ast2 = getAST(data);
if (ast.what != ast2.what) {
throw "Not the same result every time";
}
}
stopwatch.stop();
print("Next $numRuns took ${stopwatch.elapsedMilliseconds} ms "
"(i.e. ${stopwatch.elapsedMilliseconds / numRuns}ms/iteration)");
} else {
print(ast);
}
}
class DirectParserASTListener extends AbstractDirectParserASTListener {
void seen(DirectParserASTContent entry) {
switch (entry.type) {
case DirectParserASTType.BEGIN:
case DirectParserASTType.HANDLE:
// This just adds stuff.
data.add(entry);
break;
case DirectParserASTType.END:
// End should gobble up everything until the corresponding begin (which
// should be the latest begin).
int beginIndex;
for (int i = data.length - 1; i >= 0; i--) {
if (data[i].type == DirectParserASTType.BEGIN) {
beginIndex = i;
break;
}
}
if (beginIndex == null) {
throw "Couldn't find a begin for ${entry.what}. Has:\n"
"${data.map((e) => "${e.what}: ${e.type}").join("\n")}";
}
String begin = data[beginIndex].what;
String end = entry.what;
if (begin == end) {
// Exact match.
} else if (end == "TopLevelDeclaration" &&
(begin == "ExtensionDeclarationPrelude" ||
begin == "ClassOrNamedMixinApplicationPrelude" ||
begin == "TopLevelMember" ||
begin == "UncategorizedTopLevelDeclaration")) {
// endTopLevelDeclaration is started by one of
// beginExtensionDeclarationPrelude,
// beginClassOrNamedMixinApplicationPrelude
// beginTopLevelMember or beginUncategorizedTopLevelDeclaration.
} else if (begin == "Method" &&
(end == "ClassConstructor" ||
end == "ClassMethod" ||
end == "ExtensionConstructor" ||
end == "ExtensionMethod" ||
end == "MixinConstructor" ||
end == "MixinMethod")) {
// beginMethod is ended by one of endClassConstructor, endClassMethod,
// endExtensionMethod, endMixinConstructor or endMixinMethod.
} else if (begin == "Fields" &&
(end == "TopLevelFields" ||
end == "ClassFields" ||
end == "MixinFields" ||
end == "ExtensionFields")) {
// beginFields is ended by one of endTopLevelFields, endMixinFields or
// endExtensionFields.
} else if (begin == "ForStatement" && end == "ForIn") {
// beginForStatement is ended by either endForStatement or endForIn.
} else if (begin == "FactoryMethod" &&
(end == "ClassFactoryMethod" ||
end == "MixinFactoryMethod" ||
end == "ExtensionFactoryMethod")) {
// beginFactoryMethod is ended by either endClassFactoryMethod,
// endMixinFactoryMethod or endExtensionFactoryMethod.
} else if (begin == "ForControlFlow" && (end == "ForInControlFlow")) {
// beginForControlFlow is ended by either endForControlFlow or
// endForInControlFlow.
} else if (begin == "IfControlFlow" && (end == "IfElseControlFlow")) {
// beginIfControlFlow is ended by either endIfControlFlow or
// endIfElseControlFlow.
} else if (begin == "AwaitExpression" &&
(end == "InvalidAwaitExpression")) {
// beginAwaitExpression is ended by either endAwaitExpression or
// endInvalidAwaitExpression.
} else if (begin == "YieldStatement" &&
(end == "InvalidYieldStatement")) {
// beginYieldStatement is ended by either endYieldStatement or
// endInvalidYieldStatement.
} else {
throw "Unknown combination: begin$begin and end$end";
}
List<DirectParserASTContent> children = data.sublist(beginIndex);
data.length = beginIndex;
data.add(entry..children = children);
break;
}
}
@override
void reportVarianceModifierNotEnabled(Token variance) {
throw new UnimplementedError();
}
@override
Uri get uri => throw new UnimplementedError();
@override
void logEvent(String name) {
throw new UnimplementedError();
}
}