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 |