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