| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, 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:async'; | 7 import 'dart:async'; |
| 8 import 'dart:mirrors'; | 8 import 'dart:mirrors'; |
| 9 | 9 |
| 10 import 'dart:_foreign_helper' show JS, JS_CURRENT_ISOLATE; | 10 import 'dart:_foreign_helper' show JS, JS_CURRENT_ISOLATE; |
| (...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 300 } | 300 } |
| 301 if (fields is! String) { | 301 if (fields is! String) { |
| 302 // TODO(ahe): This is CSP mode. Find a way to determine the | 302 // TODO(ahe): This is CSP mode. Find a way to determine the |
| 303 // fields of this class. | 303 // fields of this class. |
| 304 fields = ''; | 304 fields = ''; |
| 305 } | 305 } |
| 306 } | 306 } |
| 307 var mirror = classMirrors[constructorOrInterceptor]; | 307 var mirror = classMirrors[constructorOrInterceptor]; |
| 308 if (mirror == null) { | 308 if (mirror == null) { |
| 309 mirror = new JsClassMirror( | 309 mirror = new JsClassMirror( |
| 310 symbol, constructorOrInterceptor, fields, fieldsMetadata); | 310 symbol, mangledName, constructorOrInterceptor, fields, fieldsMetadata); |
| 311 classMirrors[constructorOrInterceptor] = mirror; | 311 classMirrors[constructorOrInterceptor] = mirror; |
| 312 } | 312 } |
| 313 return mirror; | 313 return mirror; |
| 314 } | 314 } |
| 315 | 315 |
| 316 abstract class JsObjectMirror implements ObjectMirror { | 316 abstract class JsObjectMirror implements ObjectMirror { |
| 317 Future<InstanceMirror> setFieldAsync(Symbol fieldName, Object value) { | 317 Future<InstanceMirror> setFieldAsync(Symbol fieldName, Object value) { |
| 318 return new Future<InstanceMirror>(() => this.setField(fieldName, value)); | 318 return new Future<InstanceMirror>(() => this.setField(fieldName, value)); |
| 319 } | 319 } |
| 320 | 320 |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 395 } | 395 } |
| 396 | 396 |
| 397 String toString() => 'InstanceMirror on ${Error.safeToString(reflectee)}'; | 397 String toString() => 'InstanceMirror on ${Error.safeToString(reflectee)}'; |
| 398 | 398 |
| 399 // TODO(ahe): Remove this method from the API. | 399 // TODO(ahe): Remove this method from the API. |
| 400 MirrorSystem get mirrors => currentJsMirrorSystem; | 400 MirrorSystem get mirrors => currentJsMirrorSystem; |
| 401 } | 401 } |
| 402 | 402 |
| 403 class JsClassMirror extends JsTypeMirror with JsObjectMirror | 403 class JsClassMirror extends JsTypeMirror with JsObjectMirror |
| 404 implements ClassMirror { | 404 implements ClassMirror { |
| 405 final String _mangledName; |
| 405 final _jsConstructorOrInterceptor; | 406 final _jsConstructorOrInterceptor; |
| 406 final String _fields; | 407 final String _fields; |
| 407 final List _fieldsMetadata; | 408 final List _fieldsMetadata; |
| 408 List _metadata; | 409 List _metadata; |
| 409 JsClassMirror _superclass; | 410 JsClassMirror _superclass; |
| 410 List<JsMethodMirror> _cachedMethods; | 411 List<JsMethodMirror> _cachedMethods; |
| 411 | 412 |
| 412 // Set as side-effect of accessing JsLibraryMirror.classes. | 413 // Set as side-effect of accessing JsLibraryMirror.classes. |
| 413 JsLibraryMirror _owner; | 414 JsLibraryMirror _owner; |
| 414 | 415 |
| 415 JsClassMirror(Symbol simpleName, | 416 JsClassMirror(Symbol simpleName, |
| 417 this._mangledName, |
| 416 this._jsConstructorOrInterceptor, | 418 this._jsConstructorOrInterceptor, |
| 417 this._fields, | 419 this._fields, |
| 418 this._fieldsMetadata) | 420 this._fieldsMetadata) |
| 419 : super(simpleName); | 421 : super(simpleName); |
| 420 | 422 |
| 421 String get _prettyName => 'ClassMirror'; | 423 String get _prettyName => 'ClassMirror'; |
| 422 | 424 |
| 423 get _jsConstructor { | 425 get _jsConstructor { |
| 424 if (_jsConstructorOrInterceptor is Interceptor) { | 426 if (_jsConstructorOrInterceptor is Interceptor) { |
| 425 return JS('', '#.constructor', _jsConstructorOrInterceptor); | 427 return JS('', '#.constructor', _jsConstructorOrInterceptor); |
| 426 } else { | 428 } else { |
| 427 return _jsConstructorOrInterceptor; | 429 return _jsConstructorOrInterceptor; |
| 428 } | 430 } |
| 429 } | 431 } |
| 430 | 432 |
| 431 Map<Symbol, MethodMirror> get constructors { | 433 Map<Symbol, MethodMirror> get constructors { |
| 432 Map<Symbol, MethodMirror> result = new Map<Symbol, MethodMirror>(); | 434 var result = new Map<Symbol, MethodMirror>(); |
| 433 JsLibraryMirror library = owner; | 435 for (JsMethodMirror method in _methods) { |
| 434 String unmangledName = n(simpleName); | 436 if (method.isConstructor) { |
| 435 for (JsMethodMirror mirror in library._functionMirrors) { | 437 result[method.simpleName] = method; |
| 436 Symbol name = mirror.simpleName; | |
| 437 if (mirror.isConstructor | |
| 438 && (name == simpleName || n(name).startsWith('$unmangledName.'))) { | |
| 439 result[name] = mirror; | |
| 440 mirror._owner = this; | |
| 441 } | 438 } |
| 442 } | 439 } |
| 443 return result; | 440 return result; |
| 444 } | 441 } |
| 445 | 442 |
| 446 List<JsMethodMirror> get _methods { | 443 List<JsMethodMirror> get _methods { |
| 447 if (_cachedMethods != null) return _cachedMethods; | 444 if (_cachedMethods != null) return _cachedMethods; |
| 448 var prototype = JS('', '#.prototype', _jsConstructor); | 445 var prototype = JS('', '#.prototype', _jsConstructor); |
| 449 List<String> keys = extractKeys(prototype); | 446 List<String> keys = extractKeys(prototype); |
| 450 var result = <JsMethodMirror>[]; | 447 var result = <JsMethodMirror>[]; |
| 451 for (String key in keys) { | 448 for (String key in keys) { |
| 452 if (key == '') continue; | 449 if (key == '') continue; |
| 453 String simpleName = mangledNames[key]; | 450 String simpleName = mangledNames[key]; |
| 454 // [simpleName] can be null if [key] represents an implementation | 451 // [simpleName] can be null if [key] represents an implementation |
| 455 // detail, for example, a bailout method, or runtime type support. | 452 // detail, for example, a bailout method, or runtime type support. |
| 456 // It might also be null if the user has limited what is reified for | 453 // It might also be null if the user has limited what is reified for |
| 457 // reflection with metadata. | 454 // reflection with metadata. |
| 458 if (simpleName == null) continue; | 455 if (simpleName == null) continue; |
| 459 var function = JS('', '#[#]', prototype, key); | 456 var function = JS('', '#[#]', prototype, key); |
| 460 var mirror = | 457 var mirror = |
| 461 new JsMethodMirror.fromUnmangledName( | 458 new JsMethodMirror.fromUnmangledName( |
| 462 simpleName, function, false, false); | 459 simpleName, function, false, false); |
| 463 result.add(mirror); | 460 result.add(mirror); |
| 464 mirror._owner = this; | 461 mirror._owner = this; |
| 465 } | 462 } |
| 463 |
| 464 keys = extractKeys(JS('', 'init.statics[#]', _mangledName)); |
| 465 int length = keys.length; |
| 466 for (int i = 0; i < length; i++) { |
| 467 String mangledName = keys[i]; |
| 468 String unmangledName = mangledName; |
| 469 // TODO(ahe): Create accessor for accessing $. It is also |
| 470 // used in js_helper. |
| 471 var jsFunction = JS('', '#[#]', JS_CURRENT_ISOLATE(), mangledName); |
| 472 |
| 473 bool isConstructor = false; |
| 474 if (i + 1 < length) { |
| 475 String reflectionName = keys[i + 1]; |
| 476 if (reflectionName.startsWith('+')) { |
| 477 i++; |
| 478 reflectionName = reflectionName.substring(1); |
| 479 isConstructor = reflectionName.startsWith('new '); |
| 480 if (isConstructor) { |
| 481 reflectionName = reflectionName.substring(4).replaceAll(r'$', '.'); |
| 482 } |
| 483 } |
| 484 unmangledName = reflectionName; |
| 485 } |
| 486 bool isStatic = !isConstructor; // Constructors are not static. |
| 487 JsMethodMirror mirror = |
| 488 new JsMethodMirror.fromUnmangledName( |
| 489 unmangledName, jsFunction, isStatic, isConstructor); |
| 490 result.add(mirror); |
| 491 mirror._owner = this; |
| 492 } |
| 493 |
| 466 return _cachedMethods = result; | 494 return _cachedMethods = result; |
| 467 } | 495 } |
| 468 | 496 |
| 469 Map<Symbol, MethodMirror> get methods { | 497 Map<Symbol, MethodMirror> get methods { |
| 470 var result = new Map<Symbol, MethodMirror>(); | 498 var result = new Map<Symbol, MethodMirror>(); |
| 471 for (JsMethodMirror method in _methods) { | 499 for (JsMethodMirror method in _methods) { |
| 472 if (!method.isGetter && !method.isSetter) { | 500 if (!method.isConstructor && !method.isGetter && !method.isSetter) { |
| 473 result[method.simpleName] = method; | 501 result[method.simpleName] = method; |
| 474 } | 502 } |
| 475 } | 503 } |
| 476 return result; | 504 return result; |
| 477 } | 505 } |
| 478 | 506 |
| 479 Map<Symbol, MethodMirror> get getters { | 507 Map<Symbol, MethodMirror> get getters { |
| 480 // TODO(ahe): This is a hack to remove getters corresponding to a field. | 508 // TODO(ahe): This is a hack to remove getters corresponding to a field. |
| 481 var fields = variables; | 509 var fields = variables; |
| 482 | 510 |
| (...skipping 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 930 var metadataFunction = JS('', '#["@"]', victim); | 958 var metadataFunction = JS('', '#["@"]', victim); |
| 931 if (metadataFunction != null) return JS('', '#()', metadataFunction); | 959 if (metadataFunction != null) return JS('', '#()', metadataFunction); |
| 932 String source = JS('String', 'Function.prototype.toString.call(#)', victim); | 960 String source = JS('String', 'Function.prototype.toString.call(#)', victim); |
| 933 int index = source.lastIndexOf(new RegExp('"[0-9,]*";?[ \n\r]*}')); | 961 int index = source.lastIndexOf(new RegExp('"[0-9,]*";?[ \n\r]*}')); |
| 934 if (index == -1) return const []; | 962 if (index == -1) return const []; |
| 935 index++; | 963 index++; |
| 936 int endQuote = source.indexOf('"', index); | 964 int endQuote = source.indexOf('"', index); |
| 937 return source.substring(index, endQuote).split(',').map(int.parse).map( | 965 return source.substring(index, endQuote).split(',').map(int.parse).map( |
| 938 (int i) => JS('', 'init.metadata[#]', i)).toList(); | 966 (int i) => JS('', 'init.metadata[#]', i)).toList(); |
| 939 } | 967 } |
| OLD | NEW |