blob: 1ba67d402b08a7f784d0fae80a380b65bf6b23fb [file] [log] [blame]
// Copyright (c) 2016, 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.md file.
library rasta.custom_patch_parser;
import 'dart:async' show
Future;
import 'package:compiler/src/patch_parser.dart' show
PatchParserTask;
import 'package:compiler/src/common/tasks.dart' show
CompilerTask;
import 'package:compiler/src/library_loader.dart' show
LibraryLoader;
import 'package:compiler/src/elements/elements.dart' show
CompilationUnitElement,
LibraryElement;
import 'package:compiler/src/parser/partial_elements.dart' show
PartialClassElement;
import 'package:compiler/src/elements/modelx.dart' show
LibraryElementX;
import 'package:compiler/src/script.dart' show
Script;
import 'package:compiler/src/tokens/token.dart' show
Token;
import 'package:compiler/src/parser/listener.dart' show
ParserError;
import 'package:compiler/src/patch_parser.dart' show
PartialPatchParser,
PatchClassElementParser,
PatchElementListener,
PatchMemberListener;
import 'package:compiler/src/tree/nodes.dart' show
LibraryTag;
import 'custom_compiler.dart' show
CustomCompiler;
import 'package:compiler/src/options.dart' show
ParserOptions;
class CustomPatchParserTask extends CompilerTask implements PatchParserTask {
CustomPatchParserTask(CustomCompiler compiler)
: super(compiler);
@override String get name => "Custom patch parser";
@override ParserOptions get parserOptions => compiler.parsing.parserOptions;
@override Future patchLibrary(
LibraryLoader loader, Uri patchUri, LibraryElement originLibrary) {
throw "unsupported";
}
@override void scanLibraryElements(CompilationUnitElement compilationUnit) {
throw "unsupported";
}
@override void parsePatchClassNode(PartialClassElement cls) {
// Parse [PartialClassElement] using a "patch"-aware parser instead
// of calling its [parseNode] method.
if (cls.cachedNode != null) return;
measureElement(cls, () {
PatchMemberListener listener = new PatchMemberListener(compiler, cls);
PatchClassElementParser parser =
new PatchClassElementParser(listener, parserOptions);
try {
Token token = parser.parseTopLevelDeclaration(cls.beginToken);
assert(identical(token, cls.endToken.next));
} on ParserError catch (e) {
// No need to recover from a parser error in platform libraries, user
// will never see this if the libraries are tested correctly.
reporter.internalError(cls, "Parser error in patch file: $e");
}
cls.cachedNode = listener.popNode();
assert(listener.nodes.isEmpty);
});
}
Future<Null> onLibraryScanned(LibraryElement library,
LibraryLoader loader) async {
Uri uri = library.canonicalUri;
CustomCompiler compiler = this.compiler;
Uri patch = compiler.target.patches[uri];
if (patch != null) {
await loadPatchLibrary(patch, library, loader);
}
if (library.isPlatformLibrary && uri.path == "_patch") {
compiler.patchAnnotationClass = library.localLookup("Patch");
}
}
Future<LibraryElementX> loadPatchLibrary(
Uri patchUri,
LibraryElement originLibrary,
LibraryLoader loader) async {
Script script = await compiler.readScript(patchUri, originLibrary);
LibraryElementX patchLibrary = new LibraryElementX(script, null);
{
// TODO(ahe): This circumvents an invariant in PatchMixin.applyPatch. How
// to correctly do this?
(originLibrary as dynamic).patch = patchLibrary;
patchLibrary.origin = originLibrary;
}
loader.registerNewLibrary(patchLibrary);
scanUnit(patchLibrary.compilationUnit, isPart: false);
await loader.processLibraryTags(patchLibrary, isPatchLibrary: true);
return patchLibrary;
}
void scanUnit(CompilationUnitElement unit, {bool isPart: true}) {
Token tokens = compiler.scanner.tokenizeUnit(unit);
return measureElement(unit, () {
PatchElementListener patchListener = isPart
? new PatchPartListener(compiler, unit)
: new PatchElementListener(compiler, unit, compiler);
try {
new PartialPatchParser(patchListener, compiler.options)
.parseUnit(tokens);
} on ParserError catch (e) {
// No need to recover from a parser error in platform libraries, user
// will never see this if the libraries are tested correctly.
compiler.reporter.internalError(unit, "Parser error in patch file: $e");
}
});
}
}
class PatchPartListener extends PatchElementListener {
PatchPartListener(CustomCompiler compiler, CompilationUnitElement unit)
: super(compiler, unit, compiler);
void addLibraryTag(LibraryTag tag) {
// TODO(ahe): Check that a similar tag is already included in unit.library.
}
}