Index: dart/sdk/lib/_internal/compiler/implementation/lib/mirrors_patch.dart |
diff --git a/dart/sdk/lib/_internal/compiler/implementation/lib/mirrors_patch.dart b/dart/sdk/lib/_internal/compiler/implementation/lib/mirrors_patch.dart |
index dda7d3db3e087d5075e8c1740cc14e0792194f11..f37769d7ff3892488348718c386dd448caa3c4d1 100644 |
--- a/dart/sdk/lib/_internal/compiler/implementation/lib/mirrors_patch.dart |
+++ b/dart/sdk/lib/_internal/compiler/implementation/lib/mirrors_patch.dart |
@@ -5,60 +5,50 @@ |
// Patch library for dart:mirrors. |
import 'dart:_foreign_helper' show JS; |
-import "dart:_collection-dev" as _symbol_dev; |
- |
-// Yeah, seriously: mirrors in dart2js are experimental... |
-const String _MIRROR_OPT_IN_MESSAGE = """ |
- |
-This program is using an experimental feature called \"mirrors\". As |
-currently implemented, mirrors do not work with minification, and will |
-cause spurious errors depending on how code was optimized. |
- |
-The authors of this program are aware of these problems and have |
-decided the thrill of using an experimental feature is outweighing the |
-risks. Furthermore, the authors of this program understand that |
-long-term, to fix the problems mentioned above, mirrors may have |
-negative impact on size and performance of Dart programs compiled to |
-JavaScript. |
-"""; |
- |
-bool _mirrorsEnabled = false; |
+import 'dart:_collection-dev' as _symbol_dev; |
+import 'dart:_js_helper' show createInvocationMirror; |
+import 'dart:_interceptors' show getInterceptor; |
patch class MirrorSystem { |
- patch static String getName(Symbol symbol) { |
- return _symbol_dev.Symbol.getName(symbol); |
- } |
+ patch static String getName(Symbol symbol) => _n(symbol); |
} |
-/** |
- * Stub class for the mirror system. |
- */ |
-patch MirrorSystem currentMirrorSystem() { |
- _ensureEnabled(); |
- throw new UnsupportedError("MirrorSystem not implemented"); |
+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
|
} |
+String _n(Symbol symbol) => _symbol_dev.Symbol.getName(symbol); |
+ |
+patch MirrorSystem currentMirrorSystem() => _currentMirrorSystem; |
+ |
+_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'
|
+ |
patch Future<MirrorSystem> mirrorSystemOf(SendPort port) { |
- _ensureEnabled(); |
throw new UnsupportedError("MirrorSystem not implemented"); |
} |
patch InstanceMirror reflect(Object reflectee) { |
- if (!_mirrorsEnabled && (_MIRROR_OPT_IN_MESSAGE == reflectee)) { |
- // Turn on mirrors and warn that it is an experimental feature. |
- _mirrorsEnabled = true; |
- print(reflectee); |
- } |
return new _InstanceMirror(reflectee); |
} |
+final Expando<ClassMirror> _classMirrors = new Expando<ClassMirror>(); |
+ |
patch ClassMirror reflectClass(Type key) { |
- throw new UnimplementedError('reflectClass is not yet implemented' |
- 'in dart2js'); |
+ String className = '$key'; |
+ var constructor = Primitives.getConstructor(className); |
+ if (constructor == null) { |
+ // Probably an incepted class. |
ngeoffray
2013/05/08 12:34:06
intercepted
|
+ // TODO(ahe): How to handle intercepted classes? |
+ 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
|
+ } |
+ var mirror = _classMirrors[constructor]; |
+ if (mirror == null) { |
+ mirror = new _ClassMirror(className, constructor); |
+ _classMirrors[constructor] = mirror; |
+ } |
+ return mirror; |
} |
class _InstanceMirror extends InstanceMirror { |
- static final Expando<ClassMirror> classMirrors = new Expando<ClassMirror>(); |
final reflectee; |
@@ -66,43 +56,62 @@ class _InstanceMirror extends InstanceMirror { |
bool get hasReflectee => true; |
- ClassMirror get type { |
- _ensureEnabled(); |
- String className = Primitives.objectTypeName(reflectee); |
- var constructor = Primitives.getConstructor(className); |
- var mirror = classMirrors[constructor]; |
- if (mirror == null) { |
- mirror = new _ClassMirror(className, constructor); |
- classMirrors[constructor] = mirror; |
- } |
- return mirror; |
- } |
+ 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
|
- Future<InstanceMirror> invokeAsync(String memberName, |
+ Future<InstanceMirror> invokeAsync(Symbol memberName, |
List<Object> positionalArguments, |
[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
|
- _ensureEnabled(); |
+ if (namedArguments != null && !namedArguments.isEmpty) { |
+ throw new UnsupportedError('Named arguments are not implemented'); |
+ } |
+ return |
+ new Future<InstanceMirror>( |
+ () => invoke(memberName, positionalArguments, namedArguments)); |
+ } |
+ |
+ InstanceMirror invoke(Symbol memberName, |
+ List positionalArguments, |
+ [Map<Symbol,dynamic> namedArguments]) { |
if (namedArguments != null && !namedArguments.isEmpty) { |
throw new UnsupportedError('Named arguments are not implemented'); |
} |
// Copy the list to ensure that it can safely be passed to |
// JavaScript. |
var jsList = new List.from(positionalArguments); |
- var mangledName = '${memberName}\$${positionalArguments.length}'; |
- var method = JS('var', '#[#]', reflectee, mangledName); |
- var completer = new Completer<InstanceMirror>(); |
- // TODO(ahe): [Completer] or [Future] should have API to create a |
- // delayed action. Simulating with a [Timer]. |
- Timer.run(() { |
- if (JS('String', 'typeof #', method) == 'function') { |
- var result = |
- JS('var', '#.apply(#, #)', method, reflectee, jsList); |
- completer.complete(new _InstanceMirror(result)); |
- } else { |
- completer.completeError('not a method $memberName'); |
- } |
- }); |
- return completer.future; |
+ return _invoke( |
+ memberName, JSInvocationMirror.METHOD, |
+ '${_n(memberName)}\$${positionalArguments.length}', jsList); |
+ } |
+ |
+ InstanceMirror _invoke(Symbol name, |
+ int type, |
+ String mangledName, |
+ List arguments) { |
+ // TODO(ahe): Get the argument names. |
+ List<String> argumentNames = []; |
+ Invocation invocation = createInvocationMirror( |
+ _n(name), mangledName, type, arguments, argumentNames); |
+ |
+ return new _InstanceMirror(delegate(invocation)); |
+ } |
+ |
+ Future<InstanceMirror> setFieldAsync(Symbol fieldName, Object value) { |
+ return new Future<InstanceMirror>(() => setField(fieldName, value)); |
+ } |
+ |
+ InstanceMirror setField(Symbol fieldName, Object arg) { |
+ _invoke( |
+ 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
|
+ return new _InstanceMirror(arg); |
+ } |
+ |
+ InstanceMirror getField(Symbol fieldName) { |
+ return _invoke( |
+ fieldName, JSInvocationMirror.GETTER, 'get\$${_n(fieldName)}', []); |
Johnni Winther
2013/05/08 08:22:08
Ditto.
|
+ } |
+ |
+ Future<InstanceMirror> getFieldAsync(Symbol fieldName) { |
+ return new Future<InstanceMirror>(() => getField(fieldName)); |
} |
delegate(Invocation invocation) { |
@@ -117,13 +126,7 @@ class _ClassMirror extends ClassMirror { |
final _jsConstructor; |
_ClassMirror(this._name, this._jsConstructor) { |
- _ensureEnabled(); |
} |
String toString() => 'ClassMirror($_name)'; |
} |
- |
-_ensureEnabled() { |
- if (_mirrorsEnabled) return; |
- throw new UnsupportedError('dart:mirrors is an experimental feature'); |
-} |