OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, 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 library dart._js_mirrors; | 5 library dart._js_mirrors; |
6 | 6 |
7 import 'dart:mirrors'; | 7 import 'dart:mirrors'; |
8 import 'dart:_foreign_helper' show JS; | 8 import 'dart:_foreign_helper' show JS; |
9 import 'dart:_internal' as _internal; | 9 import 'dart:_internal' as _internal; |
10 | 10 |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
66 dynamic _getGenericArgs(obj) { | 66 dynamic _getGenericArgs(obj) { |
67 return JS('', '#.getGenericArgs(#)', _dart, obj); | 67 return JS('', '#.getGenericArgs(#)', _dart, obj); |
68 } | 68 } |
69 | 69 |
70 dynamic _defaultConstructorType(type) { | 70 dynamic _defaultConstructorType(type) { |
71 return JS('', '#.definiteFunctionType(#, [])', _dart, type); | 71 return JS('', '#.definiteFunctionType(#, [])', _dart, type); |
72 } | 72 } |
73 | 73 |
74 typedef T _Lazy<T>(); | 74 typedef T _Lazy<T>(); |
75 | 75 |
| 76 String _getNameForESSymbol(member) { |
| 77 // Convert private JS symbol "Symbol(_foo)" to string "_foo". |
| 78 var str = member.toString(); |
| 79 assert(str.startsWith('Symbol(') && str.endsWith(')')); |
| 80 return str.substring(7, str.length - 1); |
| 81 } |
| 82 |
| 83 Map _toDartMap(data) { |
| 84 if (data == null) return {}; |
| 85 var map = JS('Map', '#.map(#)', _dart, data); |
| 86 // Note: we recorded a map from fields/methods to their type and metadata. |
| 87 // The key is a string name for public members but an ES6 symbol for private |
| 88 // ones. That's works nicely for dynamic operations, but dart:mirrors expects |
| 89 // strings, so we convert back here. |
| 90 var privateMembers = JS('', 'Object.getOwnPropertySymbols(#)', data); |
| 91 for (var member in privateMembers) { |
| 92 var name = _getNameForESSymbol(member); |
| 93 map[name] = JS('', '#[#]', data, member); |
| 94 } |
| 95 return map; |
| 96 } |
| 97 |
76 Map _getConstructors(obj) { | 98 Map _getConstructors(obj) { |
77 List sig = JS('', '#.getConstructorSig(#)', _dart, obj); | 99 List sig = JS('', '#.getConstructorSig(#)', _dart, obj); |
78 if (sig == null) return {}; | 100 return _toDartMap(sig); |
79 return JS('', '#.map(#)', _dart, sig); | |
80 } | 101 } |
81 | 102 |
82 Map _getFields(obj) { | 103 Map _getFields(obj) { |
83 List sig = JS('', '#.getFieldSig(#)', _dart, obj); | 104 List sig = JS('', '#.getFieldSig(#)', _dart, obj); |
84 if (sig == null) return {}; | 105 return _toDartMap(sig); |
85 return JS('', '#.map(#)', _dart, sig); | |
86 } | 106 } |
87 | 107 |
88 Map _getMethods(obj) { | 108 Map _getMethods(obj) { |
89 List sig = JS('', '#.getMethodSig(#)', _dart, obj); | 109 List sig = JS('', '#.getMethodSig(#)', _dart, obj); |
90 if (sig == null) return {}; | 110 return _toDartMap(sig); |
91 return JS('', '#.map(#)', _dart, sig); | |
92 } | 111 } |
93 | 112 |
94 Map _getGetters(obj) { | 113 Map _getGetters(obj) { |
95 List sig = JS('', '#.getGetterSig(#)', _dart, obj); | 114 List sig = JS('', '#.getGetterSig(#)', _dart, obj); |
96 if (sig == null) return {}; | 115 return _toDartMap(sig); |
97 return JS('', '#.map(#)', _dart, sig); | |
98 } | 116 } |
99 | 117 |
100 Map _getSetters(obj) { | 118 Map _getSetters(obj) { |
101 List sig = JS('', '#.getSetterSig(#)', _dart, obj); | 119 List sig = JS('', '#.getSetterSig(#)', _dart, obj); |
102 if (sig == null) return {}; | 120 return _toDartMap(sig); |
103 return JS('', '#.map(#)', _dart, sig); | |
104 } | 121 } |
105 | 122 |
106 Map _getStaticFields(obj) { | 123 Map _getStaticFields(obj) { |
107 List sig = JS('', '#.getStaticFieldSig(#)', _dart, obj); | 124 List sig = JS('', '#.getStaticFieldSig(#)', _dart, obj); |
108 if (sig == null) return {}; | 125 return _toDartMap(sig); |
109 return JS('', '#.map(#)', _dart, sig); | |
110 } | 126 } |
111 | 127 |
112 Map _getStatics(obj) { | 128 Map _getStatics(obj) { |
113 List sig = JS('', '#.getStaticSig(#)', _dart, obj); | 129 List sig = JS('', '#.getStaticSig(#)', _dart, obj); |
114 if (sig == null) return {}; | 130 return _toDartMap(sig); |
115 return JS('', '#.map(#)', _dart, sig); | |
116 } | 131 } |
117 | 132 |
118 Map _getStaticGetters(obj) { | 133 Map _getStaticGetters(obj) { |
119 List sig = JS('', '#.getStaticGetterSig(#)', _dart, obj); | 134 List sig = JS('', '#.getStaticGetterSig(#)', _dart, obj); |
120 if (sig == null) return {}; | 135 return _toDartMap(sig); |
121 return JS('', '#.map(#)', _dart, sig); | |
122 } | 136 } |
123 | 137 |
124 Map _getStaticSetters(obj) { | 138 Map _getStaticSetters(obj) { |
125 List sig = JS('', '#.getStaticSetterSig(#)', _dart, obj); | 139 List sig = JS('', '#.getStaticSetterSig(#)', _dart, obj); |
126 if (sig == null) return {}; | 140 return _toDartMap(sig); |
127 return JS('', '#.map(#)', _dart, sig); | |
128 } | 141 } |
129 | 142 |
130 // TODO(vsm): These methods need to validate whether we really have a | 143 // TODO(vsm): These methods need to validate whether we really have a |
131 // WrappedType or a raw type that should be wrapped (as opposed to a | 144 // WrappedType or a raw type that should be wrapped (as opposed to a |
132 // function). | 145 // function). |
133 dynamic _unwrap(obj) => JS('', '#.unwrapType(#)', _dart, obj); | 146 dynamic _unwrap(obj) => JS('', '#.unwrapType(#)', _dart, obj); |
134 | 147 |
135 dynamic _wrap(obj) => JS('', '#.wrapType(#)', _dart, obj); | 148 dynamic _wrap(obj) => JS('', '#.wrapType(#)', _dart, obj); |
136 | 149 |
137 _unimplemented(Type t, Invocation i) { | 150 _unimplemented(Type t, Invocation i) { |
138 throw new UnimplementedError('$t.${i.memberName} unimplemented'); | 151 throw new UnimplementedError('$t.${getName(i.memberName)} unimplemented'); |
| 152 } |
| 153 |
| 154 dynamic _toJsMap(Map<Symbol, dynamic> map) { |
| 155 var obj = JS('', '{}'); |
| 156 map.forEach((Symbol key, value) { |
| 157 JS('', '#[#] = #', obj, getName(key), value); |
| 158 }); |
| 159 return obj; |
139 } | 160 } |
140 | 161 |
141 class JsMirror implements Mirror { | 162 class JsMirror implements Mirror { |
142 noSuchMethod(Invocation i) { | 163 noSuchMethod(Invocation i) { |
143 _unimplemented(this.runtimeType, i); | 164 _unimplemented(this.runtimeType, i); |
144 } | 165 } |
145 } | 166 } |
146 | 167 |
147 class JsCombinatorMirror extends JsMirror implements CombinatorMirror { | 168 class JsCombinatorMirror extends JsMirror implements CombinatorMirror { |
148 } | 169 } |
(...skipping 28 matching lines...) Expand all Loading... |
177 bool operator==(Object other) { | 198 bool operator==(Object other) { |
178 return (other is JsInstanceMirror) && identical(reflectee, other.reflectee); | 199 return (other is JsInstanceMirror) && identical(reflectee, other.reflectee); |
179 } | 200 } |
180 | 201 |
181 int get hashCode { | 202 int get hashCode { |
182 // Avoid hash collisions with the reflectee. This constant is in Smi range | 203 // Avoid hash collisions with the reflectee. This constant is in Smi range |
183 // and happens to be the inner padding from RFC 2104. | 204 // and happens to be the inner padding from RFC 2104. |
184 return identityHashCode(reflectee) ^ 0x36363636; | 205 return identityHashCode(reflectee) ^ 0x36363636; |
185 } | 206 } |
186 | 207 |
| 208 // Returns a String for public members or an ES6 symbol for private members. |
| 209 _getAccessor(dynamic reflectee, Symbol symbol, [List<dynamic> args, |
| 210 Map<Symbol, dynamic> namedArgs]) { |
| 211 var name = getName(symbol); |
| 212 if (!name.startsWith('_')) return name; |
| 213 |
| 214 // TODO(vsm): Ideally, we'd record ES6 symbols properly during codegen if |
| 215 // mirrors is enabled. Here, we're trying to recover it from the receiver |
| 216 // instead. |
| 217 // |
| 218 // Get private fields and members. Members are on proto. |
| 219 var privateMembers = JS('', 'Object.getOwnPropertySymbols(#)', reflectee) |
| 220 ..addAll(JS('', 'Object.getOwnPropertySymbols(#.__proto__)', reflectee)); |
| 221 for (var member in privateMembers) { |
| 222 var privateName = _getNameForESSymbol(member); |
| 223 if (name == privateName) return member; |
| 224 } |
| 225 return new NoSuchMethodError(reflectee, symbol, args, namedArgs); |
| 226 } |
| 227 |
187 InstanceMirror getField(Symbol symbol) { | 228 InstanceMirror getField(Symbol symbol) { |
188 var name = getName(symbol); | 229 var name = _getAccessor(reflectee, symbol); |
189 var field = _dload(reflectee, name); | 230 var field = _dload(reflectee, name); |
190 return reflect(field); | 231 return reflect(field); |
191 } | 232 } |
192 | 233 |
193 InstanceMirror setField(Symbol symbol, Object value) { | 234 InstanceMirror setField(Symbol symbol, Object value) { |
194 var name = getName(symbol); | 235 var name = _getAccessor(reflectee, symbol); |
195 _dput(reflectee, name, value); | 236 _dput(reflectee, name, value); |
196 return reflect(value); | 237 return reflect(value); |
197 } | 238 } |
198 | 239 |
199 InstanceMirror invoke(Symbol symbol, List<dynamic> args, | 240 InstanceMirror invoke(Symbol symbol, List<dynamic> args, |
200 [Map<Symbol, dynamic> namedArgs]) { | 241 [Map<Symbol, dynamic> namedArgs]) { |
201 var name = getName(symbol); | 242 var name = _getAccessor(reflectee, symbol, args, namedArgs); |
202 if (namedArgs != null) { | 243 if (namedArgs != null) { |
203 args = new List.from(args); | 244 args = new List.from(args); |
204 args.add(_toJsMap(namedArgs)); | 245 args.add(_toJsMap(namedArgs)); |
205 } | 246 } |
206 var result = _dsend(reflectee, name, args); | 247 var result = _dsend(reflectee, name, args); |
207 return reflect(result); | 248 return reflect(result); |
208 } | 249 } |
209 | 250 |
210 dynamic _toJsMap(Map<Symbol, dynamic> map) { | 251 String toString() => "InstanceMirror on '$reflectee'"; |
211 var obj = JS('', '{}'); | |
212 map.forEach((Symbol key, value) { | |
213 JS('', '#[#] = #', obj, getName(key), value); | |
214 }); | |
215 return obj; | |
216 } | |
217 } | 252 } |
218 | 253 |
219 class JsClosureMirror extends JsInstanceMirror implements ClosureMirror { | 254 class JsClosureMirror extends JsInstanceMirror implements ClosureMirror { |
220 JsClosureMirror._(reflectee) : super._(reflectee); | 255 JsClosureMirror._(reflectee) : super._(reflectee); |
221 | 256 |
222 InstanceMirror apply(List<dynamic> args, | 257 InstanceMirror apply(List<dynamic> args, |
223 [Map<Symbol, dynamic> namedArgs]) { | 258 [Map<Symbol, dynamic> namedArgs]) { |
224 if (namedArgs != null) { | 259 if (namedArgs != null) { |
225 args = new List.from(args); | 260 args = new List.from(args); |
226 args.add(_toJsMap(namedArgs)); | 261 args.add(_toJsMap(namedArgs)); |
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
345 [Map<Symbol, dynamic> namedArgs]) { | 380 [Map<Symbol, dynamic> namedArgs]) { |
346 // TODO(vsm): Support factory constructors and named arguments. | 381 // TODO(vsm): Support factory constructors and named arguments. |
347 var name = getName(constructorName); | 382 var name = getName(constructorName); |
348 assert(namedArgs == null || namedArgs.isEmpty); | 383 assert(namedArgs == null || namedArgs.isEmpty); |
349 var instance = (name == 'new' || name == '') | 384 var instance = (name == 'new' || name == '') |
350 ? JS('', 'new #(...#)', _unwrap(_cls), args) | 385 ? JS('', 'new #(...#)', _unwrap(_cls), args) |
351 : JS('', 'new (#.#)(...#)', _unwrap(_cls), name, args); | 386 : JS('', 'new (#.#)(...#)', _unwrap(_cls), name, args); |
352 return reflect(instance); | 387 return reflect(instance); |
353 } | 388 } |
354 | 389 |
| 390 // TODO(vsm): Need to check for NSM, types on accessors below. Unlike the |
| 391 // InstanceMirror case, there is no dynamic helper to delegate to - we never |
| 392 // need a dload, etc. on a static. |
| 393 |
| 394 InstanceMirror getField(Symbol symbol) { |
| 395 var name = getName(symbol); |
| 396 return reflect(JS('', '#[#]', _unwrap(_cls), name)); |
| 397 } |
| 398 |
| 399 InstanceMirror setField(Symbol symbol, Object value) { |
| 400 var name = getName(symbol); |
| 401 JS('', '#[#] = #', _unwrap(_cls), name, value); |
| 402 return reflect(value); |
| 403 } |
| 404 |
| 405 InstanceMirror invoke(Symbol symbol, List<dynamic> args, |
| 406 [Map<Symbol, dynamic> namedArgs]) { |
| 407 var name = getName(symbol); |
| 408 if (namedArgs != null) { |
| 409 args = new List.from(args); |
| 410 args.add(_toJsMap(namedArgs)); |
| 411 } |
| 412 var result = JS('', '#.#(...#)', _unwrap(_cls), name, args); |
| 413 return reflect(result); |
| 414 } |
| 415 |
355 List<ClassMirror> get superinterfaces { | 416 List<ClassMirror> get superinterfaces { |
356 _Lazy<List<Type>> interfaceThunk = JS('', '#[dart.implements]', _unwrap(_cls
)); | 417 _Lazy<List<Type>> interfaceThunk = JS('', '#[dart.implements]', _unwrap(_cls
)); |
357 if (interfaceThunk == null) { | 418 if (interfaceThunk == null) { |
358 return []; | 419 return []; |
359 } else { | 420 } else { |
360 List<Type> interfaces = interfaceThunk(); | 421 List<Type> interfaces = interfaceThunk(); |
361 return interfaces.map((t) => reflectType(t)).toList(); | 422 return interfaces.map((t) => reflectType(t)).toList(); |
362 } | 423 } |
363 } | 424 } |
364 | 425 |
(...skipping 13 matching lines...) Expand all Loading... |
378 throw new UnimplementedError("ClassMirror.originalDeclaration unimplemented"
); | 439 throw new UnimplementedError("ClassMirror.originalDeclaration unimplemented"
); |
379 } | 440 } |
380 | 441 |
381 ClassMirror get superclass { | 442 ClassMirror get superclass { |
382 if (_cls == Object) { | 443 if (_cls == Object) { |
383 return null; | 444 return null; |
384 } else { | 445 } else { |
385 return reflectType(_wrap(JS('Type', '#.__proto__', _unwrap(_cls)))); | 446 return reflectType(_wrap(JS('Type', '#.__proto__', _unwrap(_cls)))); |
386 } | 447 } |
387 } | 448 } |
| 449 |
| 450 String toString() => "ClassMirror on '$_cls'"; |
388 } | 451 } |
389 | 452 |
390 class JsVariableMirror extends JsMirror implements VariableMirror { | 453 class JsVariableMirror extends JsMirror implements VariableMirror { |
391 final String _name; | 454 final String _name; |
392 final TypeMirror type; | 455 final TypeMirror type; |
393 final List<InstanceMirror> metadata; | 456 final List<InstanceMirror> metadata; |
394 | 457 |
395 // TODO(vsm): Refactor this out. | 458 // TODO(vsm): Refactor this out. |
396 Symbol get simpleName => new Symbol(_name); | 459 Symbol get simpleName => new Symbol(_name); |
397 | 460 |
398 // TODO(vsm): Fix this | 461 // TODO(vsm): Fix this |
399 final bool isStatic = false; | 462 final bool isStatic = false; |
400 final bool isFinal = false; | 463 final bool isFinal = false; |
401 | 464 |
402 JsVariableMirror._(this._name, Type t, List annotations) | 465 JsVariableMirror._(this._name, Type t, List annotations) |
403 : type = reflectType(t), | 466 : type = reflectType(t), |
404 metadata = new List<InstanceMirror>.unmodifiable( | 467 metadata = new List<InstanceMirror>.unmodifiable( |
405 annotations.map((a) => reflect(a))); | 468 annotations.map((a) => reflect(a))); |
| 469 |
| 470 String toString() => "VariableMirror on '$_name'"; |
406 } | 471 } |
407 | 472 |
408 class JsParameterMirror extends JsVariableMirror implements ParameterMirror { | 473 class JsParameterMirror extends JsVariableMirror implements ParameterMirror { |
409 JsParameterMirror._(String name, Type t, List annotations) | 474 JsParameterMirror._(String name, Type t, List annotations) |
410 : super._(name, t, annotations); | 475 : super._(name, t, annotations); |
| 476 |
| 477 String toString() => "ParameterMirror on '$_name'"; |
411 } | 478 } |
412 | 479 |
413 class JsMethodMirror extends JsMirror implements MethodMirror { | 480 class JsMethodMirror extends JsMirror implements MethodMirror { |
414 // TODO(vsm): This could be a JS symbol for private methods | 481 // TODO(vsm): This could be a JS symbol for private methods |
415 final String _name; | 482 final String _name; |
416 List<ParameterMirror> _params; | 483 List<ParameterMirror> _params; |
417 List<InstanceMirror> _metadata; | 484 List<InstanceMirror> _metadata; |
418 final bool isConstructor; | 485 final bool isConstructor; |
419 final bool isStatic; | 486 final bool isStatic; |
420 | 487 |
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
478 for (var i = 0; i < opts.length; ++i) { | 545 for (var i = 0; i < opts.length; ++i) { |
479 var type = opts[i]; | 546 var type = opts[i]; |
480 var metadata = ftype.metadata[args.length + i]; | 547 var metadata = ftype.metadata[args.length + i]; |
481 // TODO(vsm): Recover the param name. | 548 // TODO(vsm): Recover the param name. |
482 var param = new JsParameterMirror._('', _wrap(type), metadata); | 549 var param = new JsParameterMirror._('', _wrap(type), metadata); |
483 params[i + args.length] = param; | 550 params[i + args.length] = param; |
484 } | 551 } |
485 | 552 |
486 _params = new List.unmodifiable(params); | 553 _params = new List.unmodifiable(params); |
487 } | 554 } |
| 555 |
| 556 String toString() => "MethodMirror on '$_name'"; |
488 } | 557 } |
OLD | NEW |