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 |