| 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 273 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 284 | 284 |
| 285 void onLibraryLoaded(LibraryElement library, Uri uri) { | 285 void onLibraryLoaded(LibraryElement library, Uri uri) { |
| 286 if (uri.toString() == 'dart:isolate') { | 286 if (uri.toString() == 'dart:isolate') { |
| 287 enableIsolateSupport(library); | 287 enableIsolateSupport(library); |
| 288 } | 288 } |
| 289 if (dynamicClass !== null) { | 289 if (dynamicClass !== null) { |
| 290 // When loading the built-in libraries, dynamicClass is null. We | 290 // When loading the built-in libraries, dynamicClass is null. We |
| 291 // take advantage of this as core and coreimpl import js_helper | 291 // take advantage of this as core and coreimpl import js_helper |
| 292 // and see Dynamic this way. | 292 // and see Dynamic this way. |
| 293 withCurrentElement(dynamicClass, () { | 293 withCurrentElement(dynamicClass, () { |
| 294 library.define(dynamicClass, this); | 294 library.addToScope(dynamicClass, this); |
| 295 }); | 295 }); |
| 296 } | 296 } |
| 297 } | 297 } |
| 298 | 298 |
| 299 abstract LibraryElement scanBuiltinLibrary(String filename); | 299 abstract LibraryElement scanBuiltinLibrary(String filename); |
| 300 | 300 |
| 301 void initializeSpecialClasses() { | 301 void initializeSpecialClasses() { |
| 302 bool coreLibValid = true; | 302 bool coreLibValid = true; |
| 303 ClassElement lookupSpecialClass(SourceString name) { | 303 ClassElement lookupSpecialClass(SourceString name) { |
| 304 ClassElement result = coreLibrary.find(name); | 304 ClassElement result = coreLibrary.find(name); |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 363 if (patchUri !== null) { | 363 if (patchUri !== null) { |
| 364 LibraryElement patchLibrary = | 364 LibraryElement patchLibrary = |
| 365 patchParser.loadPatchLibrary(patchUri); | 365 patchParser.loadPatchLibrary(patchUri); |
| 366 // We allow foreign functions in patched libraries. | 366 // We allow foreign functions in patched libraries. |
| 367 addForeignFunctions(library); // Is safe even if already added. | 367 addForeignFunctions(library); // Is safe even if already added. |
| 368 applyLibraryPatch(library, patchLibrary); | 368 applyLibraryPatch(library, patchLibrary); |
| 369 } | 369 } |
| 370 } | 370 } |
| 371 | 371 |
| 372 void applyLibraryPatch(LibraryElement original, LibraryElement patch) { | 372 void applyLibraryPatch(LibraryElement original, LibraryElement patch) { |
| 373 Link<Element> patches = patch.topLevelElements; | 373 Link<Element> patches = patch.localMembers; |
| 374 applyContainerPatch(original, patches, original.findLocal); | 374 applyContainerPatch(original, patches); |
| 375 | 375 |
| 376 // Copy imports from patch to original library. | 376 // Copy imports from patch to original library. |
| 377 Map<String, LibraryElement> delayedPatches = <LibraryElement>{}; | 377 Map<String, LibraryElement> delayedPatches = <LibraryElement>{}; |
| 378 Uri patchBase = patch.script.uri; | 378 Uri patchBase = patch.uri; |
| 379 for (ScriptTag tag in patch.tags.reverse()) { | 379 for (ScriptTag tag in patch.tags.reverse()) { |
| 380 if (tag.isImport()) { | 380 if (tag.isImport()) { |
| 381 StringNode argument = tag.argument; | 381 StringNode argument = tag.argument; |
| 382 Uri resolved = patchBase.resolve(argument.dartString.slowToString()); | 382 Uri resolved = patchBase.resolve(argument.dartString.slowToString()); |
| 383 LibraryElement importedLibrary = | 383 LibraryElement importedLibrary = |
| 384 scanner.loadLibrary(resolved, argument); | 384 scanner.loadLibrary(resolved, argument); |
| 385 scanner.importLibrary(original, importedLibrary, tag, patch); | 385 scanner.importLibrary(original, importedLibrary, tag, |
| 386 patch.entryCompilationUnit); |
| 386 if (resolved.scheme == "dart") { | 387 if (resolved.scheme == "dart") { |
| 387 delayedPatches[resolved.path] = importedLibrary; | 388 delayedPatches[resolved.path] = importedLibrary; |
| 388 } | 389 } |
| 389 } | 390 } |
| 390 } | 391 } |
| 391 | 392 |
| 392 // Mark library as already patched. | 393 // Mark library as already patched. |
| 393 original.patch = patch; | 394 original.patch = patch; |
| 394 | 395 |
| 395 // We patch imported libraries after marking the current library as | 396 // We patch imported libraries after marking the current library as |
| 396 // patched, to avoid problems with cyclic dependencies. | 397 // patched, to avoid problems with cyclic dependencies. |
| 397 delayedPatches.forEach((String path, LibraryElement importedLibrary) { | 398 delayedPatches.forEach((String path, LibraryElement importedLibrary) { |
| 398 patchDartLibrary(importedLibrary, path); | 399 patchDartLibrary(importedLibrary, path); |
| 399 }); | 400 }); |
| 400 } | 401 } |
| 401 | 402 |
| 402 void applyContainerPatch(ContainerElement original, Link<Element> patches, | 403 void applyContainerPatch(ScopeContainerElement original, |
| 403 Element lookup(SourceString name)) { | 404 Link<Element> patches) { |
| 404 while (!patches.isEmpty()) { | 405 while (!patches.isEmpty()) { |
| 405 Element patchElement = patches.head; | 406 Element patchElement = patches.head; |
| 406 Element originalElement = lookup(patchElement.name); | 407 Element originalElement = original.localLookup(patchElement.name); |
| 407 if (patchElement.isAccessor()) { | 408 if (patchElement.isAccessor()) { |
| 408 // Skip accessors. An accessor always has an abstract field, | 409 // Skip accessors. An accessor always has an abstract field, |
| 409 // representing the accessor in the lookup scope. We can thus skip the | 410 // representing the accessor in the lookup scope. We can thus skip the |
| 410 // accessors and just handle the abstract field. | 411 // accessors and just handle the abstract field. |
| 411 } else if (patchElement.kind === ElementKind.ABSTRACT_FIELD) { | 412 } else if (patchElement.kind === ElementKind.ABSTRACT_FIELD) { |
| 412 // Getters and setters are kept inside a synthetic field. | 413 // Getters and setters are kept inside a synthetic field. |
| 413 if (originalElement !== null && | 414 if (originalElement !== null && |
| 414 originalElement.kind !== ElementKind.ABSTRACT_FIELD) { | 415 originalElement.kind !== ElementKind.ABSTRACT_FIELD) { |
| 415 internalError("Cannot patch non-getter/setter with getter/setter", | 416 internalError("Cannot patch non-getter/setter with getter/setter", |
| 416 element: originalElement); | 417 element: originalElement); |
| 417 } | 418 } |
| 418 AbstractFieldElement patchField = patchElement; | 419 AbstractFieldElement patchField = patchElement; |
| 419 AbstractFieldElement originalField = originalElement; | 420 AbstractFieldElement originalField = originalElement; |
| 420 if (patchField.getter !== null) { | 421 if (patchField.getter !== null) { |
| 421 if (originalField === null || originalField.getter === null) { | 422 if (originalField === null || originalField.getter === null) { |
| 422 original.addGetterOrSetter(clonePatch(patchField.getter), | 423 original.addGetterOrSetter(clonePatch(patchField.getter), |
| 423 originalField, | 424 originalField, |
| 424 this); | 425 this); |
| 425 if (originalField === null && patchField.setter !== null) { | 426 if (originalField === null && patchField.setter !== null) { |
| 426 // It exists now, so find it for the setter patching. | 427 // It exists now, so find it for the setter patching. |
| 427 originalField = lookup(patchElement.name); | 428 originalField = original.localLookup(patchElement.name); |
| 428 } | 429 } |
| 429 } else { | 430 } else { |
| 430 patchMember(originalField.getter, patchField.getter); | 431 patchMember(originalField.getter, patchField.getter); |
| 431 } | 432 } |
| 432 } | 433 } |
| 433 if (patchField.setter !== null) { | 434 if (patchField.setter !== null) { |
| 434 if (originalField === null || originalField.setter === null) { | 435 if (originalField === null || originalField.setter === null) { |
| 435 original.addGetterOrSetter(clonePatch(patchField.setter), | 436 original.addGetterOrSetter(clonePatch(patchField.setter), |
| 436 originalField, | 437 originalField, |
| 437 this); | 438 this); |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 528 } | 529 } |
| 529 | 530 |
| 530 void applyClassPatch(PartialClassElement original, | 531 void applyClassPatch(PartialClassElement original, |
| 531 PartialClassElement patch) { | 532 PartialClassElement patch) { |
| 532 // Eagerly parse the class so we can patch it. | 533 // Eagerly parse the class so we can patch it. |
| 533 // TODO(lrn): Perhaps find a way to delay parsing until the class is needed, | 534 // TODO(lrn): Perhaps find a way to delay parsing until the class is needed, |
| 534 // i.e., until [parseNode] is called on [original]. | 535 // i.e., until [parseNode] is called on [original]. |
| 535 ClassNode node = original.parseNode(this); | 536 ClassNode node = original.parseNode(this); |
| 536 // Parse patch class with "patch" parser. | 537 // Parse patch class with "patch" parser. |
| 537 ClassNode patchNode = patchParser.parsePatchClassNode(patch); | 538 ClassNode patchNode = patchParser.parsePatchClassNode(patch); |
| 538 Link<Element> patches = patch.members; | 539 Link<Element> patches = patch.localMembers; |
| 539 Element lookupMemberOrConstructor(SourceString name) { | 540 applyContainerPatch(original, patches); |
| 540 Element result = original.lookupLocalMember(name); | |
| 541 if (result !== null) return result; | |
| 542 return original.lookupConstructor(name); | |
| 543 } | |
| 544 applyContainerPatch(original, patches, lookupMemberOrConstructor); | |
| 545 } | 541 } |
| 546 | 542 |
| 547 /** | 543 /** |
| 548 * Get an [Uri] pointing to a patch for the dart: library with | 544 * Get an [Uri] pointing to a patch for the dart: library with |
| 549 * the given path. Returns null if there is no patch. | 545 * the given path. Returns null if there is no patch. |
| 550 */ | 546 */ |
| 551 abstract Uri resolvePatchUri(String dartLibraryPath); | 547 abstract Uri resolvePatchUri(String dartLibraryPath); |
| 552 | 548 |
| 553 /** Define the JS helper functions in the given library. */ | 549 /** Define the JS helper functions in the given library. */ |
| 554 void addForeignFunctions(LibraryElement library) { | 550 void addForeignFunctions(LibraryElement library) { |
| 555 library.define(new ForeignElement( | 551 library.addToScope(new ForeignElement( |
| 556 const SourceString('JS'), library), this); | 552 const SourceString('JS'), library), this); |
| 557 library.define(new ForeignElement( | 553 library.addToScope(new ForeignElement( |
| 558 const SourceString('UNINTERCEPTED'), library), this); | 554 const SourceString('UNINTERCEPTED'), library), this); |
| 559 library.define(new ForeignElement( | 555 library.addToScope(new ForeignElement( |
| 560 const SourceString('JS_HAS_EQUALS'), library), this); | 556 const SourceString('JS_HAS_EQUALS'), library), this); |
| 561 library.define(new ForeignElement( | 557 library.addToScope(new ForeignElement( |
| 562 const SourceString('JS_CURRENT_ISOLATE'), library), this); | 558 const SourceString('JS_CURRENT_ISOLATE'), library), this); |
| 563 library.define(new ForeignElement( | 559 library.addToScope(new ForeignElement( |
| 564 const SourceString('JS_CALL_IN_ISOLATE'), library), this); | 560 const SourceString('JS_CALL_IN_ISOLATE'), library), this); |
| 565 library.define(new ForeignElement( | 561 library.addToScope(new ForeignElement( |
| 566 const SourceString('DART_CLOSURE_TO_JS'), library), this); | 562 const SourceString('DART_CLOSURE_TO_JS'), library), this); |
| 567 } | 563 } |
| 568 | 564 |
| 569 void runCompiler(Uri uri) { | 565 void runCompiler(Uri uri) { |
| 570 scanBuiltinLibraries(); | 566 scanBuiltinLibraries(); |
| 571 mainApp = scanner.loadLibrary(uri, null); | 567 mainApp = scanner.loadLibrary(uri, null); |
| 572 final Element main = mainApp.find(MAIN); | 568 final Element main = mainApp.find(MAIN); |
| 573 if (main === null) { | 569 if (main === null) { |
| 574 reportFatalError('Could not find $MAIN', mainApp); | 570 reportFatalError('Could not find $MAIN', mainApp); |
| 575 } else { | 571 } else { |
| (...skipping 370 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 946 final endOffset = end.charOffset + end.slowCharCount; | 942 final endOffset = end.charOffset + end.slowCharCount; |
| 947 | 943 |
| 948 // [begin] and [end] might be the same for the same empty token. This | 944 // [begin] and [end] might be the same for the same empty token. This |
| 949 // happens for instance when scanning '$$'. | 945 // happens for instance when scanning '$$'. |
| 950 assert(endOffset >= beginOffset); | 946 assert(endOffset >= beginOffset); |
| 951 return f(beginOffset, endOffset); | 947 return f(beginOffset, endOffset); |
| 952 } | 948 } |
| 953 | 949 |
| 954 String toString() => 'SourceSpan($uri, $begin, $end)'; | 950 String toString() => 'SourceSpan($uri, $begin, $end)'; |
| 955 } | 951 } |
| OLD | NEW |