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

Side by Side Diff: lib/compiler/implementation/compiler.dart

Issue 10696147: Patch methods in classes. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Small type/typo fixes Created 8 years, 5 months 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « corelib/unified/math/random.dart ('k') | lib/compiler/implementation/elements/elements.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 5
6 /** 6 /**
7 * If true, print a warning for each method that was resolved, but not 7 * If true, print a warning for each method that was resolved, but not
8 * compiled. 8 * compiled.
9 */ 9 */
10 final bool REPORT_EXCESS_RESOLUTION = false; 10 final bool REPORT_EXCESS_RESOLUTION = false;
(...skipping 503 matching lines...) Expand 10 before | Expand all | Expand 10 after
514 LibraryElement patchLibrary = 514 LibraryElement patchLibrary =
515 patchParser.loadPatchLibrary(patchUri); 515 patchParser.loadPatchLibrary(patchUri);
516 // We allow foreign functions in patched libraries. 516 // We allow foreign functions in patched libraries.
517 addForeignFunctions(library); // Is safe even if already added. 517 addForeignFunctions(library); // Is safe even if already added.
518 applyLibraryPatch(library, patchLibrary); 518 applyLibraryPatch(library, patchLibrary);
519 } 519 }
520 } 520 }
521 521
522 void applyLibraryPatch(LibraryElement original, LibraryElement patch) { 522 void applyLibraryPatch(LibraryElement original, LibraryElement patch) {
523 Link<Element> patches = patch.topLevelElements; 523 Link<Element> patches = patch.topLevelElements;
524 applyContainerPatch(original, patches, original.findLocal);
524 525
525 // Copy/patch top-level elements. 526 // Copy imports from patch to original library.
527 Map<String, LibraryElement> delayedPatches = <LibraryElement>{};
528 Uri patchBase = patch.script.uri;
529 for (ScriptTag tag in patch.tags.reverse()) {
530 if (tag.isImport()) {
531 StringNode argument = tag.argument;
532 Uri resolved = patchBase.resolve(argument.dartString.slowToString());
533 LibraryElement importedLibrary =
534 scanner.loadLibrary(resolved, argument);
535 scanner.importLibrary(original, importedLibrary, tag, patch);
536 if (resolved.scheme == "dart") {
537 delayedPatches[resolved.path] = importedLibrary;
538 }
539 }
540 }
541
542 // Mark library as already patched.
543 original.patch = patch;
544
545 // We patch imported libraries after marking the current library as
546 // patched, to avoid problems with cyclic dependencies.
547 delayedPatches.forEach((String path, LibraryElement importedLibrary) {
548 patchDartLibrary(importedLibrary, path);
549 });
550 }
551
552 void applyContainerPatch(ContainerElement original, Link<Element> patches,
553 Element lookup(SourceString name)) {
526 while (!patches.isEmpty()) { 554 while (!patches.isEmpty()) {
527 Element patchElement = patches.head; 555 Element patchElement = patches.head;
528 Element originalElement = original.elements[patchElement.name]; 556 Element originalElement = lookup(patchElement.name);
529 // Getters and setters are kept inside a synthetic field. 557 // Getters and setters are kept inside a synthetic field.
530 if (patchElement.kind === ElementKind.ABSTRACT_FIELD) { 558 if (patchElement.kind === ElementKind.ABSTRACT_FIELD) {
531 if (originalElement !== null && 559 if (originalElement !== null &&
532 originalElement.kind !== ElementKind.ABSTRACT_FIELD) { 560 originalElement.kind !== ElementKind.ABSTRACT_FIELD) {
533 internalError("Cannot patch non-getter/setter with getter/setter", 561 internalError("Cannot patch non-getter/setter with getter/setter",
534 element: originalElement); 562 element: originalElement);
535 } 563 }
536 AbstractFieldElement patchField = patchElement; 564 AbstractFieldElement patchField = patchElement;
537 AbstractFieldElement originalField = originalElement; 565 AbstractFieldElement originalField = originalElement;
538 if (patchField.getter !== null) { 566 if (patchField.getter !== null) {
539 if (originalField === null || originalField.getter === null) { 567 if (originalField === null || originalField.getter === null) {
540 original.addGetterOrSetter(clonePatch(patchField.getter)); 568 original.addGetterOrSetter(clonePatch(patchField.getter),
569 originalField,
570 this);
571 if (originalField === null && patchField.setter !== null) {
572 // It exists now, so find it for the setter patching.
573 originalField = lookup(patchElement.name);
574 }
541 } else { 575 } else {
542 patchMember(originalField.getter, patchField.getter); 576 patchMember(originalField.getter, patchField.getter);
543 } 577 }
544 } 578 }
545 if (patchField.setter !== null) { 579 if (patchField.setter !== null) {
546 if (originalField === null || originalField.setter === null) { 580 if (originalField === null || originalField.setter === null) {
547 original.addGetterOrSetter(clonePatch(patchField.setter)); 581 original.addGetterOrSetter(clonePatch(patchField.setter),
582 originalField,
583 this);
548 } else { 584 } else {
549 patchMember(originalField.setter, patchField.setter); 585 patchMember(originalField.setter, patchField.setter);
550 } 586 }
551 } 587 }
552 } else if (originalElement === null) { 588 } else if (originalElement === null) {
553 original.addMember(clonePatch(patchElement)); 589 if (isPatchElement(patchElement)) {
590 internalError("Cannot patch non-existing member '"
591 "${patchElement.name.slowToString()}'.");
592 }
593 original.addMember(clonePatch(patchElement), this);
554 } else { 594 } else {
555 patchMember(originalElement, patchElement); 595 patchMember(originalElement, patchElement);
556 } 596 }
557 patches = patches.tail; 597 patches = patches.tail;
558 } 598 }
559
560 // Copy imports.
561 Map<String, LibraryElement> delayedPatches = <LibraryElement>{};
562 Uri patchBase = patch.script.uri;
563 for (ScriptTag tag in patch.tags.reverse()) {
564 if (tag.isImport()) {
565 StringNode argument = tag.argument;
566 Uri resolved = patchBase.resolve(argument.dartString.slowToString());
567 LibraryElement importedLibrary =
568 scanner.loadLibrary(resolved, argument);
569 scanner.importLibrary(original, importedLibrary, tag, patch);
570 if (resolved.scheme == "dart") {
571 delayedPatches[resolved.path] = importedLibrary;
572 }
573 }
574 }
575
576 // Mark library as already patched.
577 original.patch = patch;
578
579 // We patch imported libraries after marking the current library as
580 // patched, to avoid problems with cyclic dependencies.
581 delayedPatches.forEach((String path, LibraryElement importedLibrary) {
582 patchDartLibrary(importedLibrary, path);
583 });
584 } 599 }
585 600
586 bool isPatchElement(Element element) { 601 bool isPatchElement(Element element) {
587 // TODO(lrn): More checks needed if we introduce metadata for real. 602 // TODO(lrn): More checks needed if we introduce metadata for real.
588 // In that case, it must have the identifier "native" as metadata. 603 // In that case, it must have the identifier "native" as metadata.
589 return !element.metadata.isEmpty(); 604 return !element.metadata.isEmpty();
590 } 605 }
591 606
592 Element clonePatch(Element patchElement) { 607 Element clonePatch(Element patchElement) {
593 // The original library does not have an element with the same name 608 // The original library does not have an element with the same name
594 // as the patch library element. 609 // as the patch library element.
595 // In this case, the patch library element must not be marked as "patch", 610 // In this case, the patch library element must not be marked as "patch",
596 // and its name must make it private. 611 // and its name must make it private.
597 if (isPatchElement(patchElement)) {
598 internalError("Cannot patch non-existing member '"
599 "${patchElement.name.slowToString()}'.");
600
601 }
602 if (!patchElement.name.isPrivate()) { 612 if (!patchElement.name.isPrivate()) {
603 internalError("Cannot add non-private member '" 613 internalError("Cannot add non-private member '"
604 "${patchElement.name.slowToString()}' from patch."); 614 "${patchElement.name.slowToString()}' from patch.");
605 } 615 }
606 // TODO(lrn): Create a copy of patchElement that isn't added to anything, 616 // TODO(lrn): Create a copy of patchElement that isn't added to any
607 // but which takes its source from patchElement. 617 // object/library yet, but which takes its source from patchElement.
608 throw "Adding members from patch is unsupported"; 618 throw "Adding members from patch is unsupported";
609 } 619 }
610 620
611 void patchMember(Element originalElement, 621 void patchMember(Element originalElement, Element patchElement) {
612 Element patchElement) {
613 // The original library has an element with the same name as the patch 622 // The original library has an element with the same name as the patch
614 // library element. 623 // library element.
615 // In this case, the patch library element must be a function marked as 624 // In this case, the patch library element must be a function marked as
616 // "patch" and it must have the same signature as the function it patches. 625 // "patch" and it must have the same signature as the function it patches.
617 if (!isPatchElement(patchElement)) { 626 if (!isPatchElement(patchElement)) {
618 internalError("Cannot overwrite existing '" 627 internalError("Cannot overwrite existing '"
619 "${originalElement.name.slowToString()}' with non-patch."); 628 "${originalElement.name.slowToString()}' with non-patch.");
620 } 629 }
630 if (originalElement is PartialClassElement) {
631 // Only happens when patching a library. Dart does not, yet, have nested
632 // classes.
633 if (patchElement is! PartialClassElement) {
634 internalError("Trying to patch class with non-class",
635 element:originalElement);
636 }
637 applyClassPatch(originalElement, patchElement);
638 return;
639 }
621 if (originalElement is! FunctionElement) { 640 if (originalElement is! FunctionElement) {
622 // TODO(lrn): Handle class declarations too. 641 // TODO(lrn): Handle class declarations too.
623 internalError("Can only patch functions", element: originalElement); 642 internalError("Can only patch functions", element: originalElement);
624 } 643 }
625 // TODO(lrn): Abort if the original isn't marked external, when 644 FunctionElement original = originalElement;
626 // that is added to the language. 645 if (!original.modifiers.isExternal()) {
646 internalError("Can only patch external functions.", element: original);
647 }
627 if (patchElement is! FunctionElement || 648 if (patchElement is! FunctionElement ||
628 !patchSignatureMatches(originalElement, patchElement)) { 649 !patchSignatureMatches(original, patchElement)) {
629 internalError("Can only patch functions with matching signatures", 650 internalError("Can only patch functions with matching signatures",
630 element: originalElement); 651 element: original);
631 } 652 }
632 applyFunctionPatch(originalElement, patchElement); 653 applyFunctionPatch(original, patchElement);
633 } 654 }
634 655
635 bool patchSignatureMatches(FunctionElement original, FunctionElement patch) { 656 bool patchSignatureMatches(FunctionElement original, FunctionElement patch) {
636 // TODO(lrn): Check that patches actually match the signature of 657 // TODO(lrn): Check that patches actually match the signature of
637 // the function it's patching. 658 // the function it's patching.
638 return true; 659 return true;
639 } 660 }
640 661
641 void applyFunctionPatch(FunctionElement element, 662 void applyFunctionPatch(FunctionElement element,
642 FunctionElement patchElement) { 663 FunctionElement patchElement) {
643 // Don't just assign the patch field. This also updates the cachedNode.
644 if (element.isPatched) { 664 if (element.isPatched) {
645 internalError("Trying to patch a function more than once.", 665 internalError("Trying to patch a function more than once.",
646 element: element); 666 element: element);
647 } 667 }
648 if (element.cachedNode !== null) { 668 if (element.cachedNode !== null) {
649 internalError("Trying to patch an already compiled function.", 669 internalError("Trying to patch an already compiled function.",
650 element: element); 670 element: element);
651 } 671 }
672 // Don't just assign the patch field. This also updates the cachedNode.
652 element.setPatch(patchElement); 673 element.setPatch(patchElement);
653 } 674 }
654 675
676 void applyClassPatch(PartialClassElement original,
677 PartialClassElement patch) {
678 // Eagerly parse the class so we can patch it.
679 // TODO(lrn): Perhaps find a way to delay parsing until the class is needed,
680 // i.e., until [parseNode] is called on [original].
681 ClassNode node = original.parseNode(this);
682 // Parse patch class with "patch" parser.
683 ClassNode patchNode = patchParser.parsePatchClassNode(patch);
684 Link<Element> patches = patch.members;
685 Element lookupMemberOrConstructor(SourceString name) {
686 Element result = original.lookupLocalMember(name);
687 if (result !== null) return result;
688 return original.lookupConstructor(name);
689 }
690 applyContainerPatch(original, patches, lookupMemberOrConstructor);
691 }
692
655 /** 693 /**
656 * Get an [Uri] pointing to a patch for the dart: library with 694 * Get an [Uri] pointing to a patch for the dart: library with
657 * the given path. Returns null if there is no patch. 695 * the given path. Returns null if there is no patch.
658 */ 696 */
659 abstract Uri resolvePatchUri(String dartLibraryPath); 697 abstract Uri resolvePatchUri(String dartLibraryPath);
660 698
661 /** Define the JS helper functions in the given library. */ 699 /** Define the JS helper functions in the given library. */
662 void addForeignFunctions(LibraryElement library) { 700 void addForeignFunctions(LibraryElement library) {
663 library.define(new ForeignElement( 701 library.define(new ForeignElement(
664 const SourceString('JS'), library), this); 702 const SourceString('JS'), library), this);
(...skipping 378 matching lines...) Expand 10 before | Expand all | Expand 10 after
1043 f(int beginOffset, int endOffset)) { 1081 f(int beginOffset, int endOffset)) {
1044 final beginOffset = begin.charOffset; 1082 final beginOffset = begin.charOffset;
1045 final endOffset = end.charOffset + end.slowCharCount; 1083 final endOffset = end.charOffset + end.slowCharCount;
1046 1084
1047 // [begin] and [end] might be the same for the same empty token. This 1085 // [begin] and [end] might be the same for the same empty token. This
1048 // happens for instance when scanning '$$'. 1086 // happens for instance when scanning '$$'.
1049 assert(endOffset >= beginOffset); 1087 assert(endOffset >= beginOffset);
1050 return f(beginOffset, endOffset); 1088 return f(beginOffset, endOffset);
1051 } 1089 }
1052 } 1090 }
OLDNEW
« no previous file with comments | « corelib/unified/math/random.dart ('k') | lib/compiler/implementation/elements/elements.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698