| OLD | NEW |
| 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 516 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 527 | 527 |
| 528 // Copy imports from patch to original library. | 528 // Copy imports from patch to original library. |
| 529 Map<String, LibraryElement> delayedPatches = <LibraryElement>{}; | 529 Map<String, LibraryElement> delayedPatches = <LibraryElement>{}; |
| 530 Uri patchBase = patch.script.uri; | 530 Uri patchBase = patch.script.uri; |
| 531 for (ScriptTag tag in patch.tags.reverse()) { | 531 for (ScriptTag tag in patch.tags.reverse()) { |
| 532 if (tag.isImport()) { | 532 if (tag.isImport()) { |
| 533 StringNode argument = tag.argument; | 533 StringNode argument = tag.argument; |
| 534 Uri resolved = patchBase.resolve(argument.dartString.slowToString()); | 534 Uri resolved = patchBase.resolve(argument.dartString.slowToString()); |
| 535 LibraryElement importedLibrary = | 535 LibraryElement importedLibrary = |
| 536 scanner.loadLibrary(resolved, argument); | 536 scanner.loadLibrary(resolved, argument); |
| 537 scanner.importLibrary(original, importedLibrary, tag, patch); | 537 scanner.importLibrary(original, importedLibrary, tag, patch.script); |
| 538 if (resolved.scheme == "dart") { | 538 if (resolved.scheme == "dart") { |
| 539 delayedPatches[resolved.path] = importedLibrary; | 539 delayedPatches[resolved.path] = importedLibrary; |
| 540 } | 540 } |
| 541 } | 541 } |
| 542 } | 542 } |
| 543 | 543 |
| 544 // Mark library as already patched. | 544 // Mark library as already patched. |
| 545 original.patch = patch; | 545 original.patch = patch; |
| 546 | 546 |
| 547 // We patch imported libraries after marking the current library as | 547 // We patch imported libraries after marking the current library as |
| 548 // patched, to avoid problems with cyclic dependencies. | 548 // patched, to avoid problems with cyclic dependencies. |
| 549 delayedPatches.forEach((String path, LibraryElement importedLibrary) { | 549 delayedPatches.forEach((String path, LibraryElement importedLibrary) { |
| 550 patchDartLibrary(importedLibrary, path); | 550 patchDartLibrary(importedLibrary, path); |
| 551 }); | 551 }); |
| 552 } | 552 } |
| 553 | 553 |
| 554 void applyContainerPatch(ContainerElement original, Link<Element> patches, | 554 void applyContainerPatch(ContainerElement original, Link<Element> patches, |
| 555 Element lookup(SourceString name)) { | 555 Element lookup(SourceString name)) { |
| 556 while (!patches.isEmpty()) { | 556 while (!patches.isEmpty()) { |
| 557 Element patchElement = patches.head; | 557 Element patchElement = patches.head; |
| 558 Element originalElement = lookup(patchElement.name); | 558 Element originalElement = lookup(patchElement.name); |
| 559 // Getters and setters are kept inside a synthetic field. | 559 assert(patchElement.kind !== ElementKind.ABSTRACT_FIELD); |
| 560 if (patchElement.kind === ElementKind.ABSTRACT_FIELD) { | 560 if (originalElement !== null && |
| 561 if (originalElement !== null && | 561 originalElement.kind === ElementKind.ABSTRACT_FIELD) { |
| 562 originalElement.kind !== ElementKind.ABSTRACT_FIELD) { | 562 AbstractFieldElement originalField = originalElement; |
| 563 internalError("Cannot patch non-getter/setter with getter/setter", | 563 if (patchElement.kind === ElementKind.GETTER) { |
| 564 element: originalElement); | 564 originalElement = originalField.getter; |
| 565 } else if (patchElement.kind === ElementKind.SETTER) { |
| 566 originalElement = originalField.setter; |
| 567 } else { |
| 568 internalError("Cannot patch a getter/setter field with a " |
| 569 "non-getter/setter patch", element: originalElement); |
| 565 } | 570 } |
| 566 AbstractFieldElement patchField = patchElement; | 571 } |
| 567 AbstractFieldElement originalField = originalElement; | 572 if (originalElement === null) { |
| 568 if (patchField.getter !== null) { | 573 // The original library does not have an element with the same name |
| 569 if (originalField === null || originalField.getter === null) { | 574 // as the patch library element. |
| 570 original.addGetterOrSetter(clonePatch(patchField.getter), | 575 // In this case, the patch library element must not be marked as |
| 571 originalField, | 576 // "patch", and its name must make it private. |
| 572 this); | |
| 573 if (originalField === null && patchField.setter !== null) { | |
| 574 // It exists now, so find it for the setter patching. | |
| 575 originalField = lookup(patchElement.name); | |
| 576 } | |
| 577 } else { | |
| 578 patchMember(originalField.getter, patchField.getter); | |
| 579 } | |
| 580 } | |
| 581 if (patchField.setter !== null) { | |
| 582 if (originalField === null || originalField.setter === null) { | |
| 583 original.addGetterOrSetter(clonePatch(patchField.setter), | |
| 584 originalField, | |
| 585 this); | |
| 586 } else { | |
| 587 patchMember(originalField.setter, patchField.setter); | |
| 588 } | |
| 589 } | |
| 590 } else if (originalElement === null) { | |
| 591 if (isPatchElement(patchElement)) { | 577 if (isPatchElement(patchElement)) { |
| 592 internalError("Cannot patch non-existing member '" | 578 internalError("Cannot patch non-existing member '" |
| 593 "${patchElement.name.slowToString()}'."); | 579 "${patchElement.name.slowToString()}'."); |
| 594 } | 580 } |
| 595 original.addMember(clonePatch(patchElement), this); | 581 if (!patchElement.name.isPrivate()) { |
| 582 internalError("Cannot add non-private member '" |
| 583 "${patchElement.name.slowToString()}' from patch."); |
| 584 } |
| 585 Element cloneElement = patchElement.cloneTo(original, this); |
| 586 original.addMember(cloneElement, this); |
| 596 } else { | 587 } else { |
| 597 patchMember(originalElement, patchElement); | 588 patchMember(originalElement, patchElement); |
| 598 } | 589 } |
| 599 patches = patches.tail; | 590 patches = patches.tail; |
| 600 } | 591 } |
| 601 } | 592 } |
| 602 | 593 |
| 603 bool isPatchElement(Element element) { | 594 bool isPatchElement(Element element) { |
| 604 // TODO(lrn): More checks needed if we introduce metadata for real. | 595 // TODO(lrn): More checks needed if we introduce metadata for real. |
| 605 // In that case, it must have the identifier "native" as metadata. | 596 // In that case, it must have the identifier "native" as metadata. |
| 606 return !element.metadata.isEmpty(); | 597 return !element.metadata.isEmpty(); |
| 607 } | 598 } |
| 608 | 599 |
| 609 Element clonePatch(Element patchElement) { | |
| 610 // The original library does not have an element with the same name | |
| 611 // as the patch library element. | |
| 612 // In this case, the patch library element must not be marked as "patch", | |
| 613 // and its name must make it private. | |
| 614 if (!patchElement.name.isPrivate()) { | |
| 615 internalError("Cannot add non-private member '" | |
| 616 "${patchElement.name.slowToString()}' from patch."); | |
| 617 } | |
| 618 // TODO(lrn): Create a copy of patchElement that isn't added to any | |
| 619 // object/library yet, but which takes its source from patchElement. | |
| 620 throw "Adding members from patch is unsupported"; | |
| 621 } | |
| 622 | |
| 623 void patchMember(Element originalElement, Element patchElement) { | 600 void patchMember(Element originalElement, Element patchElement) { |
| 624 // The original library has an element with the same name as the patch | 601 // The original library has an element with the same name as the patch |
| 625 // library element. | 602 // library element. |
| 626 // In this case, the patch library element must be a function marked as | 603 // In this case, the patch library element must be a function marked as |
| 627 // "patch" and it must have the same signature as the function it patches. | 604 // "patch" and it must have the same signature as the function it patches. |
| 628 if (!isPatchElement(patchElement)) { | 605 if (!isPatchElement(patchElement)) { |
| 629 internalError("Cannot overwrite existing '" | 606 internalError("Cannot overwrite existing '" |
| 630 "${originalElement.name.slowToString()}' with non-patch."); | 607 "${originalElement.name.slowToString()}' with non-patch."); |
| 631 } | 608 } |
| 632 if (originalElement is PartialClassElement) { | 609 if (originalElement is PartialClassElement) { |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 971 api.Diagnostic kind); | 948 api.Diagnostic kind); |
| 972 | 949 |
| 973 SourceSpan spanFromTokens(Token begin, Token end, [Uri uri]) { | 950 SourceSpan spanFromTokens(Token begin, Token end, [Uri uri]) { |
| 974 if (begin === null || end === null) { | 951 if (begin === null || end === null) { |
| 975 // TODO(ahe): We can almost always do better. Often it is only | 952 // TODO(ahe): We can almost always do better. Often it is only |
| 976 // end that is null. Otherwise, we probably know the current | 953 // end that is null. Otherwise, we probably know the current |
| 977 // URI. | 954 // URI. |
| 978 throw 'Cannot find tokens to produce error message.'; | 955 throw 'Cannot find tokens to produce error message.'; |
| 979 } | 956 } |
| 980 if (uri === null && currentElement !== null) { | 957 if (uri === null && currentElement !== null) { |
| 981 uri = currentElement.getCompilationUnit().script.uri; | 958 uri = currentElement.getScript().uri; |
| 982 } | 959 } |
| 983 return SourceSpan.withCharacterOffsets(begin, end, | 960 return SourceSpan.withCharacterOffsets(begin, end, |
| 984 (beginOffset, endOffset) => new SourceSpan(uri, beginOffset, endOffset)); | 961 (beginOffset, endOffset) => new SourceSpan(uri, beginOffset, endOffset)); |
| 985 } | 962 } |
| 986 | 963 |
| 987 SourceSpan spanFromNode(Node node, [Uri uri]) { | 964 SourceSpan spanFromNode(Node node, [Uri uri]) { |
| 988 return spanFromTokens(node.getBeginToken(), node.getEndToken(), uri); | 965 return spanFromTokens(node.getBeginToken(), node.getEndToken(), uri); |
| 989 } | 966 } |
| 990 | 967 |
| 991 SourceSpan spanFromElement(Element element) { | 968 SourceSpan spanFromElement(Element element) { |
| 992 if (element.position() === null) { | 969 if (element.position() === null) { |
| 993 // Sometimes, the backend fakes up elements that have no | 970 // Sometimes, the backend fakes up elements that have no |
| 994 // position. So we use the enclosing element instead. It is | 971 // position. So we use the enclosing element instead. It is |
| 995 // not a good error location, but cancel really is "internal | 972 // not a good error location, but cancel really is "internal |
| 996 // error" or "not implemented yet", so the vicinity is good | 973 // error" or "not implemented yet", so the vicinity is good |
| 997 // enough for now. | 974 // enough for now. |
| 998 element = element.enclosingElement; | 975 element = element.enclosingElement; |
| 999 // TODO(ahe): I plan to overhaul this infrastructure anyways. | 976 // TODO(ahe): I plan to overhaul this infrastructure anyways. |
| 1000 } | 977 } |
| 1001 if (element === null) { | 978 if (element === null) { |
| 1002 element = currentElement; | 979 element = currentElement; |
| 1003 } | 980 } |
| 1004 Token position = element.position(); | 981 Token position = element.position(); |
| 1005 Uri uri = element.getCompilationUnit().script.uri; | 982 Uri uri = element.getScript().uri; |
| 1006 return (position === null) | 983 return (position === null) |
| 1007 ? new SourceSpan(uri, 0, 0) | 984 ? new SourceSpan(uri, 0, 0) |
| 1008 : spanFromTokens(position, position, uri); | 985 : spanFromTokens(position, position, uri); |
| 1009 } | 986 } |
| 1010 | 987 |
| 1011 Script readScript(Uri uri, [ScriptTag node]) { | 988 Script readScript(Uri uri, [ScriptTag node]) { |
| 1012 unimplemented('Compiler.readScript'); | 989 unimplemented('Compiler.readScript'); |
| 1013 } | 990 } |
| 1014 | 991 |
| 1015 String get legDirectory() { | 992 String get legDirectory() { |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1085 final endOffset = end.charOffset + end.slowCharCount; | 1062 final endOffset = end.charOffset + end.slowCharCount; |
| 1086 | 1063 |
| 1087 // [begin] and [end] might be the same for the same empty token. This | 1064 // [begin] and [end] might be the same for the same empty token. This |
| 1088 // happens for instance when scanning '$$'. | 1065 // happens for instance when scanning '$$'. |
| 1089 assert(endOffset >= beginOffset); | 1066 assert(endOffset >= beginOffset); |
| 1090 return f(beginOffset, endOffset); | 1067 return f(beginOffset, endOffset); |
| 1091 } | 1068 } |
| 1092 | 1069 |
| 1093 String toString() => 'SourceSpan($uri, $begin, $end)'; | 1070 String toString() => 'SourceSpan($uri, $begin, $end)'; |
| 1094 } | 1071 } |
| OLD | NEW |