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 { |
ngeoffray
2013/05/08 12:34:06
What can you do with an instance of this class?
ahe
2013/05/08 21:47:53
Not much yet. But all the tests in mirrors_test.d
| |
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 _MirrorSystem _currentMirrorSystem = new _MirrorSystem(); | |
Johnni Winther
2013/05/08 08:22:08
How about making this final so it will be created
ahe
2013/05/08 08:57:43
I think making it final is a good idea, but I don'
| |
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 |
33 final Expando<ClassMirror> _classMirrors = new Expando<ClassMirror>(); | |
34 | |
55 patch ClassMirror reflectClass(Type key) { | 35 patch ClassMirror reflectClass(Type key) { |
56 throw new UnimplementedError('reflectClass is not yet implemented' | 36 String className = '$key'; |
57 'in dart2js'); | 37 var constructor = Primitives.getConstructor(className); |
38 if (constructor == null) { | |
39 // Probably an incepted class. | |
ngeoffray
2013/05/08 12:34:06
intercepted
| |
40 // TODO(ahe): How to handle intercepted classes? | |
41 throw new UnsupportedError('Cannot find constructor for: $className'); | |
Johnni Winther
2013/05/08 08:22:08
The error message seems a bit internal. Maybe chan
ahe
2013/05/08 08:57:43
No problem, but this is a short-term solution. Th
| |
42 } | |
43 var mirror = _classMirrors[constructor]; | |
44 if (mirror == null) { | |
45 mirror = new _ClassMirror(className, constructor); | |
46 _classMirrors[constructor] = mirror; | |
47 } | |
48 return mirror; | |
58 } | 49 } |
59 | 50 |
60 class _InstanceMirror extends InstanceMirror { | 51 class _InstanceMirror extends InstanceMirror { |
61 static final Expando<ClassMirror> classMirrors = new Expando<ClassMirror>(); | |
62 | 52 |
63 final reflectee; | 53 final reflectee; |
64 | 54 |
65 _InstanceMirror(this.reflectee); | 55 _InstanceMirror(this.reflectee); |
66 | 56 |
67 bool get hasReflectee => true; | 57 bool get hasReflectee => true; |
68 | 58 |
69 ClassMirror get type { | 59 ClassMirror get type => reflectClass(reflectee.runtimeType); |
Johnni Winther
2013/05/08 08:22:08
What about reflection on [:null:]?
ahe
2013/05/08 08:57:43
The object "null" is an instance of a subclass of
| |
70 _ensureEnabled(); | 60 |
71 String className = Primitives.objectTypeName(reflectee); | 61 Future<InstanceMirror> invokeAsync(Symbol memberName, |
72 var constructor = Primitives.getConstructor(className); | 62 List<Object> positionalArguments, |
73 var mirror = classMirrors[constructor]; | 63 [Map<String,Object> namedArguments]) { |
Johnni Winther
2013/05/08 08:22:08
I think we have an inconsistency in the signatures
ahe
2013/05/08 21:47:53
I should clean this up in the VM as well, but I'd
| |
74 if (mirror == null) { | 64 if (namedArguments != null && !namedArguments.isEmpty) { |
75 mirror = new _ClassMirror(className, constructor); | 65 throw new UnsupportedError('Named arguments are not implemented'); |
76 classMirrors[constructor] = mirror; | |
77 } | 66 } |
78 return mirror; | 67 return |
68 new Future<InstanceMirror>( | |
69 () => invoke(memberName, positionalArguments, namedArguments)); | |
79 } | 70 } |
80 | 71 |
81 Future<InstanceMirror> invokeAsync(String memberName, | 72 InstanceMirror invoke(Symbol memberName, |
82 List<Object> positionalArguments, | 73 List positionalArguments, |
83 [Map<String,Object> namedArguments]) { | 74 [Map<Symbol,dynamic> namedArguments]) { |
84 _ensureEnabled(); | |
85 if (namedArguments != null && !namedArguments.isEmpty) { | 75 if (namedArguments != null && !namedArguments.isEmpty) { |
86 throw new UnsupportedError('Named arguments are not implemented'); | 76 throw new UnsupportedError('Named arguments are not implemented'); |
87 } | 77 } |
88 // Copy the list to ensure that it can safely be passed to | 78 // Copy the list to ensure that it can safely be passed to |
89 // JavaScript. | 79 // JavaScript. |
90 var jsList = new List.from(positionalArguments); | 80 var jsList = new List.from(positionalArguments); |
91 var mangledName = '${memberName}\$${positionalArguments.length}'; | 81 return _invoke( |
92 var method = JS('var', '#[#]', reflectee, mangledName); | 82 memberName, JSInvocationMirror.METHOD, |
93 var completer = new Completer<InstanceMirror>(); | 83 '${_n(memberName)}\$${positionalArguments.length}', jsList); |
94 // TODO(ahe): [Completer] or [Future] should have API to create a | 84 } |
95 // delayed action. Simulating with a [Timer]. | 85 |
96 Timer.run(() { | 86 InstanceMirror _invoke(Symbol name, |
97 if (JS('String', 'typeof #', method) == 'function') { | 87 int type, |
98 var result = | 88 String mangledName, |
99 JS('var', '#.apply(#, #)', method, reflectee, jsList); | 89 List arguments) { |
100 completer.complete(new _InstanceMirror(result)); | 90 // TODO(ahe): Get the argument names. |
101 } else { | 91 List<String> argumentNames = []; |
102 completer.completeError('not a method $memberName'); | 92 Invocation invocation = createInvocationMirror( |
103 } | 93 _n(name), mangledName, type, arguments, argumentNames); |
104 }); | 94 |
105 return completer.future; | 95 return new _InstanceMirror(delegate(invocation)); |
96 } | |
97 | |
98 Future<InstanceMirror> setFieldAsync(Symbol fieldName, Object value) { | |
99 return new Future<InstanceMirror>(() => setField(fieldName, value)); | |
100 } | |
101 | |
102 InstanceMirror setField(Symbol fieldName, Object arg) { | |
103 _invoke( | |
104 fieldName, JSInvocationMirror.SETTER, 'set\$${_n(fieldName)}', [arg]); | |
Johnni Winther
2013/05/08 08:22:08
'set\$...' doesn't work for minification, right?
ahe
2013/05/08 08:57:43
Yes. That could have been clearer. The CL descri
| |
105 return new _InstanceMirror(arg); | |
106 } | |
107 | |
108 InstanceMirror getField(Symbol fieldName) { | |
109 return _invoke( | |
110 fieldName, JSInvocationMirror.GETTER, 'get\$${_n(fieldName)}', []); | |
Johnni Winther
2013/05/08 08:22:08
Ditto.
| |
111 } | |
112 | |
113 Future<InstanceMirror> getFieldAsync(Symbol fieldName) { | |
114 return new Future<InstanceMirror>(() => getField(fieldName)); | |
106 } | 115 } |
107 | 116 |
108 delegate(Invocation invocation) { | 117 delegate(Invocation invocation) { |
109 return JSInvocationMirror.invokeFromMirror(invocation, reflectee); | 118 return JSInvocationMirror.invokeFromMirror(invocation, reflectee); |
110 } | 119 } |
111 | 120 |
112 String toString() => 'InstanceMirror($reflectee)'; | 121 String toString() => 'InstanceMirror($reflectee)'; |
113 } | 122 } |
114 | 123 |
115 class _ClassMirror extends ClassMirror { | 124 class _ClassMirror extends ClassMirror { |
116 final String _name; | 125 final String _name; |
117 final _jsConstructor; | 126 final _jsConstructor; |
118 | 127 |
119 _ClassMirror(this._name, this._jsConstructor) { | 128 _ClassMirror(this._name, this._jsConstructor) { |
120 _ensureEnabled(); | |
121 } | 129 } |
122 | 130 |
123 String toString() => 'ClassMirror($_name)'; | 131 String toString() => 'ClassMirror($_name)'; |
124 } | 132 } |
125 | |
126 _ensureEnabled() { | |
127 if (_mirrorsEnabled) return; | |
128 throw new UnsupportedError('dart:mirrors is an experimental feature'); | |
129 } | |
OLD | NEW |