| 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 * This library contains the infrastructure to parse and integrate patch files. | 6 * This library contains the infrastructure to parse and integrate patch files. |
| 7 * | 7 * |
| 8 * Three types of elements can be patched: [LibraryElement], [ClassElement], | 8 * Three types of elements can be patched: [LibraryElement], [ClassElement], |
| 9 * [FunctionElement]. Patches are introduced in patch libraries which are loaded | 9 * [FunctionElement]. Patches are introduced in patch libraries which are loaded |
| 10 * together with the corresponding origin library. Which libraries that are | 10 * together with the corresponding origin library. Which libraries that are |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 109 * - Builders shift between declaration and implementation depending on usages. | 109 * - Builders shift between declaration and implementation depending on usages. |
| 110 * - Compile-time constants use constructor implementation exclusively. | 110 * - Compile-time constants use constructor implementation exclusively. |
| 111 * - Work on function parameters is performed on the declaration of the function | 111 * - Work on function parameters is performed on the declaration of the function |
| 112 * element. | 112 * element. |
| 113 */ | 113 */ |
| 114 | 114 |
| 115 library dart2js.patchparser; | 115 library dart2js.patchparser; |
| 116 | 116 |
| 117 import 'dart:async'; | 117 import 'dart:async'; |
| 118 | 118 |
| 119 import 'package:front_end/src/fasta/parser.dart' |
| 120 show Listener, Parser, ParserError; |
| 121 import 'package:front_end/src/fasta/scanner.dart' show Token; |
| 122 |
| 119 import 'common/tasks.dart' show CompilerTask; | 123 import 'common/tasks.dart' show CompilerTask; |
| 120 import 'common.dart'; | 124 import 'common.dart'; |
| 121 import 'compiler.dart' show Compiler; | 125 import 'compiler.dart' show Compiler; |
| 122 import 'constants/values.dart' show ConstantValue; | 126 import 'constants/values.dart' show ConstantValue; |
| 123 import 'elements/resolution_types.dart' show ResolutionDartType; | 127 import 'elements/resolution_types.dart' show ResolutionDartType; |
| 124 import 'elements/elements.dart'; | 128 import 'elements/elements.dart'; |
| 125 import 'elements/modelx.dart' | 129 import 'elements/modelx.dart' |
| 126 show | 130 show |
| 127 BaseFunctionElementX, | 131 BaseFunctionElementX, |
| 128 ClassElementX, | 132 ClassElementX, |
| 129 GetterElementX, | 133 GetterElementX, |
| 130 LibraryElementX, | 134 LibraryElementX, |
| 131 MetadataAnnotationX, | 135 MetadataAnnotationX, |
| 132 SetterElementX; | 136 SetterElementX; |
| 133 import 'id_generator.dart'; | 137 import 'id_generator.dart'; |
| 134 import 'js_backend/js_backend.dart' show JavaScriptBackend; | |
| 135 import 'library_loader.dart' show LibraryLoader; | 138 import 'library_loader.dart' show LibraryLoader; |
| 136 import 'parser/element_listener.dart' show ElementListener; | 139 import 'parser/element_listener.dart' show ElementListener; |
| 137 import 'package:front_end/src/fasta/parser.dart' | |
| 138 show Listener, Parser, ParserError; | |
| 139 import 'parser/member_listener.dart' show MemberListener; | 140 import 'parser/member_listener.dart' show MemberListener; |
| 140 import 'parser/partial_elements.dart' | 141 import 'parser/partial_elements.dart' |
| 141 show ClassElementParser, PartialClassElement; | 142 show ClassElementParser, PartialClassElement; |
| 143 import 'parser/diet_parser_task.dart' show PartialParser; |
| 142 import 'script.dart'; | 144 import 'script.dart'; |
| 143 import 'package:front_end/src/fasta/scanner.dart' show StringToken, Token; | |
| 144 import 'parser/diet_parser_task.dart' show PartialParser; | |
| 145 | 145 |
| 146 class PatchParserTask extends CompilerTask { | 146 class PatchParserTask extends CompilerTask { |
| 147 final String name = "Patching Parser"; | 147 final String name = "Patching Parser"; |
| 148 final Compiler compiler; | 148 final Compiler compiler; |
| 149 DiagnosticReporter get reporter => compiler.reporter; | 149 DiagnosticReporter get reporter => compiler.reporter; |
| 150 | 150 |
| 151 PatchParserTask(Compiler compiler) | 151 PatchParserTask(Compiler compiler) |
| 152 : compiler = compiler, | 152 : compiler = compiler, |
| 153 super(compiler.measurer); | 153 super(compiler.measurer); |
| 154 | 154 |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 } | 326 } |
| 327 patchClass(compiler, reporter, origin, patch); | 327 patchClass(compiler, reporter, origin, patch); |
| 328 } | 328 } |
| 329 | 329 |
| 330 void patchClass(Compiler compiler, DiagnosticReporter reporter, | 330 void patchClass(Compiler compiler, DiagnosticReporter reporter, |
| 331 ClassElementX origin, ClassElementX patch) { | 331 ClassElementX origin, ClassElementX patch) { |
| 332 if (origin.isPatched) { | 332 if (origin.isPatched) { |
| 333 reporter.internalError(origin, "Patching the same class more than once."); | 333 reporter.internalError(origin, "Patching the same class more than once."); |
| 334 } | 334 } |
| 335 origin.applyPatch(patch); | 335 origin.applyPatch(patch); |
| 336 checkNativeAnnotation(compiler, patch); | |
| 337 } | |
| 338 | |
| 339 /// Check whether [cls] has a `@Native(...)` annotation, and if so, set its | |
| 340 /// native name from the annotation. | |
| 341 checkNativeAnnotation(Compiler compiler, ClassElement cls) { | |
| 342 EagerAnnotationHandler.checkAnnotation( | |
| 343 compiler, cls, const NativeAnnotationHandler()); | |
| 344 } | |
| 345 | |
| 346 checkJsInteropAnnotation(Compiler compiler, element) { | |
| 347 EagerAnnotationHandler.checkAnnotation( | |
| 348 compiler, element, const JsInteropAnnotationHandler()); | |
| 349 } | 336 } |
| 350 | 337 |
| 351 /// Abstract interface for pre-resolution detection of metadata. | 338 /// Abstract interface for pre-resolution detection of metadata. |
| 352 /// | 339 /// |
| 353 /// The detection is handled in two steps: | 340 /// The detection is handled in two steps: |
| 354 /// - match the annotation syntactically and assume that the annotation is valid | 341 /// - match the annotation syntactically and assume that the annotation is valid |
| 355 /// if it looks correct, | 342 /// if it looks correct, |
| 356 /// - setup a deferred action to check that the annotation has a valid constant | 343 /// - setup a deferred action to check that the annotation has a valid constant |
| 357 /// value and report an internal error if not. | 344 /// value and report an internal error if not. |
| 358 abstract class EagerAnnotationHandler<T> { | 345 abstract class EagerAnnotationHandler<T> { |
| 346 const EagerAnnotationHandler(); |
| 347 |
| 359 /// Checks that [annotation] looks like a matching annotation and optionally | 348 /// Checks that [annotation] looks like a matching annotation and optionally |
| 360 /// applies actions on [element]. Returns a non-null annotation marker if the | 349 /// applies actions on [element]. Returns a non-null annotation marker if the |
| 361 /// annotation matched and should be validated. | 350 /// annotation matched and should be validated. |
| 362 T apply(Compiler compiler, Element element, MetadataAnnotation annotation); | 351 T apply(Compiler compiler, Element element, MetadataAnnotation annotation); |
| 363 | 352 |
| 364 /// Checks that the annotation value is valid. | 353 /// Checks that the annotation value is valid. |
| 365 void validate(Compiler compiler, Element element, | 354 void validate(Compiler compiler, Element element, |
| 366 MetadataAnnotation annotation, ConstantValue constant); | 355 MetadataAnnotation annotation, ConstantValue constant); |
| 367 | 356 |
| 368 /// Checks [element] for metadata matching the [handler]. Return a non-null | 357 /// Checks [element] for metadata matching the [handler]. Return a non-null |
| 369 /// annotation marker matching metadata was found. | 358 /// annotation marker matching metadata was found. |
| 370 static checkAnnotation( | 359 static T checkAnnotation<T>( |
| 371 Compiler compiler, Element element, EagerAnnotationHandler handler) { | 360 Compiler compiler, Element element, EagerAnnotationHandler<T> handler) { |
| 372 for (MetadataAnnotation annotation in element.implementation.metadata) { | 361 for (MetadataAnnotation annotation in element.implementation.metadata) { |
| 373 var result = handler.apply(compiler, element, annotation); | 362 T result = handler.apply(compiler, element, annotation); |
| 374 if (result != null) { | 363 if (result != handler.defaultResult) { |
| 375 // TODO(johnniwinther): Perform this check in | 364 // TODO(johnniwinther): Perform this check in |
| 376 // [Compiler.onLibrariesLoaded]. | 365 // [Compiler.onLibrariesLoaded]. |
| 377 compiler.enqueuer.resolution.addDeferredAction(element, () { | 366 compiler.enqueuer.resolution.addDeferredAction(element, () { |
| 378 annotation.ensureResolved(compiler.resolution); | 367 annotation.ensureResolved(compiler.resolution); |
| 379 handler.validate(compiler, element, annotation, | 368 handler.validate(compiler, element, annotation, |
| 380 compiler.constants.getConstantValue(annotation.constant)); | 369 compiler.constants.getConstantValue(annotation.constant)); |
| 381 }); | 370 }); |
| 382 return result; | 371 return result; |
| 383 } | 372 } |
| 384 } | 373 } |
| 385 return null; | 374 return handler.defaultResult; |
| 386 } | |
| 387 } | |
| 388 | |
| 389 /// Annotation handler for pre-resolution detection of `@Native(...)` | |
| 390 /// annotations. | |
| 391 class NativeAnnotationHandler implements EagerAnnotationHandler<String> { | |
| 392 const NativeAnnotationHandler(); | |
| 393 | |
| 394 String getNativeAnnotation(MetadataAnnotationX annotation) { | |
| 395 if (annotation.beginToken != null && | |
| 396 annotation.beginToken.next.value == 'Native') { | |
| 397 // Skipping '@', 'Native', and '('. | |
| 398 Token argument = annotation.beginToken.next.next.next; | |
| 399 if (argument is StringToken) { | |
| 400 return argument.value; | |
| 401 } | |
| 402 } | |
| 403 return null; | |
| 404 } | 375 } |
| 405 | 376 |
| 406 String apply( | 377 /// Result that signals the absence of annotations. |
| 407 Compiler compiler, Element element, MetadataAnnotation annotation) { | 378 T get defaultResult => null; |
| 408 if (element.isClass) { | |
| 409 String native = getNativeAnnotation(annotation); | |
| 410 if (native != null) { | |
| 411 JavaScriptBackend backend = compiler.backend; | |
| 412 backend.nativeClassDataBuilder.setNativeClassTagInfo(element, native); | |
| 413 return native; | |
| 414 } | |
| 415 } | |
| 416 return null; | |
| 417 } | |
| 418 | |
| 419 void validate(Compiler compiler, Element element, | |
| 420 MetadataAnnotation annotation, ConstantValue constant) { | |
| 421 ResolutionDartType annotationType = | |
| 422 constant.getType(compiler.commonElements); | |
| 423 if (annotationType.element != | |
| 424 compiler.backend.helpers.nativeAnnotationClass) { | |
| 425 DiagnosticReporter reporter = compiler.reporter; | |
| 426 reporter.internalError(annotation, 'Invalid @Native(...) annotation.'); | |
| 427 } | |
| 428 } | |
| 429 } | |
| 430 | |
| 431 /// Annotation handler for pre-resolution detection of `@JS(...)` | |
| 432 /// annotations. | |
| 433 class JsInteropAnnotationHandler implements EagerAnnotationHandler<bool> { | |
| 434 const JsInteropAnnotationHandler(); | |
| 435 | |
| 436 bool hasJsNameAnnotation(MetadataAnnotationX annotation) => | |
| 437 annotation.beginToken != null && annotation.beginToken.next.value == 'JS'; | |
| 438 | |
| 439 bool apply( | |
| 440 Compiler compiler, Element element, MetadataAnnotation annotation) { | |
| 441 bool hasJsInterop = hasJsNameAnnotation(annotation); | |
| 442 if (hasJsInterop) { | |
| 443 JavaScriptBackend backend = compiler.backend; | |
| 444 backend.nativeClassDataBuilder.markAsJsInterop(element); | |
| 445 } | |
| 446 // Due to semantics of apply in the baseclass we have to return null to | |
| 447 // indicate that no match was found. | |
| 448 return hasJsInterop ? true : null; | |
| 449 } | |
| 450 | |
| 451 @override | |
| 452 void validate(Compiler compiler, Element element, | |
| 453 MetadataAnnotation annotation, ConstantValue constant) { | |
| 454 JavaScriptBackend backend = compiler.backend; | |
| 455 ResolutionDartType type = constant.getType(compiler.commonElements); | |
| 456 if (type.element != backend.helpers.jsAnnotationClass) { | |
| 457 compiler.reporter | |
| 458 .internalError(annotation, 'Invalid @JS(...) annotation.'); | |
| 459 } | |
| 460 } | |
| 461 } | 379 } |
| 462 | 380 |
| 463 /// Annotation handler for pre-resolution detection of `@patch` annotations. | 381 /// Annotation handler for pre-resolution detection of `@patch` annotations. |
| 464 class PatchAnnotationHandler implements EagerAnnotationHandler<PatchVersion> { | 382 class PatchAnnotationHandler extends EagerAnnotationHandler<PatchVersion> { |
| 465 const PatchAnnotationHandler(); | 383 const PatchAnnotationHandler(); |
| 466 | 384 |
| 467 PatchVersion getPatchVersion(MetadataAnnotationX annotation) { | 385 PatchVersion getPatchVersion(MetadataAnnotationX annotation) { |
| 468 if (annotation.beginToken != null) { | 386 if (annotation.beginToken != null) { |
| 469 if (annotation.beginToken.next.value == 'patch') { | 387 if (annotation.beginToken.next.value == 'patch') { |
| 470 return const PatchVersion(null); | 388 return const PatchVersion(null); |
| 471 } else if (annotation.beginToken.next.value == 'patch_full') { | 389 } else if (annotation.beginToken.next.value == 'patch_full') { |
| 472 return const PatchVersion('full'); | 390 return const PatchVersion('full'); |
| 473 } else if (annotation.beginToken.next.value == 'patch_lazy') { | 391 } else if (annotation.beginToken.next.value == 'patch_lazy') { |
| 474 return const PatchVersion('lazy'); | 392 return const PatchVersion('lazy'); |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 607 | 525 |
| 608 class PatchVersion { | 526 class PatchVersion { |
| 609 final String tag; | 527 final String tag; |
| 610 | 528 |
| 611 const PatchVersion(this.tag); | 529 const PatchVersion(this.tag); |
| 612 | 530 |
| 613 bool isActive(String patchTag) => tag == null || tag == patchTag; | 531 bool isActive(String patchTag) => tag == null || tag == patchTag; |
| 614 | 532 |
| 615 String toString() => 'PatchVersion($tag)'; | 533 String toString() => 'PatchVersion($tag)'; |
| 616 } | 534 } |
| OLD | NEW |