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.script); | 537 scanner.importLibrary(original, importedLibrary, tag, patch); |
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 assert(patchElement.kind !== ElementKind.ABSTRACT_FIELD); | 559 // Getters and setters are kept inside a synthetic field. |
560 if (originalElement !== null && | 560 if (patchElement.kind === ElementKind.ABSTRACT_FIELD) { |
561 originalElement.kind === ElementKind.ABSTRACT_FIELD) { | 561 if (originalElement !== null && |
| 562 originalElement.kind !== ElementKind.ABSTRACT_FIELD) { |
| 563 internalError("Cannot patch non-getter/setter with getter/setter", |
| 564 element: originalElement); |
| 565 } |
| 566 AbstractFieldElement patchField = patchElement; |
562 AbstractFieldElement originalField = originalElement; | 567 AbstractFieldElement originalField = originalElement; |
563 if (patchElement.kind === ElementKind.GETTER) { | 568 if (patchField.getter !== null) { |
564 originalElement = originalField.getter; | 569 if (originalField === null || originalField.getter === null) { |
565 } else if (patchElement.kind === ElementKind.SETTER) { | 570 original.addGetterOrSetter(clonePatch(patchField.getter), |
566 originalElement = originalField.setter; | 571 originalField, |
567 } else { | 572 this); |
568 internalError("Cannot patch a getter/setter field with a " | 573 if (originalField === null && patchField.setter !== null) { |
569 "non-getter/setter patch", element: originalElement); | 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 } |
570 } | 580 } |
571 } | 581 if (patchField.setter !== null) { |
572 if (originalElement === null) { | 582 if (originalField === null || originalField.setter === null) { |
573 // The original library does not have an element with the same name | 583 original.addGetterOrSetter(clonePatch(patchField.setter), |
574 // as the patch library element. | 584 originalField, |
575 // In this case, the patch library element must not be marked as | 585 this); |
576 // "patch", and its name must make it private. | 586 } else { |
| 587 patchMember(originalField.setter, patchField.setter); |
| 588 } |
| 589 } |
| 590 } else if (originalElement === null) { |
577 if (isPatchElement(patchElement)) { | 591 if (isPatchElement(patchElement)) { |
578 internalError("Cannot patch non-existing member '" | 592 internalError("Cannot patch non-existing member '" |
579 "${patchElement.name.slowToString()}'."); | 593 "${patchElement.name.slowToString()}'."); |
580 } | 594 } |
581 if (!patchElement.name.isPrivate()) { | 595 original.addMember(clonePatch(patchElement), this); |
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); | |
587 } else { | 596 } else { |
588 patchMember(originalElement, patchElement); | 597 patchMember(originalElement, patchElement); |
589 } | 598 } |
590 patches = patches.tail; | 599 patches = patches.tail; |
591 } | 600 } |
592 } | 601 } |
593 | 602 |
594 bool isPatchElement(Element element) { | 603 bool isPatchElement(Element element) { |
595 // TODO(lrn): More checks needed if we introduce metadata for real. | 604 // TODO(lrn): More checks needed if we introduce metadata for real. |
596 // In that case, it must have the identifier "native" as metadata. | 605 // In that case, it must have the identifier "native" as metadata. |
597 return !element.metadata.isEmpty(); | 606 return !element.metadata.isEmpty(); |
598 } | 607 } |
599 | 608 |
| 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 |
600 void patchMember(Element originalElement, Element patchElement) { | 623 void patchMember(Element originalElement, Element patchElement) { |
601 // The original library has an element with the same name as the patch | 624 // The original library has an element with the same name as the patch |
602 // library element. | 625 // library element. |
603 // In this case, the patch library element must be a function marked as | 626 // In this case, the patch library element must be a function marked as |
604 // "patch" and it must have the same signature as the function it patches. | 627 // "patch" and it must have the same signature as the function it patches. |
605 if (!isPatchElement(patchElement)) { | 628 if (!isPatchElement(patchElement)) { |
606 internalError("Cannot overwrite existing '" | 629 internalError("Cannot overwrite existing '" |
607 "${originalElement.name.slowToString()}' with non-patch."); | 630 "${originalElement.name.slowToString()}' with non-patch."); |
608 } | 631 } |
609 if (originalElement is PartialClassElement) { | 632 if (originalElement is PartialClassElement) { |
(...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
948 api.Diagnostic kind); | 971 api.Diagnostic kind); |
949 | 972 |
950 SourceSpan spanFromTokens(Token begin, Token end, [Uri uri]) { | 973 SourceSpan spanFromTokens(Token begin, Token end, [Uri uri]) { |
951 if (begin === null || end === null) { | 974 if (begin === null || end === null) { |
952 // TODO(ahe): We can almost always do better. Often it is only | 975 // TODO(ahe): We can almost always do better. Often it is only |
953 // end that is null. Otherwise, we probably know the current | 976 // end that is null. Otherwise, we probably know the current |
954 // URI. | 977 // URI. |
955 throw 'Cannot find tokens to produce error message.'; | 978 throw 'Cannot find tokens to produce error message.'; |
956 } | 979 } |
957 if (uri === null && currentElement !== null) { | 980 if (uri === null && currentElement !== null) { |
958 uri = currentElement.getScript().uri; | 981 uri = currentElement.getCompilationUnit().script.uri; |
959 } | 982 } |
960 return SourceSpan.withCharacterOffsets(begin, end, | 983 return SourceSpan.withCharacterOffsets(begin, end, |
961 (beginOffset, endOffset) => new SourceSpan(uri, beginOffset, endOffset)); | 984 (beginOffset, endOffset) => new SourceSpan(uri, beginOffset, endOffset)); |
962 } | 985 } |
963 | 986 |
964 SourceSpan spanFromNode(Node node, [Uri uri]) { | 987 SourceSpan spanFromNode(Node node, [Uri uri]) { |
965 return spanFromTokens(node.getBeginToken(), node.getEndToken(), uri); | 988 return spanFromTokens(node.getBeginToken(), node.getEndToken(), uri); |
966 } | 989 } |
967 | 990 |
968 SourceSpan spanFromElement(Element element) { | 991 SourceSpan spanFromElement(Element element) { |
969 if (element.position() === null) { | 992 if (element.position() === null) { |
970 // Sometimes, the backend fakes up elements that have no | 993 // Sometimes, the backend fakes up elements that have no |
971 // position. So we use the enclosing element instead. It is | 994 // position. So we use the enclosing element instead. It is |
972 // not a good error location, but cancel really is "internal | 995 // not a good error location, but cancel really is "internal |
973 // error" or "not implemented yet", so the vicinity is good | 996 // error" or "not implemented yet", so the vicinity is good |
974 // enough for now. | 997 // enough for now. |
975 element = element.enclosingElement; | 998 element = element.enclosingElement; |
976 // TODO(ahe): I plan to overhaul this infrastructure anyways. | 999 // TODO(ahe): I plan to overhaul this infrastructure anyways. |
977 } | 1000 } |
978 if (element === null) { | 1001 if (element === null) { |
979 element = currentElement; | 1002 element = currentElement; |
980 } | 1003 } |
981 Token position = element.position(); | 1004 Token position = element.position(); |
982 Uri uri = element.getScript().uri; | 1005 Uri uri = element.getCompilationUnit().script.uri; |
983 return (position === null) | 1006 return (position === null) |
984 ? new SourceSpan(uri, 0, 0) | 1007 ? new SourceSpan(uri, 0, 0) |
985 : spanFromTokens(position, position, uri); | 1008 : spanFromTokens(position, position, uri); |
986 } | 1009 } |
987 | 1010 |
988 Script readScript(Uri uri, [ScriptTag node]) { | 1011 Script readScript(Uri uri, [ScriptTag node]) { |
989 unimplemented('Compiler.readScript'); | 1012 unimplemented('Compiler.readScript'); |
990 } | 1013 } |
991 | 1014 |
992 String get legDirectory() { | 1015 String get legDirectory() { |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1062 final endOffset = end.charOffset + end.slowCharCount; | 1085 final endOffset = end.charOffset + end.slowCharCount; |
1063 | 1086 |
1064 // [begin] and [end] might be the same for the same empty token. This | 1087 // [begin] and [end] might be the same for the same empty token. This |
1065 // happens for instance when scanning '$$'. | 1088 // happens for instance when scanning '$$'. |
1066 assert(endOffset >= beginOffset); | 1089 assert(endOffset >= beginOffset); |
1067 return f(beginOffset, endOffset); | 1090 return f(beginOffset, endOffset); |
1068 } | 1091 } |
1069 | 1092 |
1070 String toString() => 'SourceSpan($uri, $begin, $end)'; | 1093 String toString() => 'SourceSpan($uri, $begin, $end)'; |
1071 } | 1094 } |
OLD | NEW |