OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 part of native; | 5 part of native; |
6 | 6 |
7 /** | 7 /** |
8 * This could be an abstract class but we use it as a stub for the dart_backend. | 8 * This could be an abstract class but we use it as a stub for the dart_backend. |
9 */ | 9 */ |
10 class NativeEnqueuer { | 10 class NativeEnqueuer { |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
58 void logSummary(log(message)) {} | 58 void logSummary(log(message)) {} |
59 | 59 |
60 // Do not use annotations in dart2dart. | 60 // Do not use annotations in dart2dart. |
61 ClassElement get annotationCreatesClass => null; | 61 ClassElement get annotationCreatesClass => null; |
62 ClassElement get annotationReturnsClass => null; | 62 ClassElement get annotationReturnsClass => null; |
63 ClassElement get annotationJsNameClass => null; | 63 ClassElement get annotationJsNameClass => null; |
64 } | 64 } |
65 | 65 |
66 | 66 |
67 abstract class NativeEnqueuerBase implements NativeEnqueuer { | 67 abstract class NativeEnqueuerBase implements NativeEnqueuer { |
| 68 static final RegExp _identifier = new RegExp(r'^[a-zA-Z_$][a-zA-Z0-9_$]*$'); |
68 | 69 |
69 /** | 70 /** |
70 * The set of all native classes. Each native class is in [nativeClasses] and | 71 * The set of all native classes. Each native class is in [nativeClasses] and |
71 * exactly one of [unusedClasses], [pendingClasses] and [registeredClasses]. | 72 * exactly one of [unusedClasses], [pendingClasses] and [registeredClasses]. |
72 */ | 73 */ |
73 final Set<ClassElement> nativeClasses = new Set<ClassElement>(); | 74 final Set<ClassElement> nativeClasses = new Set<ClassElement>(); |
74 | 75 |
75 final Set<ClassElement> registeredClasses = new Set<ClassElement>(); | 76 final Set<ClassElement> registeredClasses = new Set<ClassElement>(); |
76 final Set<ClassElement> pendingClasses = new Set<ClassElement>(); | 77 final Set<ClassElement> pendingClasses = new Set<ClassElement>(); |
77 final Set<ClassElement> unusedClasses = new Set<ClassElement>(); | 78 final Set<ClassElement> unusedClasses = new Set<ClassElement>(); |
(...skipping 314 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
392 // function or a non-method property in the prototype chain, must be coded | 393 // function or a non-method property in the prototype chain, must be coded |
393 // using a JS-call. | 394 // using a JS-call. |
394 if (element.isInstanceMember) { | 395 if (element.isInstanceMember) { |
395 setNativeName(element); | 396 setNativeName(element); |
396 } | 397 } |
397 } | 398 } |
398 } | 399 } |
399 | 400 |
400 handleMethodAnnotations(Element method) { | 401 handleMethodAnnotations(Element method) { |
401 if (isNativeMethod(method)) { | 402 if (isNativeMethod(method)) { |
402 setNativeName(method); | 403 if (method.isStatic) { |
| 404 setNativeNameForStaticMethod(method); |
| 405 } else { |
| 406 setNativeName(method); |
| 407 } |
403 } | 408 } |
404 } | 409 } |
405 | 410 |
406 /// Sets the native name of [element], either from an annotation, or | 411 /// Sets the native name of [element], either from an annotation, or |
407 /// defaulting to the Dart name. | 412 /// defaulting to the Dart name. |
408 void setNativeName(Element element) { | 413 void setNativeName(Element element) { |
409 String name = findJsNameFromAnnotation(element); | 414 String name = findJsNameFromAnnotation(element); |
410 if (name == null) name = element.name; | 415 if (name == null) name = element.name; |
411 element.setNative(name); | 416 element.setNative(name); |
412 } | 417 } |
413 | 418 |
| 419 /// Sets the native name of the static native method [element], using the |
| 420 /// following rules: |
| 421 /// 1. If [element] has a @JSName annotation that is an identifier, qualify |
| 422 /// that identifier to the @Native name of the enclosing class |
| 423 /// 2. If [element] has a @JSName annotation that is not an identifier, |
| 424 /// use the declared @JSName as the expression |
| 425 /// 3. If [element] does not have a @JSName annotation, qualify the name of |
| 426 /// the method with the @Native name of the enclosing class. |
| 427 void setNativeNameForStaticMethod(Element element) { |
| 428 String name = findJsNameFromAnnotation(element); |
| 429 if (name == null) name = element.name; |
| 430 if (isIdentifier(name)) { |
| 431 List<String> nativeNames = nativeTagsOfClassRaw(element.enclosingClass); |
| 432 if (nativeNames.length != 1) { |
| 433 compiler.internalError(element, |
| 434 'Unable to determine a native name for the enclosing class, ' |
| 435 'options: $nativeNames'); |
| 436 } |
| 437 element.setNative('${nativeNames[0]}.$name'); |
| 438 } else { |
| 439 element.setNative(name); |
| 440 } |
| 441 } |
| 442 |
| 443 bool isIdentifier(String s) => _identifier.hasMatch(s); |
| 444 |
414 bool isNativeMethod(FunctionElementX element) { | 445 bool isNativeMethod(FunctionElementX element) { |
415 if (!element.library.canUseNative) return false; | 446 if (!element.library.canUseNative) return false; |
416 // Native method? | 447 // Native method? |
417 return compiler.withCurrentElement(element, () { | 448 return compiler.withCurrentElement(element, () { |
418 Node node = element.parseNode(compiler); | 449 Node node = element.parseNode(compiler); |
419 if (node is! FunctionExpression) return false; | 450 if (node is! FunctionExpression) return false; |
420 FunctionExpression functionExpression = node; | 451 FunctionExpression functionExpression = node; |
421 node = functionExpression.body; | 452 node = functionExpression.body; |
422 Token token = node.getBeginToken(); | 453 Token token = node.getBeginToken(); |
423 if (identical(token.stringValue, 'native')) return true; | 454 if (identical(token.stringValue, 'native')) return true; |
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
632 superclass, | 663 superclass, |
633 () => <ClassElement>[]); | 664 () => <ClassElement>[]); |
634 directSubtypes.add(cls); | 665 directSubtypes.add(cls); |
635 } | 666 } |
636 | 667 |
637 void logSummary(log(message)) { | 668 void logSummary(log(message)) { |
638 log('Compiled ${registeredClasses.length} native classes, ' | 669 log('Compiled ${registeredClasses.length} native classes, ' |
639 '${unusedClasses.length} native classes omitted.'); | 670 '${unusedClasses.length} native classes omitted.'); |
640 } | 671 } |
641 } | 672 } |
OLD | NEW |