Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(494)

Unified Diff: sdk/lib/_internal/compiler/implementation/patch_parser.dart

Issue 694353007: Move dart2js from sdk/lib/_internal/compiler to pkg/compiler (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: sdk/lib/_internal/compiler/implementation/patch_parser.dart
diff --git a/sdk/lib/_internal/compiler/implementation/patch_parser.dart b/sdk/lib/_internal/compiler/implementation/patch_parser.dart
deleted file mode 100644
index 0899be3419411bc66fd745de6ce41499c0ae0651..0000000000000000000000000000000000000000
--- a/sdk/lib/_internal/compiler/implementation/patch_parser.dart
+++ /dev/null
@@ -1,513 +0,0 @@
-// Copyright (c) 2012, 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.
-
-/**
- * This library contains the infrastructure to parse and integrate patch files.
- *
- * Three types of elements can be patched: [LibraryElement], [ClassElement],
- * [FunctionElement]. Patches are introduced in patch libraries which are loaded
- * together with the corresponding origin library. Which libraries that are
- * patched is determined by the dart2jsPatchPath field of LibraryInfo found
- * in [:lib/_internal/libraries.dart:].
- *
- * Patch libraries are parsed like regular library and thus provided with their
- * own elements. These elements which are distinct from the elements from the
- * patched library and the relation between patched and patch elements is
- * established through the [:patch:] and [:origin:] fields found on
- * [LibraryElement], [ClassElement] and [FunctionElement]. The [:patch:] fields
- * are set on the patched elements to point to their corresponding patch
- * element, and the [:origin:] elements are set on the patch elements to point
- * their corresponding patched elements.
- *
- * The fields [Element.isPatched] and [Element.isPatch] can be used to determine
- * whether the [:patch:] or [:origin:] field, respectively, has been set on an
- * element, regardless of whether the element is one of the three patchable
- * element types or not.
- *
- * ## Variants of classes and functions ##
- *
- * With patches there are four variants of classes and function:
- *
- * Regular: A class or function which is not declared in a patch library and
- * which has no corresponding patch.
- * Origin: A class or function which is not declared in a patch library and
- * which has a corresponding patch. Origin functions must use the [:external:]
- * modifier and can have no body. Origin classes and functions are also
- * called 'patched'.
- * Patch: A class or function which is declared in a patch library and which
- * has a corresponding origin. Both patch classes and patch functions must use
- * the [:patch:] modifier.
- * Injected: A class or function (or even field) which is declared in a
- * patch library and which has no corresponding origin. An injected element
- * cannot use the [:patch:] modifier. Injected elements are never visible from
- * outside the patch library in which they have been declared. For this
- * reason, injected elements are often declared private and therefore called
- * also called 'patch private'.
- *
- * Examples of the variants is shown in the code below:
- *
- * // In the origin library:
- * class RegularClass { // A regular class.
- * void regularMethod() {} // A regular method.
- * }
- * class PatchedClass { // An origin class.
- * int regularField; // A regular field.
- * void regularMethod() {} // A regular method.
- * external void patchedMethod(); // An origin method.
- * }
- *
- * // In the patch library:
- * class _InjectedClass { // An injected class.
- * void _injectedMethod() {} // An injected method.
- * }
- * @patch class PatchedClass { // A patch class.
- * int _injectedField; { // An injected field.
- * @patch void patchedMethod() {} // A patch method.
- * }
- *
- *
- * ## Declaration and implementation ##
- *
- * With patches we have two views on elements: as the 'declaration' which
- * introduces the entity and defines its interface, and as the 'implementation'
- * which defines the actual implementation of the entity.
- *
- * Every element has a 'declaration' and an 'implementation' element. For
- * regular and injected elements these are the same. For origin elements the
- * declaration is the element itself and the implementation is the patch element
- * found through its [:patch:] field. For patch elements the implementation is
- * the element itself and the declaration is the origin element found through
- * its [:origin:] field. The declaration and implementation of any element is
- * conveniently available through the [Element.declaration] and
- * [Element.implementation] getters.
- *
- * Most patch-related invariants enforced through-out the compiler are defined
- * in terms of 'declaration' and 'implementation', and tested through the
- * predicate getters [Element.isDeclaration] and [Element.isImplementation].
- * Patch invariants are stated both in comments and as assertions.
- *
- *
- * ## General invariant guidelines ##
- *
- * For [LibraryElement] we always use declarations. This means the
- * [Element.getLibrary] method will only return library declarations. Patch
- * library implementations are only accessed through calls to
- * [Element.getImplementationLibrary] which is used to setup the correct
- * [Element.enclosingElement] relation between patch/injected elements and the
- * patch library.
- *
- * For [ClassElement] and [FunctionElement] we use declarations for determining
- * identity and implementations for work based on the AST nodes, such as
- * resolution, type-checking, type inference, building SSA graphs, etc.
- * - Worklist only contain declaration elements.
- * - Most maps and sets use declarations exclusively, and their individual
- * invariants are stated in the field comments.
- * - [tree.TreeElements] only map to patch elements from inside a patch library.
- * TODO(johnniwinther): Simplify this invariant to use only declarations in
- * [tree.TreeElements].
- * - Builders shift between declaration and implementation depending on usages.
- * - Compile-time constants use constructor implementation exclusively.
- * - Work on function parameters is performed on the declaration of the function
- * element.
- */
-
-library patchparser;
-
-import 'dart:async';
-
-import 'constants/values.dart' show ConstantValue;
-import 'dart2jslib.dart'
- show Compiler,
- CompilerTask,
- DiagnosticListener,
- MessageKind,
- Script;
-import 'elements/elements.dart';
-import 'elements/modelx.dart'
- show LibraryElementX,
- MetadataAnnotationX,
- ClassElementX,
- FunctionElementX;
-import 'helpers/helpers.dart'; // Included for debug helpers.
-import 'library_loader.dart' show LibraryLoader;
-import 'scanner/scannerlib.dart'; // Scanner, Parsers, Listeners
-import 'util/util.dart';
-
-class PatchParserTask extends CompilerTask {
- PatchParserTask(Compiler compiler): super(compiler);
- final String name = "Patching Parser";
-
- /**
- * Scans a library patch file, applies the method patches and
- * injections to the library, and returns a list of class
- * patches.
- */
- Future patchLibrary(LibraryLoader loader,
- Uri patchUri, LibraryElement originLibrary) {
- return compiler.readScript(originLibrary, patchUri)
- .then((Script script) {
- var patchLibrary = new LibraryElementX(script, null, originLibrary);
- return compiler.withCurrentElement(patchLibrary, () {
- loader.registerNewLibrary(patchLibrary);
- compiler.withCurrentElement(patchLibrary.entryCompilationUnit, () {
- // This patches the elements of the patch library into [library].
- // Injected elements are added directly under the compilation unit.
- // Patch elements are stored on the patched functions or classes.
- scanLibraryElements(patchLibrary.entryCompilationUnit);
- });
- return loader.processLibraryTags(patchLibrary);
- });
- });
- }
-
- void scanLibraryElements(CompilationUnitElement compilationUnit) {
- measure(() {
- // TODO(johnniwinther): Test that parts and exports are handled correctly.
- Script script = compilationUnit.script;
- Token tokens = new Scanner(script.file).tokenize();
- Function idGenerator = compiler.getNextFreeClassId;
- Listener patchListener = new PatchElementListener(compiler,
- compilationUnit,
- idGenerator);
- new PartialParser(patchListener).parseUnit(tokens);
- });
- }
-
- void parsePatchClassNode(PartialClassElement element) {
- // Parse [PartialClassElement] using a "patch"-aware parser instead
- // of calling its [parseNode] method.
- if (element.cachedNode != null) return;
-
- measure(() => compiler.withCurrentElement(element, () {
- MemberListener listener = new MemberListener(compiler, element);
- Parser parser = new PatchClassElementParser(listener);
- Token token = parser.parseTopLevelDeclaration(element.beginToken);
- assert(identical(token, element.endToken.next));
- element.cachedNode = listener.popNode();
- assert(listener.nodes.isEmpty);
-
- Link<Element> patches = element.localMembers;
- applyContainerPatch(element.origin, patches);
- }));
- }
-
- void applyContainerPatch(ClassElement originClass,
- Link<Element> patches) {
- for (Element patch in patches) {
- if (!isPatchElement(compiler, patch)) continue;
-
- Element origin = originClass.localLookup(patch.name);
- patchElement(compiler, origin, patch);
- }
- }
-}
-
-/**
- * Partial parser for patch files that also handles the members of class
- * declarations.
- */
-class PatchClassElementParser extends PartialParser {
- PatchClassElementParser(Listener listener) : super(listener);
-
- Token parseClassBody(Token token) => fullParseClassBody(token);
-}
-
-/**
- * Extension of [ElementListener] for parsing patch files.
- */
-class PatchElementListener extends ElementListener implements Listener {
- final Compiler compiler;
-
- PatchElementListener(Compiler compiler,
- CompilationUnitElement patchElement,
- int idGenerator())
- : this.compiler = compiler,
- super(compiler, patchElement, idGenerator);
-
- void pushElement(Element patch) {
- super.pushElement(patch);
- if (isPatchElement(compiler, patch)) {
- LibraryElement originLibrary = compilationUnitElement.library;
- assert(originLibrary.isPatched);
- Element origin = originLibrary.localLookup(patch.name);
- patchElement(listener, origin, patch);
- }
- }
-}
-
-void patchElement(Compiler compiler,
- Element origin,
- Element patch) {
- if (origin == null) {
- compiler.reportError(
- patch, MessageKind.PATCH_NON_EXISTING, {'name': patch.name});
- return;
- }
- if (!(origin.isClass ||
- origin.isConstructor ||
- origin.isFunction ||
- origin.isAbstractField)) {
- // TODO(ahe): Remove this error when the parser rejects all bad modifiers.
- compiler.reportError(origin, MessageKind.PATCH_NONPATCHABLE);
- return;
- }
- if (patch.isClass) {
- tryPatchClass(compiler, origin, patch);
- } else if (patch.isGetter) {
- tryPatchGetter(compiler, origin, patch);
- } else if (patch.isSetter) {
- tryPatchSetter(compiler, origin, patch);
- } else if (patch.isConstructor) {
- tryPatchConstructor(compiler, origin, patch);
- } else if(patch.isFunction) {
- tryPatchFunction(compiler, origin, patch);
- } else {
- // TODO(ahe): Remove this error when the parser rejects all bad modifiers.
- compiler.reportError(patch, MessageKind.PATCH_NONPATCHABLE);
- }
-}
-
-void tryPatchClass(Compiler compiler,
- Element origin,
- ClassElement patch) {
- if (!origin.isClass) {
- compiler.reportError(
- origin, MessageKind.PATCH_NON_CLASS, {'className': patch.name});
- compiler.reportInfo(
- patch, MessageKind.PATCH_POINT_TO_CLASS, {'className': patch.name});
- return;
- }
- patchClass(compiler, origin, patch);
-}
-
-void patchClass(Compiler compiler,
- ClassElementX origin,
- ClassElementX patch) {
- if (origin.isPatched) {
- compiler.internalError(origin,
- "Patching the same class more than once.");
- }
- origin.applyPatch(patch);
- checkNativeAnnotation(compiler, patch);
-}
-
-/// Check whether [cls] has a `@Native(...)` annotation, and if so, set its
-/// native name from the annotation.
-checkNativeAnnotation(Compiler compiler, ClassElement cls) {
- EagerAnnotationHandler.checkAnnotation(compiler, cls,
- const NativeAnnotationHandler());
-}
-
-/// Abstract interface for pre-resolution detection of metadata.
-///
-/// The detection is handled in two steps:
-/// - match the annotation syntactically and assume that the annotation is valid
-/// if it looks correct,
-/// - setup a deferred action to check that the annotation has a valid constant
-/// value and report an internal error if not.
-abstract class EagerAnnotationHandler {
- /// Checks that [annotation] looks like a matching annotation and optionally
- /// applies actions on [element]. Returns `true` if the annotation matched.
- bool apply(Compiler compiler,
- Element element,
- MetadataAnnotation annotation);
-
- /// Checks that the annotation value is valid.
- void validate(Compiler compiler,
- Element element,
- MetadataAnnotation annotation,
- ConstantValue constant);
-
-
- /// Checks [element] for metadata matching the [handler]. Return `true` if
- /// matching metadata was found.
- static bool checkAnnotation(Compiler compiler,
- Element element,
- EagerAnnotationHandler handler) {
- for (Link<MetadataAnnotation> link = element.metadata;
- !link.isEmpty;
- link = link.tail) {
- MetadataAnnotation annotation = link.head;
- if (handler.apply(compiler, element, annotation)) {
- // TODO(johnniwinther): Perform this check in
- // [Compiler.onLibrariesLoaded].
- compiler.enqueuer.resolution.addDeferredAction(element, () {
- annotation.ensureResolved(compiler);
- handler.validate(
- compiler, element, annotation, annotation.constant.value);
- });
- return true;
- }
- }
- return false;
- }
-}
-
-/// Annotation handler for pre-resolution detection of `@Native(...)`
-/// annotations.
-class NativeAnnotationHandler implements EagerAnnotationHandler {
- const NativeAnnotationHandler();
-
- String getNativeAnnotation(MetadataAnnotation annotation) {
- if (annotation.beginToken != null &&
- annotation.beginToken.next.value == 'Native') {
- // Skipping '@', 'Native', and '('.
- Token argument = annotation.beginToken.next.next.next;
- if (argument is StringToken) {
- return argument.value;
- }
- }
- return null;
- }
-
- bool apply(Compiler compiler,
- Element element,
- MetadataAnnotation annotation) {
- if (element.isClass) {
- String native = getNativeAnnotation(annotation);
- if (native != null) {
- ClassElementX declaration = element.declaration;
- declaration.setNative(native);
- return true;
- }
- }
- return false;
- }
-
- void validate(Compiler compiler,
- Element element,
- MetadataAnnotation annotation,
- ConstantValue constant) {
- if (constant.computeType(compiler).element !=
- compiler.nativeAnnotationClass) {
- compiler.internalError(annotation, 'Invalid @Native(...) annotation.');
- }
- }
-}
-
-/// Annotation handler for pre-resolution detection of `@patch` annotations.
-class PatchAnnotationHandler implements EagerAnnotationHandler {
- const PatchAnnotationHandler();
-
- bool isPatchAnnotation(MetadataAnnotation annotation) {
- return annotation.beginToken != null &&
- annotation.beginToken.next.value == 'patch';
- }
-
- bool apply(Compiler compiler,
- Element element,
- MetadataAnnotation annotation) {
- return isPatchAnnotation(annotation);
- }
-
- void validate(Compiler compiler,
- Element element,
- MetadataAnnotation annotation,
- ConstantValue constant) {
- if (constant != compiler.patchConstant) {
- compiler.internalError(annotation, 'Invalid patch annotation.');
- }
- }
-}
-
-
-void tryPatchGetter(DiagnosticListener listener,
- Element origin,
- FunctionElement patch) {
- if (!origin.isAbstractField) {
- listener.reportError(
- origin, MessageKind.PATCH_NON_GETTER, {'name': origin.name});
- listener.reportInfo(
- patch,
- MessageKind.PATCH_POINT_TO_GETTER, {'getterName': patch.name});
- return;
- }
- AbstractFieldElement originField = origin;
- if (originField.getter == null) {
- listener.reportError(
- origin, MessageKind.PATCH_NO_GETTER, {'getterName': patch.name});
- listener.reportInfo(
- patch,
- MessageKind.PATCH_POINT_TO_GETTER, {'getterName': patch.name});
- return;
- }
- patchFunction(listener, originField.getter, patch);
-}
-
-void tryPatchSetter(DiagnosticListener listener,
- Element origin,
- FunctionElement patch) {
- if (!origin.isAbstractField) {
- listener.reportError(
- origin, MessageKind.PATCH_NON_SETTER, {'name': origin.name});
- listener.reportInfo(
- patch,
- MessageKind.PATCH_POINT_TO_SETTER, {'setterName': patch.name});
- return;
- }
- AbstractFieldElement originField = origin;
- if (originField.setter == null) {
- listener.reportError(
- origin, MessageKind.PATCH_NO_SETTER, {'setterName': patch.name});
- listener.reportInfo(
- patch,
- MessageKind.PATCH_POINT_TO_SETTER, {'setterName': patch.name});
- return;
- }
- patchFunction(listener, originField.setter, patch);
-}
-
-void tryPatchConstructor(DiagnosticListener listener,
- Element origin,
- FunctionElement patch) {
- if (!origin.isConstructor) {
- listener.reportError(
- origin,
- MessageKind.PATCH_NON_CONSTRUCTOR, {'constructorName': patch.name});
- listener.reportInfo(
- patch,
- MessageKind.PATCH_POINT_TO_CONSTRUCTOR,
- {'constructorName': patch.name});
- return;
- }
- patchFunction(listener, origin, patch);
-}
-
-void tryPatchFunction(DiagnosticListener listener,
- Element origin,
- FunctionElement patch) {
- if (!origin.isFunction) {
- listener.reportError(
- origin,
- MessageKind.PATCH_NON_FUNCTION, {'functionName': patch.name});
- listener.reportInfo(
- patch,
- MessageKind.PATCH_POINT_TO_FUNCTION, {'functionName': patch.name});
- return;
- }
- patchFunction(listener, origin, patch);
-}
-
-void patchFunction(DiagnosticListener listener,
- FunctionElementX origin,
- FunctionElementX patch) {
- if (!origin.modifiers.isExternal) {
- listener.reportError(origin, MessageKind.PATCH_NON_EXTERNAL);
- listener.reportInfo(
- patch,
- MessageKind.PATCH_POINT_TO_FUNCTION, {'functionName': patch.name});
- return;
- }
- if (origin.isPatched) {
- listener.internalError(origin,
- "Trying to patch a function more than once.");
- }
- origin.applyPatch(patch);
-}
-
-// TODO(johnniwinther): Add unittest when patch is (real) metadata.
-bool isPatchElement(Compiler compiler, Element element) {
- return EagerAnnotationHandler.checkAnnotation(compiler, element,
- const PatchAnnotationHandler());
-}

Powered by Google App Engine
This is Rietveld 408576698