// 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. // VM-specific implementation of the dart:mirrors library. // These values are allowed to be passed directly over the wire. bool isSimpleValue(var value) { return (value === null || value is num || value is String || value is bool); } Map filterMap(Map old_map, bool filter(key, value)) { Map new_map = new Map(); old_map.forEach((key, value) { if (filter(key, value)) { new_map[key] = value; } }); return new_map; } class _LocalMirrorSystemImpl implements MirrorSystem { _LocalMirrorSystemImpl(this.libraries, this.isolate) {} final Map libraries; final IsolateMirror isolate; TypeMirror _dynamicType = null; TypeMirror get dynamicType() { if (_dynamicType === null) { _dynamicType = new _LocalClassMirrorImpl( null, 'Dynamic', false, null, null, [], null, const {}); } return _dynamicType; } TypeMirror _voidType = null; TypeMirror get voidType() { if (_voidType === null) { _voidType = new _LocalClassMirrorImpl( null, 'void', false, null, null, [], null, const {}); } return _voidType; } String toString() => "MirrorSystem for isolate '$debugName'"; } abstract class _LocalMirrorImpl implements Mirror { int hashCode() { throw new NotImplementedException('Mirror.hashCode() not yet implemented'); } // Local mirrors always return the same MirrorSystem. This field // is more interesting once we implement remote mirrors. MirrorSystem get mirrors() => _Mirrors.currentMirrorSystem(); } class _LocalIsolateMirrorImpl extends _LocalMirrorImpl implements IsolateMirror { _LocalIsolateMirrorImpl(this.debugName, this._rootLibrary) {} final String debugName; final bool isCurrent = true; var _rootLibrary; LibraryMirror get rootLibrary() { if (_rootLibrary is _LazyLibraryMirror) { _rootLibrary = _rootLibrary.resolve(mirrors); } return _rootLibrary; } String toString() => "IsolateMirror on '$debugName'"; } // A VMReference is used to hold a reference to a VM-internal object, // which can include things like libraries, classes, etc. class VMReference extends NativeFieldWrapperClass1 { } abstract class _LocalVMObjectMirrorImpl extends _LocalMirrorImpl { _LocalVMObjectMirrorImpl(this._reference) {} // For now, all VMObjects hold a VMReference. We could consider // storing the Object reference itself here if the object is a Dart // language objects (except for objects of type VMReference, of // course). VMReference _reference; } abstract class _LocalObjectMirrorImpl extends _LocalVMObjectMirrorImpl implements ObjectMirror { _LocalObjectMirrorImpl(ref) : super(ref) {} Future invoke(String memberName, List positionalArguments, [Map namedArguments]) { if (namedArguments !== null) { throw new NotImplementedException('named arguments not implemented'); } // Walk the arguments and make sure they are legal. for (int i = 0; i < positionalArguments.length; i++) { var arg = positionalArguments[i]; _validateArgument(i, arg); } Completer completer = new Completer(); try { completer.complete( _invoke(this, memberName, positionalArguments)); } catch (var exception) { completer.completeException(exception); } return completer.future; } Future getField(String fieldName) { Completer completer = new Completer(); try { completer.complete(_getField(this, fieldName)); } catch (var exception) { completer.completeException(exception); } return completer.future; } Future setField(String fieldName, Object arg) { _validateArgument(0, arg); Completer completer = new Completer(); try { completer.complete(_setField(this, fieldName, arg)); } catch (var exception) { completer.completeException(exception); } return completer.future; } static _validateArgument(int i, Object arg) { if (arg is Mirror) { if (arg is! InstanceMirror) { throw new MirrorException( 'positional argument $i ($arg) was not an InstanceMirror'); } } else if (!isSimpleValue(arg)) { throw new MirrorException( 'positional argument $i ($arg) was not a simple value'); } } static _invoke(ref, memberName, positionalArguments) native 'LocalObjectMirrorImpl_invoke'; static _getField(ref, fieldName) native 'LocalObjectMirrorImpl_getField'; static _setField(ref, fieldName, value) native 'LocalObjectMirrorImpl_setField'; } // Prints a string as it might appear in dart program text. // TODO(turnidge): Consider truncating. String _dartEscape(String str) { bool isNice(int code) => (code >= 32 && code <= 126); StringBuffer buf = new StringBuffer(); for (int i = 0; i < str.length; i++) { var input = str[i]; String output; switch (input) { case '\\' : output = @'\\'; break; case "\'" : output = @"\'"; break; case '\n' : output = @'\n'; break; case '\r' : output = @'\r'; break; case '\f' : output = @'\f'; break; case '\b' : output = @'\b'; break; case '\t' : output = @'\t'; break; case '\v' : output = @'\v'; break; default: int code = input.charCodeAt(0); if (isNice(code)) { output = input; } else { output = '\\u{${code.toRadixString(16)}}'; } break; } buf.add(output); } return buf.toString(); } class _LocalInstanceMirrorImpl extends _LocalObjectMirrorImpl implements InstanceMirror { _LocalInstanceMirrorImpl(ref, this._type, this._reflectee) : super(ref) {} var _type; ClassMirror get type() { if (_type is _LazyClassMirror) { _type = _type.resolve(mirrors); } return _type; } // LocalInstanceMirrors always reflect local instances bool hasReflectee = true; var _reflectee; get reflectee() => _reflectee; String toString() { if (isSimpleValue(_reflectee)) { if (_reflectee is String) { return "InstanceMirror on <'${_dartEscape(_reflectee)}'>"; } else { return "InstanceMirror on <$_reflectee>"; } } else { return "InstanceMirror on instance of '${type.simpleName}'"; } } } class _LocalClosureMirrorImpl extends _LocalInstanceMirrorImpl implements ClosureMirror { _LocalClosureMirrorImpl(ref, klass, reflectee) : super(ref, klass, reflectee) {} MethodMirror _function; MethodMirror function() => _function; String get source() { throw new NotImplementedException('ClosureMirror.source not implemented'); } Future apply(List positionalArguments, [Map namedArguments]) { if (namedArguments !== null) { throw new NotImplementedException('named arguments not implemented'); } // Walk the arguments and make sure they are legal. for (int i = 0; i < positionalArguments.length; i++) { var arg = positionalArguments[i]; _LocalObjectMirrorImpl._validateArgument(i, arg); } Completer completer = new Completer(); try { completer.complete( _apply(this, positionalArguments)); } catch (var exception) { completer.completeException(exception); } return completer.future; } Future findInContext(String name) { throw new NotImplementedException( 'ClosureMirror.findInContext() not implemented'); } static _apply(ref, positionalArguments) native 'LocalClosureMirrorImpl_apply'; } class _LazyClassMirror { _LazyClassMirror(this.libraryName, this.interfaceName) {} ClassMirror resolve(MirrorSystem mirrors) { if (libraryName === null) { if (interfaceName == 'Dynamic') { return mirrors.dynamicType(); } else if (interfaceName == 'void') { return mirrors.voidType(); } else { throw new NotImplementedException( "Mirror for type '$interfaceName' not implemented"); } } return mirrors.libraries[libraryName].members[interfaceName]; } final String libraryName; final String interfaceName; } class _LocalClassMirrorImpl extends _LocalObjectMirrorImpl implements ClassMirror { _LocalClassMirrorImpl(ref, this.simpleName, this.isClass, this._owner, this._superclass, this._superinterfaces, this._defaultFactory, this.members) : super(ref) {} final String simpleName; String _qualifiedName = null; String get qualifiedName() { if (_qualifiedName === null) { _qualifiedName = '${owner.qualifiedName}.${simpleName}'; } return _qualifiedName; } var _owner; DeclarationMirror get owner() { if (_owner is! Mirror) { _owner = _owner.resolve(mirrors); } return _owner; } bool get isPrivate() => simpleName.startsWith('_'); final bool isTopLevel = true; SourceLocation get location() { throw new NotImplementedException( 'ClassMirror.location not yet implemented'); } final bool isClass; var _superclass; ClassMirror get superclass() { if (_superclass is _LazyClassMirror) { _superclass = _superclass.resolve(mirrors); } return _superclass; } var _superinterfaces; List get superinterfaces() { if (_superinterfaces.length > 0 && _superinterfaces[0] is _LazyClassMirror) { List resolved = new List(); for (int i = 0; i < _superinterfaces.length; i++) { resolved.add(_superinterfaces[i].resolve(mirrors)); } _superinterfaces = resolved; } return _superinterfaces; } var _defaultFactory; ClassMirror get defaultFactory() { if (_defaultFactory is _LazyClassMirror) { _defaultFactory = _defaultFactory.resolve(mirrors); } return _defaultFactory; } final Map members; Map _methods = null; Map _constructors = null; Map _getters = null; Map _setters = null; Map _variables = null; Map get methods() { if (_methods == null) { _methods = filterMap(members, (key, value) => (value is MethodMirror)); } return _methods; } Map get constructors() { if (_constructors == null) { _constructors = filterMap(methods, (key, value) => (value.isConstructor)); } return _constructors; } Map get getters() { if (_getters == null) { _getters = filterMap(methods, (key, value) => (value.isGetter)); } return _getters; } Map get setters() { if (_setters == null) { _setters = filterMap(methods, (key, value) => (value.isSetter)); } return _setters; } Map get variables() { if (_variables == null) { _variables = filterMap(members, (key, value) => (value is VariableMirror)); } return _variables; } List get typeVariables() { throw new NotImplementedException( 'ClassMirror.typeVariables not yet implemented'); } List get typeArguments() { throw new NotImplementedException( 'ClassMirror.typeArguments not yet implemented'); } bool isGenericDeclaration() { throw new NotImplementedException( 'ClassMirror.isGenericDeclaration not yet implemented'); } ClassMirror genericDeclaration() { throw new NotImplementedException( 'ClassMirror.genericDeclaration not yet implemented'); } String toString() => "ClassMirror on '$simpleName'"; Future newInstance(String constructorName, List positionalArguments, [Map namedArguments]) { if (namedArguments !== null) { throw new NotImplementedException('named arguments not implemented'); } // Walk the arguments and make sure they are legal. for (int i = 0; i < positionalArguments.length; i++) { var arg = positionalArguments[i]; _LocalObjectMirrorImpl._validateArgument(i, arg); } Completer completer = new Completer(); try { completer.complete( _invokeConstructor(this, constructorName, positionalArguments)); } catch (var exception) { completer.completeException(exception); } return completer.future; } static _invokeConstructor(ref, constructorName, positionalArguments) native 'LocalClassMirrorImpl_invokeConstructor'; } class _LazyLibraryMirror { _LazyLibraryMirror(this.libraryName) {} LibraryMirror resolve(MirrorSystem mirrors) { return mirrors.libraries[libraryName]; } final String libraryName; } class _LocalLibraryMirrorImpl extends _LocalObjectMirrorImpl implements LibraryMirror { _LocalLibraryMirrorImpl(ref, this.simpleName, this.url, this.members) : super(ref) {} final String simpleName; // The simple name and the qualified name are the same for a library. String get qualifiedName() => simpleName; // Always null for libraries. final DeclarationMirror owner = null; // Always false for libraries. final bool isPrivate = false; // Always false for libraries. final bool isTopLevel = false; SourceLocation get location() { throw new NotImplementedException( 'LibraryMirror.location not yet implemented'); } final String url; final Map members; Map _classes = null; Map _functions = null; Map _getters = null; Map _setters = null; Map _variables = null; Map get classes() { if (_classes == null) { _classes = filterMap(members, (key, value) => (value is ClassMirror)); } return _classes; } Map get functions() { if (_functions == null) { _functions = filterMap(members, (key, value) => (value is MethodMirror)); } return _functions; } Map get getters() { if (_getters == null) { _getters = filterMap(functions, (key, value) => (value.isGetter)); } return _getters; } Map get setters() { if (_setters == null) { _setters = filterMap(functions, (key, value) => (value.isSetter)); } return _setters; } Map get variables() { if (_variables == null) { _variables = filterMap(members, (key, value) => (value is VariableMirror)); } return _variables; } String toString() => "LibraryMirror on '$simpleName'"; } class _LocalMethodMirrorImpl extends _LocalMirrorImpl implements MethodMirror { _LocalMethodMirrorImpl(this.simpleName, this._owner, this.parameters, this.isStatic, this.isAbstract, this.isGetter, this.isSetter, this.isConstructor, this.isConstConstructor, this.isGenerativeConstructor, this.isRedirectingConstructor, this.isFactoryConstructor) {} final String simpleName; String _qualifiedName = null; String get qualifiedName() { if (_qualifiedName === null) { _qualifiedName = '${owner.qualifiedName}.${simpleName}'; } return _qualifiedName; } var _owner; DeclarationMirror get owner() { if (_owner is! Mirror) { _owner = _owner.resolve(mirrors); } return _owner; } bool get isPrivate() { return simpleName.startsWith('_') || constructorName.startsWith('_'); } bool get isTopLevel() => owner is LibraryMirror; SourceLocation get location() { throw new NotImplementedException( 'MethodMirror.location not yet implemented'); } TypeMirror get returnType() { throw new NotImplementedException( 'MethodMirror.returnType not yet implemented'); } final List parameters; final bool isStatic; final bool isAbstract; bool get isRegularMethod() => !isGetter && !isSetter && !isConstructor; TypeMirror get isOperator() { throw new NotImplementedException( 'MethodMirror.isOperator not yet implemented'); } final bool isGetter; final bool isSetter; final bool isConstructor; var _constructorName = null; String get constructorName() { if (_constructorName === null) { if (!isConstructor) { _constructorName = ''; } else { var parts = simpleName.split('.'); if (parts.length > 2) { throw new MirrorException( 'Internal error in MethodMirror.constructorName: ' 'malformed name <$simpleName>'); } else if (parts.length == 2) { _constructorName = parts[1]; } else { _constructorName = ''; } } } return _constructorName; } final bool isConstConstructor; final bool isGenerativeConstructor; final bool isRedirectingConstructor; final bool isFactoryConstructor; String toString() => "MethodMirror on '$simpleName'"; } class _LocalVariableMirrorImpl extends _LocalMirrorImpl implements VariableMirror { _LocalVariableMirrorImpl(this.simpleName, this._owner, this.isStatic, this.isFinal) {} final String simpleName; String _qualifiedName = null; String get qualifiedName() { if (_qualifiedName === null) { _qualifiedName = '${owner.qualifiedName}.${simpleName}'; } return _qualifiedName; } var _owner; DeclarationMirror get owner() { if (_owner is! Mirror) { _owner = _owner.resolve(mirrors); } return _owner; } bool get isPrivate() { return simpleName.startsWith('_'); } bool get isTopLevel() { return owner is LibraryMirror; } SourceLocation get location() { throw new NotImplementedException( 'MethodMirror.location not yet implemented'); } TypeMirror get returnType() { throw new NotImplementedException( 'MethodMirror.returnType not yet implemented'); } final bool isStatic; final bool isFinal; String toString() => "VariableMirror on '$simpleName'"; } class _LocalParameterMirrorImpl extends _LocalVariableMirrorImpl implements ParameterMirror { // TODO(rmacnak): Fill these mirrors will real information _LocalParameterMirrorImpl(this.isOptional) : super(null, null, false, false) {} final bool isOptional; TypeMirror get type() { throw new NotImplementedException( 'ParameterMirror.type not yet implemented'); } String get defaultValue() { throw new NotImplementedException( 'ParameterMirror.defaultValue not yet implemented'); } bool get hasDefaultValue() { throw new NotImplementedException( 'ParameterMirror.hasDefaultValue not yet implemented'); } } class _Mirrors { // Does a port refer to our local isolate? static bool isLocalPort(SendPort port) native 'Mirrors_isLocalPort'; static MirrorSystem _currentMirrorSystem = null; // Creates a new local MirrorSystem. static MirrorSystem makeLocalMirrorSystem() native 'Mirrors_makeLocalMirrorSystem'; // The MirrorSystem for the current isolate. static MirrorSystem currentMirrorSystem() { if (_currentMirrorSystem === null) { _currentMirrorSystem = makeLocalMirrorSystem(); } return _currentMirrorSystem; } static Future mirrorSystemOf(SendPort port) { Completer completer = new Completer(); if (isLocalPort(port)) { // Make a local mirror system. try { completer.complete(currentMirrorSystem()); } catch (var exception) { completer.completeException(exception); } } else { // Make a remote mirror system throw new NotImplementedException('Remote mirrors not yet implemented'); } return completer.future; } // Creates a new local InstanceMirror static InstanceMirror makeLocalInstanceMirror(Object reflectee) native 'Mirrors_makeLocalInstanceMirror'; // Creates a new local mirror for some Object. static InstanceMirror reflect(Object reflectee) { return makeLocalInstanceMirror(reflectee); } }