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 |