Index: pkg/dev_compiler/tool/input_sdk/private/js_mirrors.dart |
diff --git a/pkg/dev_compiler/tool/input_sdk/private/js_mirrors.dart b/pkg/dev_compiler/tool/input_sdk/private/js_mirrors.dart |
index 84e51430724074a80011a74c0db161f005feffaf..f87c4c9d41d72ab0459ebd47ec4da36559ae6be5 100644 |
--- a/pkg/dev_compiler/tool/input_sdk/private/js_mirrors.dart |
+++ b/pkg/dev_compiler/tool/input_sdk/private/js_mirrors.dart |
@@ -73,58 +73,71 @@ dynamic _defaultConstructorType(type) { |
typedef T _Lazy<T>(); |
+String _getNameForESSymbol(member) { |
+ // Convert private JS symbol "Symbol(_foo)" to string "_foo". |
+ var str = member.toString(); |
+ assert(str.startsWith('Symbol(') && str.endsWith(')')); |
+ return str.substring(7, str.length - 1); |
+} |
+ |
+Map _toDartMap(data) { |
+ if (data == null) return {}; |
+ var map = JS('Map', '#.map(#)', _dart, data); |
+ // Note: we recorded a map from fields/methods to their type and metadata. |
+ // The key is a string name for public members but an ES6 symbol for private |
+ // ones. That's works nicely for dynamic operations, but dart:mirrors expects |
+ // strings, so we convert back here. |
+ var privateMembers = JS('', 'Object.getOwnPropertySymbols(#)', data); |
+ for (var member in privateMembers) { |
+ var name = _getNameForESSymbol(member); |
+ map[name] = JS('', '#[#]', data, member); |
+ } |
+ return map; |
+} |
+ |
Map _getConstructors(obj) { |
List sig = JS('', '#.getConstructorSig(#)', _dart, obj); |
- if (sig == null) return {}; |
- return JS('', '#.map(#)', _dart, sig); |
+ return _toDartMap(sig); |
} |
Map _getFields(obj) { |
List sig = JS('', '#.getFieldSig(#)', _dart, obj); |
- if (sig == null) return {}; |
- return JS('', '#.map(#)', _dart, sig); |
+ return _toDartMap(sig); |
} |
Map _getMethods(obj) { |
List sig = JS('', '#.getMethodSig(#)', _dart, obj); |
- if (sig == null) return {}; |
- return JS('', '#.map(#)', _dart, sig); |
+ return _toDartMap(sig); |
} |
Map _getGetters(obj) { |
List sig = JS('', '#.getGetterSig(#)', _dart, obj); |
- if (sig == null) return {}; |
- return JS('', '#.map(#)', _dart, sig); |
+ return _toDartMap(sig); |
} |
Map _getSetters(obj) { |
List sig = JS('', '#.getSetterSig(#)', _dart, obj); |
- if (sig == null) return {}; |
- return JS('', '#.map(#)', _dart, sig); |
+ return _toDartMap(sig); |
} |
Map _getStaticFields(obj) { |
List sig = JS('', '#.getStaticFieldSig(#)', _dart, obj); |
- if (sig == null) return {}; |
- return JS('', '#.map(#)', _dart, sig); |
+ return _toDartMap(sig); |
} |
Map _getStatics(obj) { |
List sig = JS('', '#.getStaticSig(#)', _dart, obj); |
- if (sig == null) return {}; |
- return JS('', '#.map(#)', _dart, sig); |
+ return _toDartMap(sig); |
} |
Map _getStaticGetters(obj) { |
List sig = JS('', '#.getStaticGetterSig(#)', _dart, obj); |
- if (sig == null) return {}; |
- return JS('', '#.map(#)', _dart, sig); |
+ return _toDartMap(sig); |
} |
Map _getStaticSetters(obj) { |
List sig = JS('', '#.getStaticSetterSig(#)', _dart, obj); |
- if (sig == null) return {}; |
- return JS('', '#.map(#)', _dart, sig); |
+ return _toDartMap(sig); |
} |
// TODO(vsm): These methods need to validate whether we really have a |
@@ -135,7 +148,15 @@ dynamic _unwrap(obj) => JS('', '#.unwrapType(#)', _dart, obj); |
dynamic _wrap(obj) => JS('', '#.wrapType(#)', _dart, obj); |
_unimplemented(Type t, Invocation i) { |
- throw new UnimplementedError('$t.${i.memberName} unimplemented'); |
+ throw new UnimplementedError('$t.${getName(i.memberName)} unimplemented'); |
+} |
+ |
+dynamic _toJsMap(Map<Symbol, dynamic> map) { |
+ var obj = JS('', '{}'); |
+ map.forEach((Symbol key, value) { |
+ JS('', '#[#] = #', obj, getName(key), value); |
+ }); |
+ return obj; |
} |
class JsMirror implements Mirror { |
@@ -184,21 +205,41 @@ class JsInstanceMirror extends JsObjectMirror implements InstanceMirror { |
return identityHashCode(reflectee) ^ 0x36363636; |
} |
- InstanceMirror getField(Symbol symbol) { |
+ // Returns a String for public members or an ES6 symbol for private members. |
+ _getAccessor(dynamic reflectee, Symbol symbol, [List<dynamic> args, |
+ Map<Symbol, dynamic> namedArgs]) { |
var name = getName(symbol); |
+ if (!name.startsWith('_')) return name; |
+ |
+ // TODO(vsm): Ideally, we'd record ES6 symbols properly during codegen if |
+ // mirrors is enabled. Here, we're trying to recover it from the receiver |
+ // instead. |
+ // |
+ // Get private fields and members. Members are on proto. |
+ var privateMembers = JS('', 'Object.getOwnPropertySymbols(#)', reflectee) |
+ ..addAll(JS('', 'Object.getOwnPropertySymbols(#.__proto__)', reflectee)); |
+ for (var member in privateMembers) { |
+ var privateName = _getNameForESSymbol(member); |
+ if (name == privateName) return member; |
+ } |
+ return new NoSuchMethodError(reflectee, symbol, args, namedArgs); |
+ } |
+ |
+ InstanceMirror getField(Symbol symbol) { |
+ var name = _getAccessor(reflectee, symbol); |
var field = _dload(reflectee, name); |
return reflect(field); |
} |
InstanceMirror setField(Symbol symbol, Object value) { |
- var name = getName(symbol); |
+ var name = _getAccessor(reflectee, symbol); |
_dput(reflectee, name, value); |
return reflect(value); |
} |
InstanceMirror invoke(Symbol symbol, List<dynamic> args, |
[Map<Symbol, dynamic> namedArgs]) { |
- var name = getName(symbol); |
+ var name = _getAccessor(reflectee, symbol, args, namedArgs); |
if (namedArgs != null) { |
args = new List.from(args); |
args.add(_toJsMap(namedArgs)); |
@@ -207,13 +248,7 @@ class JsInstanceMirror extends JsObjectMirror implements InstanceMirror { |
return reflect(result); |
} |
- dynamic _toJsMap(Map<Symbol, dynamic> map) { |
- var obj = JS('', '{}'); |
- map.forEach((Symbol key, value) { |
- JS('', '#[#] = #', obj, getName(key), value); |
- }); |
- return obj; |
- } |
+ String toString() => "InstanceMirror on '$reflectee'"; |
} |
class JsClosureMirror extends JsInstanceMirror implements ClosureMirror { |
@@ -352,6 +387,32 @@ class JsClassMirror extends JsMirror implements ClassMirror { |
return reflect(instance); |
} |
+ // TODO(vsm): Need to check for NSM, types on accessors below. Unlike the |
+ // InstanceMirror case, there is no dynamic helper to delegate to - we never |
+ // need a dload, etc. on a static. |
+ |
+ InstanceMirror getField(Symbol symbol) { |
+ var name = getName(symbol); |
+ return reflect(JS('', '#[#]', _unwrap(_cls), name)); |
+ } |
+ |
+ InstanceMirror setField(Symbol symbol, Object value) { |
+ var name = getName(symbol); |
+ JS('', '#[#] = #', _unwrap(_cls), name, value); |
+ return reflect(value); |
+ } |
+ |
+ InstanceMirror invoke(Symbol symbol, List<dynamic> args, |
+ [Map<Symbol, dynamic> namedArgs]) { |
+ var name = getName(symbol); |
+ if (namedArgs != null) { |
+ args = new List.from(args); |
+ args.add(_toJsMap(namedArgs)); |
+ } |
+ var result = JS('', '#.#(...#)', _unwrap(_cls), name, args); |
+ return reflect(result); |
+ } |
+ |
List<ClassMirror> get superinterfaces { |
_Lazy<List<Type>> interfaceThunk = JS('', '#[dart.implements]', _unwrap(_cls)); |
if (interfaceThunk == null) { |
@@ -385,6 +446,8 @@ class JsClassMirror extends JsMirror implements ClassMirror { |
return reflectType(_wrap(JS('Type', '#.__proto__', _unwrap(_cls)))); |
} |
} |
+ |
+ String toString() => "ClassMirror on '$_cls'"; |
} |
class JsVariableMirror extends JsMirror implements VariableMirror { |
@@ -403,11 +466,15 @@ class JsVariableMirror extends JsMirror implements VariableMirror { |
: type = reflectType(t), |
metadata = new List<InstanceMirror>.unmodifiable( |
annotations.map((a) => reflect(a))); |
+ |
+ String toString() => "VariableMirror on '$_name'"; |
} |
class JsParameterMirror extends JsVariableMirror implements ParameterMirror { |
JsParameterMirror._(String name, Type t, List annotations) |
: super._(name, t, annotations); |
+ |
+ String toString() => "ParameterMirror on '$_name'"; |
} |
class JsMethodMirror extends JsMirror implements MethodMirror { |
@@ -485,4 +552,6 @@ class JsMethodMirror extends JsMirror implements MethodMirror { |
_params = new List.unmodifiable(params); |
} |
+ |
+ String toString() => "MethodMirror on '$_name'"; |
} |