| 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 // Patch library for dart:mirrors. | 5 // Patch library for dart:mirrors. |
| 6 | 6 |
| 7 import 'dart:_foreign_helper' show JS; | 7 import 'dart:_foreign_helper' show JS; |
| 8 import "dart:_collection-dev" as _symbol_dev; | 8 import 'dart:_collection-dev' as _symbol_dev; |
| 9 | 9 import 'dart:_js_helper' show createInvocationMirror; |
| 10 // Yeah, seriously: mirrors in dart2js are experimental... | 10 import 'dart:_interceptors' show getInterceptor; |
| 11 const String _MIRROR_OPT_IN_MESSAGE = """ | |
| 12 | |
| 13 This program is using an experimental feature called \"mirrors\". As | |
| 14 currently implemented, mirrors do not work with minification, and will | |
| 15 cause spurious errors depending on how code was optimized. | |
| 16 | |
| 17 The authors of this program are aware of these problems and have | |
| 18 decided the thrill of using an experimental feature is outweighing the | |
| 19 risks. Furthermore, the authors of this program understand that | |
| 20 long-term, to fix the problems mentioned above, mirrors may have | |
| 21 negative impact on size and performance of Dart programs compiled to | |
| 22 JavaScript. | |
| 23 """; | |
| 24 | |
| 25 bool _mirrorsEnabled = false; | |
| 26 | 11 |
| 27 patch class MirrorSystem { | 12 patch class MirrorSystem { |
| 28 patch static String getName(Symbol symbol) { | 13 patch static String getName(Symbol symbol) => _n(symbol); |
| 29 return _symbol_dev.Symbol.getName(symbol); | |
| 30 } | |
| 31 } | 14 } |
| 32 | 15 |
| 33 /** | 16 class _MirrorSystem implements MirrorSystem { |
| 34 * Stub class for the mirror system. | |
| 35 */ | |
| 36 patch MirrorSystem currentMirrorSystem() { | |
| 37 _ensureEnabled(); | |
| 38 throw new UnsupportedError("MirrorSystem not implemented"); | |
| 39 } | 17 } |
| 40 | 18 |
| 19 String _n(Symbol symbol) => _symbol_dev.Symbol.getName(symbol); |
| 20 |
| 21 patch MirrorSystem currentMirrorSystem() => _currentMirrorSystem; |
| 22 |
| 23 final _MirrorSystem _currentMirrorSystem = new _MirrorSystem(); |
| 24 |
| 41 patch Future<MirrorSystem> mirrorSystemOf(SendPort port) { | 25 patch Future<MirrorSystem> mirrorSystemOf(SendPort port) { |
| 42 _ensureEnabled(); | |
| 43 throw new UnsupportedError("MirrorSystem not implemented"); | 26 throw new UnsupportedError("MirrorSystem not implemented"); |
| 44 } | 27 } |
| 45 | 28 |
| 46 patch InstanceMirror reflect(Object reflectee) { | 29 patch InstanceMirror reflect(Object reflectee) { |
| 47 if (!_mirrorsEnabled && (_MIRROR_OPT_IN_MESSAGE == reflectee)) { | |
| 48 // Turn on mirrors and warn that it is an experimental feature. | |
| 49 _mirrorsEnabled = true; | |
| 50 print(reflectee); | |
| 51 } | |
| 52 return new _InstanceMirror(reflectee); | 30 return new _InstanceMirror(reflectee); |
| 53 } | 31 } |
| 54 | 32 |
| 55 patch ClassMirror reflectClass(Type key) { | 33 final Expando<ClassMirror> _classMirrors = new Expando<ClassMirror>(); |
| 56 throw new UnimplementedError('reflectClass is not yet implemented' | 34 |
| 57 'in dart2js'); | 35 patch ClassMirror reflectClass(Type key) => _reflectClass(key); |
| 36 |
| 37 // TODO(ahe): This is a workaround for http://dartbug.com/10543 |
| 38 ClassMirror _reflectClass(Type key) { |
| 39 String className = '$key'; |
| 40 var constructor = Primitives.getConstructor(className); |
| 41 if (constructor == null) { |
| 42 // Probably an intercepted class. |
| 43 // TODO(ahe): How to handle intercepted classes? |
| 44 throw new UnsupportedError('Cannot find class for: $className'); |
| 45 } |
| 46 var mirror = _classMirrors[constructor]; |
| 47 if (mirror == null) { |
| 48 mirror = new _ClassMirror(className, constructor); |
| 49 _classMirrors[constructor] = mirror; |
| 50 } |
| 51 return mirror; |
| 58 } | 52 } |
| 59 | 53 |
| 60 class _InstanceMirror extends InstanceMirror { | 54 class _InstanceMirror extends InstanceMirror { |
| 61 static final Expando<ClassMirror> classMirrors = new Expando<ClassMirror>(); | |
| 62 | 55 |
| 63 final reflectee; | 56 final reflectee; |
| 64 | 57 |
| 65 _InstanceMirror(this.reflectee); | 58 _InstanceMirror(this.reflectee); |
| 66 | 59 |
| 67 bool get hasReflectee => true; | 60 bool get hasReflectee => true; |
| 68 | 61 |
| 69 ClassMirror get type { | 62 ClassMirror get type => _reflectClass(reflectee.runtimeType); |
| 70 _ensureEnabled(); | 63 |
| 71 String className = Primitives.objectTypeName(reflectee); | 64 Future<InstanceMirror> invokeAsync(Symbol memberName, |
| 72 var constructor = Primitives.getConstructor(className); | 65 List<Object> positionalArguments, |
| 73 var mirror = classMirrors[constructor]; | 66 [Map<String,Object> namedArguments]) { |
| 74 if (mirror == null) { | 67 if (namedArguments != null && !namedArguments.isEmpty) { |
| 75 mirror = new _ClassMirror(className, constructor); | 68 throw new UnsupportedError('Named arguments are not implemented'); |
| 76 classMirrors[constructor] = mirror; | |
| 77 } | 69 } |
| 78 return mirror; | 70 return |
| 71 new Future<InstanceMirror>( |
| 72 () => invoke(memberName, positionalArguments, namedArguments)); |
| 79 } | 73 } |
| 80 | 74 |
| 81 Future<InstanceMirror> invokeAsync(String memberName, | 75 InstanceMirror invoke(Symbol memberName, |
| 82 List<Object> positionalArguments, | 76 List positionalArguments, |
| 83 [Map<String,Object> namedArguments]) { | 77 [Map<Symbol,dynamic> namedArguments]) { |
| 84 _ensureEnabled(); | |
| 85 if (namedArguments != null && !namedArguments.isEmpty) { | 78 if (namedArguments != null && !namedArguments.isEmpty) { |
| 86 throw new UnsupportedError('Named arguments are not implemented'); | 79 throw new UnsupportedError('Named arguments are not implemented'); |
| 87 } | 80 } |
| 88 // Copy the list to ensure that it can safely be passed to | 81 // Copy the list to ensure that it can safely be passed to |
| 89 // JavaScript. | 82 // JavaScript. |
| 90 var jsList = new List.from(positionalArguments); | 83 var jsList = new List.from(positionalArguments); |
| 91 var mangledName = '${memberName}\$${positionalArguments.length}'; | 84 return _invoke( |
| 92 var method = JS('var', '#[#]', reflectee, mangledName); | 85 memberName, JSInvocationMirror.METHOD, |
| 93 var completer = new Completer<InstanceMirror>(); | 86 '${_n(memberName)}\$${positionalArguments.length}', jsList); |
| 94 // TODO(ahe): [Completer] or [Future] should have API to create a | 87 } |
| 95 // delayed action. Simulating with a [Timer]. | 88 |
| 96 Timer.run(() { | 89 InstanceMirror _invoke(Symbol name, |
| 97 if (JS('String', 'typeof #', method) == 'function') { | 90 int type, |
| 98 var result = | 91 String mangledName, |
| 99 JS('var', '#.apply(#, #)', method, reflectee, jsList); | 92 List arguments) { |
| 100 completer.complete(new _InstanceMirror(result)); | 93 // TODO(ahe): Get the argument names. |
| 101 } else { | 94 List<String> argumentNames = []; |
| 102 completer.completeError('not a method $memberName'); | 95 Invocation invocation = createInvocationMirror( |
| 103 } | 96 _n(name), mangledName, type, arguments, argumentNames); |
| 104 }); | 97 |
| 105 return completer.future; | 98 return new _InstanceMirror(delegate(invocation)); |
| 99 } |
| 100 |
| 101 Future<InstanceMirror> setFieldAsync(Symbol fieldName, Object value) { |
| 102 return new Future<InstanceMirror>(() => setField(fieldName, value)); |
| 103 } |
| 104 |
| 105 InstanceMirror setField(Symbol fieldName, Object arg) { |
| 106 _invoke( |
| 107 fieldName, JSInvocationMirror.SETTER, 'set\$${_n(fieldName)}', [arg]); |
| 108 return new _InstanceMirror(arg); |
| 109 } |
| 110 |
| 111 InstanceMirror getField(Symbol fieldName) { |
| 112 return _invoke( |
| 113 fieldName, JSInvocationMirror.GETTER, 'get\$${_n(fieldName)}', []); |
| 114 } |
| 115 |
| 116 Future<InstanceMirror> getFieldAsync(Symbol fieldName) { |
| 117 return new Future<InstanceMirror>(() => getField(fieldName)); |
| 106 } | 118 } |
| 107 | 119 |
| 108 delegate(Invocation invocation) { | 120 delegate(Invocation invocation) { |
| 109 return JSInvocationMirror.invokeFromMirror(invocation, reflectee); | 121 return JSInvocationMirror.invokeFromMirror(invocation, reflectee); |
| 110 } | 122 } |
| 111 | 123 |
| 112 String toString() => 'InstanceMirror($reflectee)'; | 124 String toString() => 'InstanceMirror($reflectee)'; |
| 113 } | 125 } |
| 114 | 126 |
| 115 class _ClassMirror extends ClassMirror { | 127 class _ClassMirror extends ClassMirror { |
| 116 final String _name; | 128 final String _name; |
| 117 final _jsConstructor; | 129 final _jsConstructor; |
| 118 | 130 |
| 119 _ClassMirror(this._name, this._jsConstructor) { | 131 _ClassMirror(this._name, this._jsConstructor) { |
| 120 _ensureEnabled(); | |
| 121 } | 132 } |
| 122 | 133 |
| 123 String toString() => 'ClassMirror($_name)'; | 134 String toString() => 'ClassMirror($_name)'; |
| 124 } | 135 } |
| 125 | |
| 126 _ensureEnabled() { | |
| 127 if (_mirrorsEnabled) return; | |
| 128 throw new UnsupportedError('dart:mirrors is an experimental feature'); | |
| 129 } | |
| OLD | NEW |