Chromium Code Reviews| Index: lib/compiler/implementation/compiler.dart |
| diff --git a/lib/compiler/implementation/compiler.dart b/lib/compiler/implementation/compiler.dart |
| index 4c078eb2884bb28109d19d276b27e8ea7ca8d82b..94560faea0d8c1a89e862e53551b4225fad0b5dd 100644 |
| --- a/lib/compiler/implementation/compiler.dart |
| +++ b/lib/compiler/implementation/compiler.dart |
| @@ -521,11 +521,39 @@ class Compiler implements DiagnosticListener { |
| void applyLibraryPatch(LibraryElement original, LibraryElement patch) { |
| Link<Element> patches = patch.topLevelElements; |
| + applyContainerPatch(original, patches, original.findLocal); |
| - // Copy/patch top-level elements. |
| + // Copy imports from patch to original library. |
| + Map<String, LibraryElement> delayedPatches = <LibraryElement>{}; |
| + Uri patchBase = patch.script.uri; |
| + for (ScriptTag tag in patch.tags.reverse()) { |
| + if (tag.isImport()) { |
| + StringNode argument = tag.argument; |
| + Uri resolved = patchBase.resolve(argument.dartString.slowToString()); |
| + LibraryElement importedLibrary = |
| + scanner.loadLibrary(resolved, argument); |
| + scanner.importLibrary(original, importedLibrary, tag, patch); |
| + if (resolved.scheme == "dart") { |
| + delayedPatches[resolved.path] = importedLibrary; |
| + } |
| + } |
| + } |
| + |
| + // Mark library as already patched. |
| + original.patch = patch; |
| + |
| + // We patch imported libraries after marking the current library as |
| + // patched, to avoid problems with cyclic dependencies. |
| + delayedPatches.forEach((String path, LibraryElement importedLibrary) { |
| + patchDartLibrary(importedLibrary, path); |
| + }); |
| + } |
| + |
| + void applyContainerPatch(ContainerElement original, Link<Element> patches, |
| + Element lookup(SourceString name)) { |
| while (!patches.isEmpty()) { |
| Element patchElement = patches.head; |
| - Element originalElement = original.elements[patchElement.name]; |
| + Element originalElement = lookup(patchElement.name); |
| // Getters and setters are kept inside a synthetic field. |
| if (patchElement.kind === ElementKind.ABSTRACT_FIELD) { |
| if (originalElement !== null && |
| @@ -550,37 +578,17 @@ class Compiler implements DiagnosticListener { |
| } |
| } |
| } else if (originalElement === null) { |
| + if (isPatchElement(patchElement)) { |
| + /// WHAT IS WRONG HERE? Why isn't _RANDOM in the library? |
|
floitsch
2012/07/10 17:53:45
remove?
Lasse Reichstein Nielsen
2012/07/11 07:45:22
Absolutely. Just a comment to myself, so I could r
|
| + internalError("Cannot patch non-existing member '" |
| + "${patchElement.name.slowToString()}'."); |
| + } |
| original.addMember(clonePatch(patchElement)); |
| } else { |
| patchMember(originalElement, patchElement); |
| } |
| patches = patches.tail; |
| } |
| - |
| - // Copy imports. |
| - Map<String, LibraryElement> delayedPatches = <LibraryElement>{}; |
| - Uri patchBase = patch.script.uri; |
| - for (ScriptTag tag in patch.tags.reverse()) { |
| - if (tag.isImport()) { |
| - StringNode argument = tag.argument; |
| - Uri resolved = patchBase.resolve(argument.dartString.slowToString()); |
| - LibraryElement importedLibrary = |
| - scanner.loadLibrary(resolved, argument); |
| - scanner.importLibrary(original, importedLibrary, tag, patch); |
| - if (resolved.scheme == "dart") { |
| - delayedPatches[resolved.path] = importedLibrary; |
| - } |
| - } |
| - } |
| - |
| - // Mark library as already patched. |
| - original.patch = patch; |
| - |
| - // We patch imported libraries after marking the current library as |
| - // patched, to avoid problems with cyclic dependencies. |
| - delayedPatches.forEach((String path, LibraryElement importedLibrary) { |
| - patchDartLibrary(importedLibrary, path); |
| - }); |
| } |
| bool isPatchElement(Element element) { |
| @@ -594,22 +602,16 @@ class Compiler implements DiagnosticListener { |
| // as the patch library element. |
| // In this case, the patch library element must not be marked as "patch", |
| // and its name must make it private. |
| - if (isPatchElement(patchElement)) { |
| - internalError("Cannot patch non-existing member '" |
| - "${patchElement.name.slowToString()}'."); |
| - |
| - } |
| if (!patchElement.name.isPrivate()) { |
| internalError("Cannot add non-private member '" |
| "${patchElement.name.slowToString()}' from patch."); |
| } |
| - // TODO(lrn): Create a copy of patchElement that isn't added to anything, |
| - // but which takes its source from patchElement. |
| + // TODO(lrn): Create a copy of patchElement that isn't added to any |
| + // object/library yet, but which takes its source from patchElement. |
| throw "Adding members from patch is unsupported"; |
| } |
| - void patchMember(Element originalElement, |
| - Element patchElement) { |
| + void patchMember(Element originalElement, Element patchElement) { |
| // The original library has an element with the same name as the patch |
| // library element. |
| // In this case, the patch library element must be a function marked as |
| @@ -618,18 +620,30 @@ class Compiler implements DiagnosticListener { |
| internalError("Cannot overwrite existing '" |
| "${originalElement.name.slowToString()}' with non-patch."); |
| } |
| + if (originalElement is PartialClassElement) { |
| + // Only happens when patching a library. Dart does not, yet, have nested |
| + // classes. |
| + if (patchElement is! PartialClassElement) { |
| + internalError("Trying to patch class with non-class", |
| + element:originalElement); |
| + } |
| + applyClassPatch(originalElement, patchElement); |
| + return; |
| + } |
| if (originalElement is! FunctionElement) { |
| // TODO(lrn): Handle class declarations too. |
| internalError("Can only patch functions", element: originalElement); |
| } |
| - // TODO(lrn): Abort if the original isn't marked external, when |
| - // that is added to the language. |
| + FunctionElement original = originalElement; |
| + if (!original.modifiers.isExternal()) { |
| + internalError("Can only patch external functions.", element: original); |
| + } |
| if (patchElement is! FunctionElement || |
| - !patchSignatureMatches(originalElement, patchElement)) { |
| + !patchSignatureMatches(original, patchElement)) { |
| internalError("Can only patch functions with matching signatures", |
| - element: originalElement); |
| + element: original); |
| } |
| - applyFunctionPatch(originalElement, patchElement); |
| + applyFunctionPatch(original, patchElement); |
| } |
| bool patchSignatureMatches(FunctionElement original, FunctionElement patch) { |
| @@ -640,7 +654,6 @@ class Compiler implements DiagnosticListener { |
| void applyFunctionPatch(FunctionElement element, |
| FunctionElement patchElement) { |
| - // Don't just assign the patch field. This also updates the cachedNode. |
| if (element.isPatched) { |
| internalError("Trying to patch a function more than once.", |
| element: element); |
| @@ -649,9 +662,27 @@ class Compiler implements DiagnosticListener { |
| internalError("Trying to patch an already compiled function.", |
| element: element); |
| } |
| + // Don't just assign the patch field. This also updates the cachedNode. |
| element.setPatch(patchElement); |
| } |
| + void applyClassPatch(PartialClassElement original, |
| + PartialClassElement patch) { |
| + // Eagerly parse the class so we can patch it. |
| + // TODO(lrn): Perhaps find a way to delay parsing until the class is needed, |
| + // i.e., until [parseNode] is called on [original]. |
|
floitsch
2012/07/10 17:53:45
Does parsing a class go into the methods? If not,
Lasse Reichstein Nielsen
2012/07/11 07:45:22
It doesn't.
We first diet-parse the structure of
|
| + ClassNode node = original.parseNode(this); |
| + // Parse patch class with "patch" parser. |
| + ClassNode patchNode = patchParser.parsePatchClassNode(patch); |
| + Link<Element> patches = patch.members; |
| + Element lookupMemberOrConstructor(SourceString name) { |
| + Element result = original.lookupLocalMember(name); |
| + if (result !== null) return result; |
| + return original.lookupConstructor(name); |
| + } |
| + applyContainerPatch(original, patches, lookupMemberOrConstructor); |
| + } |
| + |
| /** |
| * Get an [Uri] pointing to a patch for the dart: library with |
| * the given path. Returns null if there is no patch. |