blob: ffcef0aaa14649092eae8a3783f870ed1184801d [file] [log] [blame]
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
// Patch library for dart:mirrors.
import 'dart:_foreign_helper' show JS;
import 'dart:_collection-dev' as _symbol_dev;
import 'dart:_js_helper' show createInvocationMirror;
import 'dart:_interceptors' show Interceptor;
patch class MirrorSystem {
patch static String getName(Symbol symbol) => _n(symbol);
}
class _MirrorSystem implements MirrorSystem {
TypeMirror get dynamicType => _dynamicType;
TypeMirror get voidType => _voidType;
final static TypeMirror _dynamicType =
new _TypeMirror(const Symbol('dynamic'));
final static TypeMirror _voidType = new _TypeMirror(const Symbol('void'));
static final Map<String, List<LibraryMirror>> librariesByName =
computeLibrariesByName();
Iterable<LibraryMirror> findLibrary(Symbol libraryName) {
return new List<LibraryMirror>.from(librariesByName[_n(libraryName)]);
}
static Map<String, List<LibraryMirror>> computeLibrariesByName() {
var result = new Map<String, List<LibraryMirror>>();
var jsLibraries = JS('=List|Null', 'init.libraries');
if (jsLibraries == null) return result;
for (List data in jsLibraries) {
String name = data[0];
Uri uri = Uri.parse(data[1]);
List<String> classes = data[2];
List<String> functions = data[3];
var libraries = result.putIfAbsent(name, () => <LibraryMirror>[]);
libraries.add(new _LibraryMirror(_s(name), uri, classes, functions));
}
return result;
}
}
class _TypeMirror implements TypeMirror {
final Symbol simpleName;
_TypeMirror(this.simpleName);
}
class _LibraryMirror extends _ObjectMirror implements LibraryMirror {
final Symbol simpleName;
final Uri uri;
final List<String> _classes;
final List<String> _functions;
_LibraryMirror(this.simpleName, this.uri, this._classes, this._functions);
Symbol get qualifiedName => simpleName;
Map<Symbol, ClassMirror> get classes {
var result = new Map<Symbol, ClassMirror>();
for (int i = 0; i < _classes.length; i += 2) {
Symbol symbol = _s(_classes[i]);
_ClassMirror cls = _reflectClass(symbol, _classes[i + 1]);
result[symbol] = cls;
cls._owner = this;
}
return result;
}
InstanceMirror setField(Symbol fieldName, Object arg) {
// TODO(ahe): This is extremely dangerous!!!
JS('void', r'$[#] = #', _n(fieldName), arg);
return _reflect(arg);
}
InstanceMirror getField(Symbol fieldName) {
// TODO(ahe): This is extremely dangerous!!!
return _reflect(JS('', r'$[#]', _n(fieldName)));
}
Map<Symbol, MethodMirror> get functions {
var result = new Map<Symbol, MethodMirror>();
for (int i = 0; i < _functions.length; i++) {
String name = _functions[i];
Symbol symbol = _s(name);
int parameterCount = null; // TODO(ahe): Compute this.
_MethodMirror mirror =
// TODO(ahe): Create accessor for accessing $. It is also
// used in js_helper.
new _MethodMirror(symbol, JS('', r'$[#]', name), parameterCount);
// TODO(ahe): Cache mirrors.
result[symbol] = mirror;
mirror._owner = this;
}
return result;
}
Map<Symbol, MethodMirror> get getters {
var result = new Map<Symbol, MethodMirror>();
// TODO(ahe): Implement this.
return result;
}
Map<Symbol, MethodMirror> get setters {
var result = new Map<Symbol, MethodMirror>();
// TODO(ahe): Implement this.
return result;
}
Map<Symbol, VariableMirror> get variables {
var result = new Map<Symbol, VariableMirror>();
// TODO(ahe): Implement this.
return result;
}
Map<Symbol, Mirror> get members {
Map<Symbol, Mirror> result = new Map<Symbol, Mirror>.from(classes);
addToResult(Symbol key, Mirror value) {
result[key] = value;
}
functions.forEach(addToResult);
getters.forEach(addToResult);
setters.forEach(addToResult);
variables.forEach(addToResult);
return result;
}
}
String _n(Symbol symbol) => _symbol_dev.Symbol.getName(symbol);
Symbol _s(String name) {
if (name == null) return null;
return new _symbol_dev.Symbol.unvalidated(name);
}
patch MirrorSystem currentMirrorSystem() => _currentMirrorSystem;
final _MirrorSystem _currentMirrorSystem = new _MirrorSystem();
patch Future<MirrorSystem> mirrorSystemOf(SendPort port) {
throw new UnsupportedError("MirrorSystem not implemented");
}
// TODO(ahe): This is a workaround for http://dartbug.com/10543
patch InstanceMirror reflect(Object reflectee) => _reflect(reflectee);
InstanceMirror _reflect(Object reflectee) {
if (reflectee is Closure) {
return new _ClosureMirror(reflectee);
} else {
return new _InstanceMirror(reflectee);
}
}
final Expando<ClassMirror> _classMirrors = new Expando<ClassMirror>();
patch ClassMirror reflectClass(Type key) => __reflectClass(key);
// TODO(ahe): This is a workaround for http://dartbug.com/10543
ClassMirror __reflectClass(Type key) => _reflectClass(_s('$key'), null);
ClassMirror _reflectClass(Symbol symbol, String fields) {
String className = _n(symbol);
var constructor = Primitives.getConstructor(className);
if (constructor == null) {
// Probably an intercepted class.
// TODO(ahe): How to handle intercepted classes?
throw new UnsupportedError('Cannot find class for: $className');
}
var mirror = _classMirrors[constructor];
if (mirror == null) {
mirror = new _ClassMirror(symbol, constructor, fields);
_classMirrors[constructor] = mirror;
}
return mirror;
}
abstract class _ObjectMirror implements ObjectMirror {
Future<InstanceMirror> setFieldAsync(Symbol fieldName, Object value) {
return new Future<InstanceMirror>(() => this.setField(fieldName, value));
}
Future<InstanceMirror> getFieldAsync(Symbol fieldName) {
return new Future<InstanceMirror>(() => this.getField(fieldName));
}
}
class _InstanceMirror extends _ObjectMirror implements InstanceMirror {
final reflectee;
_InstanceMirror(this.reflectee);
bool get hasReflectee => true;
ClassMirror get type => __reflectClass(reflectee.runtimeType);
Future<InstanceMirror> invokeAsync(Symbol memberName,
List<Object> positionalArguments,
[Map<String,Object> namedArguments]) {
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);
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 _reflect(delegate(invocation));
}
InstanceMirror setField(Symbol fieldName, Object arg) {
_invoke(
fieldName, JSInvocationMirror.SETTER, 'set\$${_n(fieldName)}', [arg]);
return _reflect(arg);
}
InstanceMirror getField(Symbol fieldName) {
return _invoke(
fieldName, JSInvocationMirror.GETTER, 'get\$${_n(fieldName)}', []);
}
delegate(Invocation invocation) {
return JSInvocationMirror.invokeFromMirror(invocation, reflectee);
}
String toString() => 'InstanceMirror($reflectee)';
}
class _ClassMirror extends _ObjectMirror implements ClassMirror {
final Symbol simpleName;
final _jsConstructor;
final String _fields;
// Set as side-effect of accessing _LibraryMirror.classes.
_LibraryMirror _owner;
_ClassMirror(this.simpleName, this._jsConstructor, this._fields);
Symbol get qualifiedName => _computeQualifiedName(owner, simpleName);
Map<Symbol, MethodMirror> get functions {
var result = new Map<Symbol, MethodMirror>();
// TODO(ahe): Implement this.
return result;
}
Map<Symbol, MethodMirror> get getters {
var result = new Map<Symbol, MethodMirror>();
// TODO(ahe): Implement this.
return result;
}
Map<Symbol, MethodMirror> get setters {
var result = new Map<Symbol, MethodMirror>();
// TODO(ahe): Implement this.
return result;
}
Map<Symbol, VariableMirror> get variables {
var result = new Map<Symbol, VariableMirror>();
var s = _fields.split(";");
var fields = s[1] == "" ? [] : s[1].split(",");
for (String field in fields) {
_VariableMirror mirror = new _VariableMirror.from(field);
result[mirror.simpleName] = mirror;
mirror._owner = this;
}
return result;
}
Map<Symbol, Mirror> get members {
Map<Symbol, Mirror> result = new Map<Symbol, Mirror>.from(functions);
addToResult(Symbol key, Mirror value) {
result[key] = value;
}
getters.forEach(addToResult);
setters.forEach(addToResult);
variables.forEach(addToResult);
return result;
}
InstanceMirror setField(Symbol fieldName, Object arg) {
// TODO(ahe): This is extremely dangerous!!!
JS('void', r'$[#] = #', '${_n(simpleName)}_${_n(fieldName)}', arg);
return _reflect(arg);
}
InstanceMirror getField(Symbol fieldName) {
// TODO(ahe): This is extremely dangerous!!!
return _reflect(
JS('', r'$[#]', '${_n(simpleName)}_${_n(fieldName)}'));
}
InstanceMirror newInstance(Symbol constructorName,
List positionalArguments,
[Map<Symbol,dynamic> namedArguments]) {
if (namedArguments != null && !namedArguments.isEmpty) {
throw new UnsupportedError('Named arguments are not implemented');
}
String constructorName = '${_n(simpleName)}\$${_n(constructorName)}';
return _reflect(JS('', r'$[#].apply($, #)', constructorName,
new List.from(positionalArguments)));
}
Future<InstanceMirror> newInstanceAsync(
Symbol constructorName,
List positionalArguments,
[Map<Symbol, dynamic> namedArguments]) {
if (namedArguments != null && !namedArguments.isEmpty) {
throw new UnsupportedError('Named arguments are not implemented');
}
return new Future<InstanceMirror>(
() => newInstance(
constructorName, positionalArguments, namedArguments));
}
DeclarationMirror get owner {
if (_owner == null) {
if (_jsConstructor is Interceptor) {
_owner = __reflectClass(Object).owner;
} else {
for (var list in _MirrorSystem.librariesByName.values) {
for (_LibraryMirror library in list) {
// This will set _owner field on all clasess as a side
// effect. This gives us a fast path to reflect on a
// class without parsing reflection data.
library.classes;
}
}
}
if (_owner == null) {
throw new StateError('Class "${_n(simpleName)}" has no owner');
}
}
return _owner;
}
String toString() => 'ClassMirror(${_n(simpleName)})';
}
class _VariableMirror implements VariableMirror {
// TODO(ahe): The values in these fields are virtually untested.
final Symbol simpleName;
final String _jsName;
final bool _readOnly;
DeclarationMirror _owner;
_VariableMirror(this.simpleName, this._jsName, this._readOnly);
factory _VariableMirror.from(String descriptor) {
int length = descriptor.length;
var code = fieldCode(descriptor.codeUnitAt(length - 1));
if (code == 0) {
throw new RuntimeError('Bad field descriptor: $descriptor');
}
bool hasGetter = (code & 3) != 0;
bool hasSetter = (code >> 2) != 0;
String jsName;
String accessorName = jsName = descriptor.substring(0, length - 1);
int divider = descriptor.indexOf(":");
if (divider > 0) {
accessorName = accessorName.substring(0, divider);
jsName = accessorName.substring(divider + 1);
}
bool readOnly = !hasSetter;
return new _VariableMirror(_s(accessorName), jsName, readOnly);
}
TypeMirror get type => _MirrorSystem._dynamicType;
DeclarationMirror get owner => _owner;
Symbol get qualifiedName => _computeQualifiedName(owner, simpleName);
static int fieldCode(int code) {
if (code >= 60 && code <= 64) return code - 59;
if (code >= 123 && code <= 126) return code - 117;
if (code >= 37 && code <= 43) return code - 27;
return 0;
}
}
class _ClosureMirror extends _InstanceMirror implements ClosureMirror {
_ClosureMirror(reflectee) : super(reflectee);
MethodMirror get function {
// TODO(ahe): What about optional parameters (named or not).
var extractCallName = JS('', r'''
function(reflectee) {
for (var property in reflectee) {
if ("call$" == property.substring(0, 5)) return property;
}
return null;
}
''');
String callName = JS('String|Null', '#(#)', extractCallName, reflectee);
if (callName == null) {
throw new RuntimeError('Cannot find callName on "$reflectee"');
}
var jsFunction = JS('', '#[#]', reflectee, callName);
int parameterCount = int.parse(callName.split(r'$')[1]);
return new _MethodMirror(_s(callName), jsFunction, parameterCount);
}
InstanceMirror apply(List positionalArguments,
[Map<Symbol, dynamic> namedArguments]) {
return _reflect(
Function.apply(reflectee, positionalArguments, namedArguments));
}
Future<InstanceMirror> applyAsync(List positionalArguments,
[Map<Symbol, dynamic> namedArguments]) {
return new Future<InstanceMirror>(
() => apply(positionalArguments, namedArguments));
}
}
class _MethodMirror implements MethodMirror {
final Symbol simpleName;
final _jsFunction;
final int _parameterCount;
DeclarationMirror _owner;
_MethodMirror(this.simpleName, this._jsFunction, this._parameterCount);
List<ParameterMirror> get parameters {
// TODO(ahe): Fill the list with parameter mirrors.
return new List<ParameterMirror>(_parameterCount);
}
DeclarationMirror get owner => _owner;
Symbol get qualifiedName => _computeQualifiedName(owner, simpleName);
}
Symbol _computeQualifiedName(DeclarationMirror owner, Symbol simpleName) {
if (owner == null) return simpleName;
String ownerName = _n(owner.qualifiedName);
if (ownerName == '') return simpleName;
return _s('$ownerName.${_n(simpleName)}');
}