Chromium Code Reviews| 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 266 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 277 throw; | 277 throw; |
| 278 } finally { | 278 } finally { |
| 279 _currentElement = old; | 279 _currentElement = old; |
| 280 } | 280 } |
| 281 } | 281 } |
| 282 | 282 |
| 283 List<CompilerTask> tasks; | 283 List<CompilerTask> tasks; |
| 284 ScannerTask scanner; | 284 ScannerTask scanner; |
| 285 DietParserTask dietParser; | 285 DietParserTask dietParser; |
| 286 ParserTask parser; | 286 ParserTask parser; |
| 287 PatchParserTask patchParser; | |
| 287 TreeValidatorTask validator; | 288 TreeValidatorTask validator; |
| 288 ResolverTask resolver; | 289 ResolverTask resolver; |
| 289 TypeCheckerTask checker; | 290 TypeCheckerTask checker; |
| 290 Backend backend; | 291 Backend backend; |
| 291 ConstantHandler constantHandler; | 292 ConstantHandler constantHandler; |
| 292 EnqueueTask enqueuer; | 293 EnqueueTask enqueuer; |
| 293 | 294 |
| 294 static final SourceString MAIN = const SourceString('main'); | 295 static final SourceString MAIN = const SourceString('main'); |
| 295 static final SourceString NO_SUCH_METHOD = const SourceString('noSuchMethod'); | 296 static final SourceString NO_SUCH_METHOD = const SourceString('noSuchMethod'); |
| 296 static final SourceString NO_SUCH_METHOD_EXCEPTION = | 297 static final SourceString NO_SUCH_METHOD_EXCEPTION = |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 316 validateUnparse = false, | 317 validateUnparse = false, |
| 317 generateSourceMap = true]) | 318 generateSourceMap = true]) |
| 318 : libraries = new Map<String, LibraryElement>(), | 319 : libraries = new Map<String, LibraryElement>(), |
| 319 world = new World(), | 320 world = new World(), |
| 320 progress = new Stopwatch.start() { | 321 progress = new Stopwatch.start() { |
| 321 namer = new Namer(this); | 322 namer = new Namer(this); |
| 322 constantHandler = new ConstantHandler(this); | 323 constantHandler = new ConstantHandler(this); |
| 323 scanner = new ScannerTask(this); | 324 scanner = new ScannerTask(this); |
| 324 dietParser = new DietParserTask(this); | 325 dietParser = new DietParserTask(this); |
| 325 parser = new ParserTask(this); | 326 parser = new ParserTask(this); |
| 327 patchParser = new PatchParserTask(this); | |
| 326 validator = new TreeValidatorTask(this); | 328 validator = new TreeValidatorTask(this); |
| 327 resolver = new ResolverTask(this); | 329 resolver = new ResolverTask(this); |
| 328 checker = new TypeCheckerTask(this); | 330 checker = new TypeCheckerTask(this); |
| 329 backend = emitJavascript ? | 331 backend = emitJavascript ? |
| 330 new JavaScriptBackend(this, generateSourceMap) : | 332 new JavaScriptBackend(this, generateSourceMap) : |
| 331 new dart_backend.DartBackend(this, validateUnparse); | 333 new dart_backend.DartBackend(this, validateUnparse); |
| 332 enqueuer = new EnqueueTask(this); | 334 enqueuer = new EnqueueTask(this); |
| 333 tasks = [scanner, dietParser, parser, resolver, checker, | 335 tasks = [scanner, dietParser, parser, resolver, checker, |
| 334 constantHandler, enqueuer]; | 336 constantHandler, enqueuer]; |
| 335 tasks.addAll(backend.tasks); | 337 tasks.addAll(backend.tasks); |
| (...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 513 initializeSpecialClasses(); | 515 initializeSpecialClasses(); |
| 514 | 516 |
| 515 patchDartLibrary(coreLibrary, 'core'); | 517 patchDartLibrary(coreLibrary, 'core'); |
| 516 patchDartLibrary(coreImplLibrary, 'coreimpl'); | 518 patchDartLibrary(coreImplLibrary, 'coreimpl'); |
| 517 } | 519 } |
| 518 | 520 |
| 519 void patchDartLibrary(LibraryElement library, String dartLibraryPath) { | 521 void patchDartLibrary(LibraryElement library, String dartLibraryPath) { |
| 520 if (library.isPatched) return; | 522 if (library.isPatched) return; |
| 521 Uri patchUri = resolvePatchUri(dartLibraryPath); | 523 Uri patchUri = resolvePatchUri(dartLibraryPath); |
| 522 if (patchUri !== null) { | 524 if (patchUri !== null) { |
| 523 // TODO(lrn): Use a different parser to allow for "patch" annotations. | 525 LibraryElement patchLibrary = |
| 524 // For now just assume everything in the patch library is a patch | 526 patchParser.loadPatchLibrary(patchUri); |
| 525 // function. | 527 // We allow foreign functions in patched libraries. |
| 526 LibraryElement patchLibrary = scanner.loadLibrary(patchUri, null); | 528 addForeignFunctions(library); // Is safe even if already added. |
| 527 applyLibraryPatch(library, patchLibrary); | 529 applyLibraryPatch(library, patchLibrary); |
| 528 } | 530 } |
| 529 } | 531 } |
| 530 | 532 |
| 531 void applyLibraryPatch(LibraryElement library, LibraryElement patch) { | 533 void applyLibraryPatch(LibraryElement original, LibraryElement patch) { |
| 532 // We allow foreign functions in patched libraries. | 534 Link<Element> patches = patch.topLevelElements; |
| 533 addForeignFunctions(library); // Is safe even if already added. | |
| 534 | 535 |
| 535 // Copy/patch top-level elements. | 536 // Copy/patch top-level elements. |
| 536 Link<Element> patches = patch.topLevelElements; | |
| 537 while (!patches.isEmpty()) { | 537 while (!patches.isEmpty()) { |
| 538 Element patchElement = patches.head; | 538 Element patchElement = patches.head; |
| 539 Element originalElement = library.elements[patchElement.name]; | 539 Element originalElement = original.elements[patchElement.name]; |
| 540 if (originalElement !== null) { | 540 // Getters and setters are kept inside a synthetic field. |
| 541 // Assume that we are patching if the original exists. | 541 if (patchElement.kind === ElementKind.ABSTRACT_FIELD) { |
| 542 if (originalElement is! FunctionElement) { | 542 if (originalElement !== null && |
| 543 // TODO(lrn): Handle class declarations too. | 543 originalElement.kind !== ElementKind.ABSTRACT_FIELD) { |
| 544 internalError("Can only patch functions", element: originalElement); | 544 internalError("Cannot patch non-getter/setter with getter/setter", |
| 545 } | |
| 546 // TODO(lrn): Abort if the original isn't marked external, when | |
| 547 // that is added to the language. | |
| 548 if (patchElement is! FunctionElement || | |
| 549 !patchSignatureMatches(originalElement, patchElement)) { | |
| 550 internalError("Can only patch functions with matching signatures", | |
| 551 element: originalElement); | 545 element: originalElement); |
| 552 } | 546 } |
| 553 applyFunctionPatch(originalElement, patchElement); | 547 AbstractFieldElement patchField = patchElement; |
| 548 AbstractFieldElement originalField = originalElement; | |
| 549 if (patchField.getter !== null) { | |
| 550 if (originalField === null || originalField.getter === null) { | |
| 551 original.addGetterOrSetter(clonePatch(patchField.getter)); | |
| 552 } else { | |
| 553 patchMember(originalField.getter, patchField.getter); | |
| 554 } | |
| 555 } | |
| 556 if (patchField.setter !== null) { | |
| 557 if (originalField === null || originalField.setter === null) { | |
| 558 original.addGetterOrSetter(clonePatch(patchField.setter)); | |
| 559 } else { | |
| 560 patchMember(originalField.setter, patchField.setter); | |
| 561 } | |
| 562 } | |
| 563 } else if (originalElement === null) { | |
| 564 original.addMember(clonePatch(patchElement)); | |
| 554 } else { | 565 } else { |
| 555 // TODO(lrn): Allow adding private elements to the original library. | 566 patchMember(originalElement, patchElement); |
| 556 } | 567 } |
| 557 patches = patches.tail; | 568 patches = patches.tail; |
| 558 } | 569 } |
| 559 | 570 |
| 560 // Copy imports. | 571 // Copy imports. |
| 561 Map<String, LibraryElement> delayedPatches = <LibraryElement>{}; | 572 Map<String, LibraryElement> delayedPatches = <LibraryElement>{}; |
| 562 Uri base = patch.script.uri; | 573 Uri patchBase = patch.script.uri; |
| 563 for (ScriptTag tag in patch.tags.reverse()) { | 574 for (ScriptTag tag in patch.tags.reverse()) { |
| 564 if (tag.isImport()) { | 575 if (tag.isImport()) { |
| 565 StringNode argument = tag.argument; | 576 StringNode argument = tag.argument; |
| 566 Uri resolved = base.resolve(argument.dartString.slowToString()); | 577 Uri resolved = patchBase.resolve(argument.dartString.slowToString()); |
| 567 LibraryElement importedLibrary = | 578 LibraryElement importedLibrary = |
| 568 scanner.loadLibrary(resolved, argument); | 579 scanner.loadLibrary(resolved, argument); |
| 569 scanner.importLibrary(library, importedLibrary, tag, patch); | 580 scanner.importLibrary(original, importedLibrary, tag, patch); |
| 570 if (resolved.scheme == "dart") { | 581 if (resolved.scheme == "dart") { |
| 571 delayedPatches[resolved.path] = importedLibrary; | 582 delayedPatches[resolved.path] = importedLibrary; |
| 572 } | 583 } |
| 573 } | 584 } |
| 574 } | 585 } |
| 586 | |
| 575 // Mark library as already patched. | 587 // Mark library as already patched. |
| 576 library.patch = patch; | 588 original.patch = patch; |
| 577 // We patch imported libraries after marking the current library as patched, | 589 |
| 578 // to avoid problems with cyclic dependencies. | 590 // We patch imported libraries after marking the current library as |
| 591 // patched, to avoid problems with cyclic dependencies. | |
| 579 delayedPatches.forEach((String path, LibraryElement importedLibrary) { | 592 delayedPatches.forEach((String path, LibraryElement importedLibrary) { |
| 580 patchDartLibrary(importedLibrary, path); | 593 patchDartLibrary(importedLibrary, path); |
| 581 }); | 594 }); |
| 582 } | 595 } |
| 583 | 596 |
| 597 Element clonePatch(Element patchElement) { | |
| 598 bool isPatch(Element element) { | |
| 599 // TODO(lrn): More checks needed if we introduce matadata for real. | |
|
Johnni Winther
2012/07/06 07:57:39
matadata -> metadata
Lasse Reichstein Nielsen
2012/07/06 10:26:23
Done.
| |
| 600 return !element.metadata.isEmpty(); | |
| 601 } | |
| 602 if (isPatch(patchElement)) { | |
| 603 internalError("Cannot patch non-existing member '" | |
| 604 "${patchElement.name.slowToString()}'."); | |
|
Johnni Winther
2012/07/06 07:57:39
I can't see the relation between 1) the element ha
Lasse Reichstein Nielsen
2012/07/06 10:26:23
This function is for copying a declaration from th
| |
| 605 | |
| 606 } | |
| 607 if (!patchElement.name.isPrivate()) { | |
| 608 internalError("Cannot add non-private member '" | |
| 609 "${patchElement.name.slowToString()}' from patch."); | |
| 610 } | |
| 611 // TODO(lrn): Create a copy of patchElement that isn't added to anything, | |
| 612 // but which takes its source from patchElement. | |
| 613 throw "Adding members from patch is unsupported"; | |
| 614 } | |
| 615 | |
| 616 void patchMember(Element originalElement, | |
| 617 Element patchElement) { | |
| 618 // originalElement isn't null. | |
| 619 bool isPatch(Element element) { | |
|
Johnni Winther
2012/07/06 07:57:39
Make a separate isPatch check to be used both in c
Lasse Reichstein Nielsen
2012/07/06 10:26:23
Done. I consider moving everything to patch-parser
| |
| 620 // TODO(lrn): More checks needed if we introduce matadata for real. | |
| 621 return !element.metadata.isEmpty(); | |
| 622 } | |
| 623 if (!isPatch(patchElement)) { | |
| 624 internalError("Cannot overwrite existing '" | |
| 625 "${originalElement.name.slowToString()}' with non-patch."); | |
| 626 } | |
| 627 if (originalElement is! FunctionElement) { | |
| 628 // TODO(lrn): Handle class declarations too. | |
| 629 internalError("Can only patch functions", element: originalElement); | |
| 630 } | |
| 631 // TODO(lrn): Abort if the original isn't marked external, when | |
| 632 // that is added to the language. | |
| 633 if (patchElement is! FunctionElement || | |
| 634 !patchSignatureMatches(originalElement, patchElement)) { | |
| 635 internalError("Can only patch functions with matching signatures", | |
| 636 element: originalElement); | |
| 637 } | |
| 638 applyFunctionPatch(originalElement, patchElement); | |
| 639 } | |
| 640 | |
| 584 bool patchSignatureMatches(FunctionElement original, FunctionElement patch) { | 641 bool patchSignatureMatches(FunctionElement original, FunctionElement patch) { |
| 585 // TODO(lrn): Check that patches actually match the signature of | 642 // TODO(lrn): Check that patches actually match the signature of |
| 586 // the function it's patching. | 643 // the function it's patching. |
| 587 return true; | 644 return true; |
| 588 } | 645 } |
| 589 | 646 |
| 590 void applyFunctionPatch(FunctionElement element, | 647 void applyFunctionPatch(FunctionElement element, |
| 591 FunctionElement patchElement) { | 648 FunctionElement patchElement) { |
| 592 // Don't just assign the patch field. This also updates the cachedNode. | 649 // Don't just assign the patch field. This also updates the cachedNode. |
| 593 if (element.isPatched) { | 650 if (element.isPatched) { |
| (...skipping 398 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 992 f(int beginOffset, int endOffset)) { | 1049 f(int beginOffset, int endOffset)) { |
| 993 final beginOffset = begin.charOffset; | 1050 final beginOffset = begin.charOffset; |
| 994 final endOffset = end.charOffset + end.slowCharCount; | 1051 final endOffset = end.charOffset + end.slowCharCount; |
| 995 | 1052 |
| 996 // [begin] and [end] might be the same for the same empty token. This | 1053 // [begin] and [end] might be the same for the same empty token. This |
| 997 // happens for instance when scanning '$$'. | 1054 // happens for instance when scanning '$$'. |
| 998 assert(endOffset >= beginOffset); | 1055 assert(endOffset >= beginOffset); |
| 999 return f(beginOffset, endOffset); | 1056 return f(beginOffset, endOffset); |
| 1000 } | 1057 } |
| 1001 } | 1058 } |
| OLD | NEW |