| 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 427 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 438 | 438 |
| 439 void onLibraryLoaded(LibraryElement library, Uri uri) { | 439 void onLibraryLoaded(LibraryElement library, Uri uri) { |
| 440 if (uri.toString() == 'dart:isolate') { | 440 if (uri.toString() == 'dart:isolate') { |
| 441 enableIsolateSupport(library); | 441 enableIsolateSupport(library); |
| 442 } | 442 } |
| 443 if (dynamicClass !== null) { | 443 if (dynamicClass !== null) { |
| 444 // When loading the built-in libraries, dynamicClass is null. We | 444 // When loading the built-in libraries, dynamicClass is null. We |
| 445 // take advantage of this as core and coreimpl import js_helper | 445 // take advantage of this as core and coreimpl import js_helper |
| 446 // and see Dynamic this way. | 446 // and see Dynamic this way. |
| 447 withCurrentElement(dynamicClass, () { | 447 withCurrentElement(dynamicClass, () { |
| 448 library.define(dynamicClass, this); | 448 library.addToScope(dynamicClass, this); |
| 449 }); | 449 }); |
| 450 } | 450 } |
| 451 } | 451 } |
| 452 | 452 |
| 453 abstract LibraryElement scanBuiltinLibrary(String filename); | 453 abstract LibraryElement scanBuiltinLibrary(String filename); |
| 454 | 454 |
| 455 void initializeSpecialClasses() { | 455 void initializeSpecialClasses() { |
| 456 bool coreLibValid = true; | 456 bool coreLibValid = true; |
| 457 ClassElement lookupSpecialClass(SourceString name) { | 457 ClassElement lookupSpecialClass(SourceString name) { |
| 458 ClassElement result = coreLibrary.find(name); | 458 ClassElement result = coreLibrary.find(name); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 517 if (patchUri !== null) { | 517 if (patchUri !== null) { |
| 518 LibraryElement patchLibrary = | 518 LibraryElement patchLibrary = |
| 519 patchParser.loadPatchLibrary(patchUri); | 519 patchParser.loadPatchLibrary(patchUri); |
| 520 // We allow foreign functions in patched libraries. | 520 // We allow foreign functions in patched libraries. |
| 521 addForeignFunctions(library); // Is safe even if already added. | 521 addForeignFunctions(library); // Is safe even if already added. |
| 522 applyLibraryPatch(library, patchLibrary); | 522 applyLibraryPatch(library, patchLibrary); |
| 523 } | 523 } |
| 524 } | 524 } |
| 525 | 525 |
| 526 void applyLibraryPatch(LibraryElement original, LibraryElement patch) { | 526 void applyLibraryPatch(LibraryElement original, LibraryElement patch) { |
| 527 Link<Element> patches = patch.topLevelElements; | 527 Link<Element> patches = patch.localMembers; |
| 528 applyContainerPatch(original, patches, original.findLocal); | 528 applyContainerPatch(original, patches); |
| 529 | 529 |
| 530 // Copy imports from patch to original library. | 530 // Copy imports from patch to original library. |
| 531 Map<String, LibraryElement> delayedPatches = <LibraryElement>{}; | 531 Map<String, LibraryElement> delayedPatches = <LibraryElement>{}; |
| 532 Uri patchBase = patch.script.uri; | 532 Uri patchBase = patch.uri; |
| 533 for (ScriptTag tag in patch.tags.reverse()) { | 533 for (ScriptTag tag in patch.tags.reverse()) { |
| 534 if (tag.isImport()) { | 534 if (tag.isImport()) { |
| 535 StringNode argument = tag.argument; | 535 StringNode argument = tag.argument; |
| 536 Uri resolved = patchBase.resolve(argument.dartString.slowToString()); | 536 Uri resolved = patchBase.resolve(argument.dartString.slowToString()); |
| 537 LibraryElement importedLibrary = | 537 LibraryElement importedLibrary = |
| 538 scanner.loadLibrary(resolved, argument); | 538 scanner.loadLibrary(resolved, argument); |
| 539 scanner.importLibrary(original, importedLibrary, tag, patch); | 539 scanner.importLibrary(original, importedLibrary, tag, |
| 540 patch.entryCompilationUnit); |
| 540 if (resolved.scheme == "dart") { | 541 if (resolved.scheme == "dart") { |
| 541 delayedPatches[resolved.path] = importedLibrary; | 542 delayedPatches[resolved.path] = importedLibrary; |
| 542 } | 543 } |
| 543 } | 544 } |
| 544 } | 545 } |
| 545 | 546 |
| 546 // Mark library as already patched. | 547 // Mark library as already patched. |
| 547 original.patch = patch; | 548 original.patch = patch; |
| 548 | 549 |
| 549 // We patch imported libraries after marking the current library as | 550 // We patch imported libraries after marking the current library as |
| 550 // patched, to avoid problems with cyclic dependencies. | 551 // patched, to avoid problems with cyclic dependencies. |
| 551 delayedPatches.forEach((String path, LibraryElement importedLibrary) { | 552 delayedPatches.forEach((String path, LibraryElement importedLibrary) { |
| 552 patchDartLibrary(importedLibrary, path); | 553 patchDartLibrary(importedLibrary, path); |
| 553 }); | 554 }); |
| 554 } | 555 } |
| 555 | 556 |
| 556 void applyContainerPatch(ContainerElement original, Link<Element> patches, | 557 void applyContainerPatch(ScopeContainerElement original, |
| 557 Element lookup(SourceString name)) { | 558 Link<Element> patches) { |
| 558 while (!patches.isEmpty()) { | 559 while (!patches.isEmpty()) { |
| 559 Element patchElement = patches.head; | 560 Element patchElement = patches.head; |
| 560 Element originalElement = lookup(patchElement.name); | 561 Element originalElement = original.localLookup(patchElement.name); |
| 561 if (patchElement.isAccessor()) { | 562 if (patchElement.isAccessor()) { |
| 562 // Skip accessors. An accessor always has an abstract field, | 563 // Skip accessors. An accessor always has an abstract field, |
| 563 // representing the accessor in the lookup scope. We can thus skip the | 564 // representing the accessor in the lookup scope. We can thus skip the |
| 564 // accessors and just handle the abstract field. | 565 // accessors and just handle the abstract field. |
| 565 } else if (patchElement.kind === ElementKind.ABSTRACT_FIELD) { | 566 } else if (patchElement.kind === ElementKind.ABSTRACT_FIELD) { |
| 566 // Getters and setters are kept inside a synthetic field. | 567 // Getters and setters are kept inside a synthetic field. |
| 567 if (originalElement !== null && | 568 if (originalElement !== null && |
| 568 originalElement.kind !== ElementKind.ABSTRACT_FIELD) { | 569 originalElement.kind !== ElementKind.ABSTRACT_FIELD) { |
| 569 internalError("Cannot patch non-getter/setter with getter/setter", | 570 internalError("Cannot patch non-getter/setter with getter/setter", |
| 570 element: originalElement); | 571 element: originalElement); |
| 571 } | 572 } |
| 572 AbstractFieldElement patchField = patchElement; | 573 AbstractFieldElement patchField = patchElement; |
| 573 AbstractFieldElement originalField = originalElement; | 574 AbstractFieldElement originalField = originalElement; |
| 574 if (patchField.getter !== null) { | 575 if (patchField.getter !== null) { |
| 575 if (originalField === null || originalField.getter === null) { | 576 if (originalField === null || originalField.getter === null) { |
| 576 original.addGetterOrSetter(clonePatch(patchField.getter), | 577 original.addGetterOrSetter(clonePatch(patchField.getter), |
| 577 originalField, | 578 originalField, |
| 578 this); | 579 this); |
| 579 if (originalField === null && patchField.setter !== null) { | 580 if (originalField === null && patchField.setter !== null) { |
| 580 // It exists now, so find it for the setter patching. | 581 // It exists now, so find it for the setter patching. |
| 581 originalField = lookup(patchElement.name); | 582 originalField = original.localLookup(patchElement.name); |
| 582 } | 583 } |
| 583 } else { | 584 } else { |
| 584 patchMember(originalField.getter, patchField.getter); | 585 patchMember(originalField.getter, patchField.getter); |
| 585 } | 586 } |
| 586 } | 587 } |
| 587 if (patchField.setter !== null) { | 588 if (patchField.setter !== null) { |
| 588 if (originalField === null || originalField.setter === null) { | 589 if (originalField === null || originalField.setter === null) { |
| 589 original.addGetterOrSetter(clonePatch(patchField.setter), | 590 original.addGetterOrSetter(clonePatch(patchField.setter), |
| 590 originalField, | 591 originalField, |
| 591 this); | 592 this); |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 682 } | 683 } |
| 683 | 684 |
| 684 void applyClassPatch(PartialClassElement original, | 685 void applyClassPatch(PartialClassElement original, |
| 685 PartialClassElement patch) { | 686 PartialClassElement patch) { |
| 686 // Eagerly parse the class so we can patch it. | 687 // Eagerly parse the class so we can patch it. |
| 687 // TODO(lrn): Perhaps find a way to delay parsing until the class is needed, | 688 // TODO(lrn): Perhaps find a way to delay parsing until the class is needed, |
| 688 // i.e., until [parseNode] is called on [original]. | 689 // i.e., until [parseNode] is called on [original]. |
| 689 ClassNode node = original.parseNode(this); | 690 ClassNode node = original.parseNode(this); |
| 690 // Parse patch class with "patch" parser. | 691 // Parse patch class with "patch" parser. |
| 691 ClassNode patchNode = patchParser.parsePatchClassNode(patch); | 692 ClassNode patchNode = patchParser.parsePatchClassNode(patch); |
| 692 Link<Element> patches = patch.members; | 693 Link<Element> patches = patch.localMembers; |
| 693 Element lookupMemberOrConstructor(SourceString name) { | 694 applyContainerPatch(original, patches); |
| 694 Element result = original.lookupLocalMember(name); | |
| 695 if (result !== null) return result; | |
| 696 return original.lookupConstructor(name); | |
| 697 } | |
| 698 applyContainerPatch(original, patches, lookupMemberOrConstructor); | |
| 699 } | 695 } |
| 700 | 696 |
| 701 /** | 697 /** |
| 702 * Get an [Uri] pointing to a patch for the dart: library with | 698 * Get an [Uri] pointing to a patch for the dart: library with |
| 703 * the given path. Returns null if there is no patch. | 699 * the given path. Returns null if there is no patch. |
| 704 */ | 700 */ |
| 705 abstract Uri resolvePatchUri(String dartLibraryPath); | 701 abstract Uri resolvePatchUri(String dartLibraryPath); |
| 706 | 702 |
| 707 /** Define the JS helper functions in the given library. */ | 703 /** Define the JS helper functions in the given library. */ |
| 708 void addForeignFunctions(LibraryElement library) { | 704 void addForeignFunctions(LibraryElement library) { |
| 709 library.define(new ForeignElement( | 705 library.addToScope(new ForeignElement( |
| 710 const SourceString('JS'), library), this); | 706 const SourceString('JS'), library), this); |
| 711 library.define(new ForeignElement( | 707 library.addToScope(new ForeignElement( |
| 712 const SourceString('UNINTERCEPTED'), library), this); | 708 const SourceString('UNINTERCEPTED'), library), this); |
| 713 library.define(new ForeignElement( | 709 library.addToScope(new ForeignElement( |
| 714 const SourceString('JS_HAS_EQUALS'), library), this); | 710 const SourceString('JS_HAS_EQUALS'), library), this); |
| 715 library.define(new ForeignElement( | 711 library.addToScope(new ForeignElement( |
| 716 const SourceString('JS_CURRENT_ISOLATE'), library), this); | 712 const SourceString('JS_CURRENT_ISOLATE'), library), this); |
| 717 library.define(new ForeignElement( | 713 library.addToScope(new ForeignElement( |
| 718 const SourceString('JS_CALL_IN_ISOLATE'), library), this); | 714 const SourceString('JS_CALL_IN_ISOLATE'), library), this); |
| 719 library.define(new ForeignElement( | 715 library.addToScope(new ForeignElement( |
| 720 const SourceString('DART_CLOSURE_TO_JS'), library), this); | 716 const SourceString('DART_CLOSURE_TO_JS'), library), this); |
| 721 } | 717 } |
| 722 | 718 |
| 723 void runCompiler(Uri uri) { | 719 void runCompiler(Uri uri) { |
| 724 scanBuiltinLibraries(); | 720 scanBuiltinLibraries(); |
| 725 mainApp = scanner.loadLibrary(uri, null); | 721 mainApp = scanner.loadLibrary(uri, null); |
| 726 final Element main = mainApp.find(MAIN); | 722 final Element main = mainApp.find(MAIN); |
| 727 if (main === null) { | 723 if (main === null) { |
| 728 reportFatalError('Could not find $MAIN', mainApp); | 724 reportFatalError('Could not find $MAIN', mainApp); |
| 729 } else { | 725 } else { |
| (...skipping 371 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1101 final endOffset = end.charOffset + end.slowCharCount; | 1097 final endOffset = end.charOffset + end.slowCharCount; |
| 1102 | 1098 |
| 1103 // [begin] and [end] might be the same for the same empty token. This | 1099 // [begin] and [end] might be the same for the same empty token. This |
| 1104 // happens for instance when scanning '$$'. | 1100 // happens for instance when scanning '$$'. |
| 1105 assert(endOffset >= beginOffset); | 1101 assert(endOffset >= beginOffset); |
| 1106 return f(beginOffset, endOffset); | 1102 return f(beginOffset, endOffset); |
| 1107 } | 1103 } |
| 1108 | 1104 |
| 1109 String toString() => 'SourceSpan($uri, $begin, $end)'; | 1105 String toString() => 'SourceSpan($uri, $begin, $end)'; |
| 1110 } | 1106 } |
| OLD | NEW |