| // 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. |
| |
| library mirrors_dart2js; |
| |
| import 'dart:io'; |
| import 'dart:uri'; |
| |
| import '../../../../../lib/compiler/compiler.dart' as diagnostics; |
| import '../../../../../lib/compiler/implementation/elements/elements.dart'; |
| import '../../../../../lib/compiler/implementation/resolution/resolution.dart' |
| show ResolverTask, ResolverVisitor; |
| import '../../../../../lib/compiler/implementation/apiimpl.dart' as api; |
| import '../../../../../lib/compiler/implementation/scanner/scannerlib.dart'; |
| import '../../../../../lib/compiler/implementation/ssa/ssa.dart'; |
| import '../../../../../lib/compiler/implementation/dart2jslib.dart'; |
| import '../../../../../lib/compiler/implementation/filenames.dart'; |
| import '../../../../../lib/compiler/implementation/source_file.dart'; |
| import '../../../../../lib/compiler/implementation/tree/tree.dart'; |
| import '../../../../../lib/compiler/implementation/util/util.dart'; |
| import '../../../../../lib/compiler/implementation/util/uri_extras.dart'; |
| import '../../../../../lib/compiler/implementation/dart2js.dart'; |
| |
| // TODO(rnystrom): Use "package:" URL (#4968). |
| import '../../mirrors.dart'; |
| import 'util.dart'; |
| |
| //------------------------------------------------------------------------------ |
| // Utility types and functions for the dart2js mirror system |
| //------------------------------------------------------------------------------ |
| |
| bool _isPrivate(String name) { |
| return name.startsWith('_'); |
| } |
| |
| List<ParameterMirror> _parametersFromFunctionSignature( |
| Dart2JsMirrorSystem system, |
| Dart2JsMethodMirror method, |
| FunctionSignature signature) { |
| var parameters = <ParameterMirror>[]; |
| Link<Element> link = signature.requiredParameters; |
| while (!link.isEmpty) { |
| parameters.add(new Dart2JsParameterMirror( |
| system, method, link.head, false)); |
| link = link.tail; |
| } |
| link = signature.optionalParameters; |
| while (!link.isEmpty) { |
| parameters.add(new Dart2JsParameterMirror( |
| system, method, link.head, true)); |
| link = link.tail; |
| } |
| return parameters; |
| } |
| |
| Dart2JsTypeMirror _convertTypeToTypeMirror( |
| Dart2JsMirrorSystem system, |
| DartType type, |
| InterfaceType defaultType, |
| [FunctionSignature functionSignature]) { |
| if (type === null) { |
| return new Dart2JsInterfaceTypeMirror(system, defaultType); |
| } else if (type is InterfaceType) { |
| if (type === system.compiler.types.dynamicType) { |
| return new Dart2JsDynamicMirror(system, type); |
| } else { |
| return new Dart2JsInterfaceTypeMirror(system, type); |
| } |
| } else if (type is TypeVariableType) { |
| return new Dart2JsTypeVariableMirror(system, type); |
| } else if (type is FunctionType) { |
| return new Dart2JsFunctionTypeMirror(system, type, functionSignature); |
| } else if (type is VoidType) { |
| return new Dart2JsVoidMirror(system, type); |
| } else if (type is TypedefType) { |
| return new Dart2JsTypedefMirror(system, type); |
| } |
| throw new ArgumentError("Unexpected interface type $type"); |
| } |
| |
| Collection<Dart2JsMemberMirror> _convertElementMemberToMemberMirrors( |
| Dart2JsObjectMirror library, Element element) { |
| if (element is SynthesizedConstructorElement) { |
| return const <Dart2JsMemberMirror>[]; |
| } else if (element is VariableElement) { |
| return <Dart2JsMemberMirror>[new Dart2JsFieldMirror(library, element)]; |
| } else if (element is FunctionElement) { |
| return <Dart2JsMemberMirror>[new Dart2JsMethodMirror(library, element)]; |
| } else if (element is AbstractFieldElement) { |
| var members = <Dart2JsMemberMirror>[]; |
| if (element.getter !== null) { |
| members.add(new Dart2JsMethodMirror(library, element.getter)); |
| } |
| if (element.setter !== null) { |
| members.add(new Dart2JsMethodMirror(library, element.setter)); |
| } |
| return members; |
| } |
| throw new ArgumentError( |
| "Unexpected member type $element ${element.kind}"); |
| } |
| |
| MethodMirror _convertElementMethodToMethodMirror(Dart2JsObjectMirror library, |
| Element element) { |
| if (element is FunctionElement) { |
| return new Dart2JsMethodMirror(library, element); |
| } else { |
| return null; |
| } |
| } |
| |
| class Dart2JsMethodKind { |
| static const Dart2JsMethodKind NORMAL = const Dart2JsMethodKind("normal"); |
| static const Dart2JsMethodKind CONSTRUCTOR |
| = const Dart2JsMethodKind("constructor"); |
| static const Dart2JsMethodKind CONST = const Dart2JsMethodKind("const"); |
| static const Dart2JsMethodKind FACTORY = const Dart2JsMethodKind("factory"); |
| static const Dart2JsMethodKind GETTER = const Dart2JsMethodKind("getter"); |
| static const Dart2JsMethodKind SETTER = const Dart2JsMethodKind("setter"); |
| static const Dart2JsMethodKind OPERATOR = const Dart2JsMethodKind("operator"); |
| |
| final String text; |
| |
| const Dart2JsMethodKind(this.text); |
| |
| String toString() => text; |
| } |
| |
| |
| String _getOperatorFromOperatorName(String name) { |
| Map<String, String> mapping = const { |
| 'eq': '==', |
| 'not': '~', |
| 'index': '[]', |
| 'indexSet': '[]=', |
| 'mul': '*', |
| 'div': '/', |
| 'mod': '%', |
| 'tdiv': '~/', |
| 'add': '+', |
| 'sub': '-', |
| 'shl': '<<', |
| 'shr': '>>', |
| 'ge': '>=', |
| 'gt': '>', |
| 'le': '<=', |
| 'lt': '<', |
| 'and': '&', |
| 'xor': '^', |
| 'or': '|', |
| }; |
| String newName = mapping[name]; |
| if (newName === null) { |
| throw new Exception('Unhandled operator name: $name'); |
| } |
| return newName; |
| } |
| |
| DiagnosticListener get _diagnosticListener { |
| return const Dart2JsDiagnosticListener(); |
| } |
| |
| class Dart2JsDiagnosticListener implements DiagnosticListener { |
| const Dart2JsDiagnosticListener(); |
| |
| void cancel(String reason, {node, token, instruction, element}) { |
| print(reason); |
| } |
| |
| void log(message) { |
| print(message); |
| } |
| |
| void internalError(String message, |
| {Node node, Token token, HInstruction instruction, |
| Element element}) { |
| cancel('Internal error: $message', node, token, instruction, element); |
| } |
| |
| void internalErrorOnElement(Element element, String message) { |
| internalError(message, element: element); |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Compiler extension for apidoc. |
| //------------------------------------------------------------------------------ |
| |
| /** |
| * Extension of the compiler that enables the analysis of several libraries with |
| * no particular entry point. |
| */ |
| class LibraryCompiler extends api.Compiler { |
| LibraryCompiler(diagnostics.ReadStringFromUri provider, |
| diagnostics.DiagnosticHandler handler, |
| Uri libraryRoot, Uri packageRoot, |
| List<String> options) |
| : super(provider, handler, libraryRoot, packageRoot, options) { |
| checker = new LibraryTypeCheckerTask(this); |
| resolver = new LibraryResolverTask(this); |
| } |
| |
| // TODO(johnniwinther): The following methods are added to enable the analysis |
| // of a collection of libraries to be used for apidoc. Most of the methods |
| // are based on copies of existing methods and could probably be implemented |
| // such that the duplicate code is avoided. Not to affect the correctness and |
| // speed of dart2js as is, the redundancy is accepted temporarily. |
| |
| /** |
| * Run the compiler on a list of libraries. No entry point is used. |
| */ |
| bool runList(List<Uri> uriList) { |
| bool success = _runList(uriList); |
| for (final task in tasks) { |
| log('${task.name} took ${task.timing}msec'); |
| } |
| return success; |
| } |
| |
| bool _runList(List<Uri> uriList) { |
| try { |
| runCompilerList(uriList); |
| } on CompilerCancelledException catch (exception) { |
| log(exception.toString()); |
| log('compilation failed'); |
| return false; |
| } |
| tracer.close(); |
| log('compilation succeeded'); |
| return true; |
| } |
| |
| void runCompilerList(List<Uri> uriList) { |
| scanBuiltinLibraries(); |
| var elementList = <LibraryElement>[]; |
| for (var uri in uriList) { |
| elementList.add(libraryLoader.loadLibrary(uri, null, uri)); |
| } |
| libraries.forEach((_, library) { |
| maybeEnableJSHelper(library); |
| }); |
| |
| world.populate(); |
| |
| log('Resolving...'); |
| phase = Compiler.PHASE_RESOLVING; |
| backend.enqueueHelpers(enqueuer.resolution); |
| processQueueList(enqueuer.resolution, elementList); |
| log('Resolved ${enqueuer.resolution.resolvedElements.length} elements.'); |
| } |
| |
| void processQueueList(Enqueuer world, List<LibraryElement> elements) { |
| backend.processNativeClasses(world, libraries.values); |
| for (var library in elements) { |
| library.forEachLocalMember((element) { |
| world.addToWorkList(element); |
| }); |
| } |
| progress.reset(); |
| world.forEach((WorkItem work) { |
| withCurrentElement(work.element, () => work.run(this, world)); |
| }); |
| } |
| |
| String codegen(WorkItem work, Enqueuer world) { |
| return null; |
| } |
| } |
| |
| // TODO(johnniwinther): The source for the apidoc includes calls to methods on |
| // for instance [MathPrimitives] which are not resolved by dart2js. Since we |
| // do not need to analyse the body of functions to produce the documenation |
| // we use a specialized resolver which bypasses method bodies. |
| class LibraryResolverTask extends ResolverTask { |
| LibraryResolverTask(api.Compiler compiler) : super(compiler); |
| |
| void visitBody(ResolverVisitor visitor, Statement body) {} |
| } |
| |
| // TODO(johnniwinther): As a side-effect of bypassing method bodies in |
| // [LibraryResolveTask] we can not perform the typecheck. |
| class LibraryTypeCheckerTask extends TypeCheckerTask { |
| LibraryTypeCheckerTask(api.Compiler compiler) : super(compiler); |
| |
| void check(Node tree, TreeElements elements) {} |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Compilation implementation |
| //------------------------------------------------------------------------------ |
| |
| class Dart2JsCompilation implements Compilation { |
| bool isWindows = (Platform.operatingSystem == 'windows'); |
| api.Compiler _compiler; |
| Uri cwd; |
| bool isAborting = false; |
| Map<String, SourceFile> sourceFiles; |
| |
| Future<String> provider(Uri uri) { |
| if (uri.scheme != 'file') { |
| throw new ArgumentError(uri); |
| } |
| String source; |
| try { |
| source = readAll(uriPathToNative(uri.path)); |
| } on FileIOException catch (ex) { |
| throw 'Error: Cannot read "${relativize(cwd, uri, isWindows)}" ' |
| '(${ex.osError}).'; |
| } |
| sourceFiles[uri.toString()] = |
| new SourceFile(relativize(cwd, uri, isWindows), source); |
| return new Future.immediate(source); |
| } |
| |
| void handler(Uri uri, int begin, int end, |
| String message, diagnostics.Diagnostic kind) { |
| if (isAborting) return; |
| bool fatal = |
| kind === diagnostics.Diagnostic.CRASH || |
| kind === diagnostics.Diagnostic.ERROR; |
| if (uri === null) { |
| if (!fatal) { |
| return; |
| } |
| print(message); |
| throw message; |
| } else if (fatal) { |
| SourceFile file = sourceFiles[uri.toString()]; |
| print(file.getLocationMessage(message, begin, end, true, (s) => s)); |
| throw message; |
| } |
| } |
| |
| Dart2JsCompilation(Path script, Path libraryRoot, |
| [Path packageRoot, List<String> opts = const <String>[]]) |
| : cwd = getCurrentDirectory(), sourceFiles = <String, SourceFile>{} { |
| var libraryUri = cwd.resolve(libraryRoot.toString()); |
| var packageUri; |
| if (packageRoot !== null) { |
| packageUri = cwd.resolve(packageRoot.toString()); |
| } else { |
| packageUri = libraryUri; |
| } |
| _compiler = new api.Compiler(provider, handler, |
| libraryUri, packageUri, <String>[]); |
| var scriptUri = cwd.resolve(script.toString()); |
| // TODO(johnniwinther): Detect file not found |
| _compiler.run(scriptUri); |
| } |
| |
| Dart2JsCompilation.library(List<Path> libraries, Path libraryRoot, |
| [Path packageRoot, List<String> opts = const <String>[]]) |
| : cwd = getCurrentDirectory(), sourceFiles = <String, SourceFile>{} { |
| var libraryUri = cwd.resolve(libraryRoot.toString()); |
| var packageUri; |
| if (packageRoot !== null) { |
| packageUri = cwd.resolve(packageRoot.toString()); |
| } else { |
| packageUri = libraryUri; |
| } |
| _compiler = new LibraryCompiler(provider, handler, |
| libraryUri, packageUri, <String>[]); |
| var librariesUri = <Uri>[]; |
| for (Path library in libraries) { |
| librariesUri.add(cwd.resolve(library.toString())); |
| // TODO(johnniwinther): Detect file not found |
| } |
| _compiler.runList(librariesUri); |
| } |
| |
| MirrorSystem get mirrors => new Dart2JsMirrorSystem(_compiler); |
| |
| Future<String> compileToJavaScript() => |
| new Future<String>.immediate(_compiler.assembledCode); |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| // Dart2Js specific extensions of mirror interfaces |
| //------------------------------------------------------------------------------ |
| |
| abstract class Dart2JsMirror implements Mirror { |
| Dart2JsMirrorSystem get system; |
| } |
| |
| abstract class Dart2JsMemberMirror implements Dart2JsMirror, MemberMirror { |
| |
| } |
| |
| abstract class Dart2JsTypeMirror implements Dart2JsMirror, TypeMirror { |
| |
| } |
| |
| abstract class Dart2JsElementMirror implements Dart2JsMirror { |
| final Dart2JsMirrorSystem system; |
| final Element _element; |
| |
| Dart2JsElementMirror(this.system, this._element) { |
| assert (system !== null); |
| assert (_element !== null); |
| } |
| |
| String get simpleName => _element.name.slowToString(); |
| |
| String get displayName => simpleName; |
| |
| Location get location => new Dart2JsLocation( |
| _element.getCompilationUnit().script, |
| system.compiler.spanFromElement(_element)); |
| |
| String toString() => _element.toString(); |
| |
| int get hashCode => qualifiedName.hashCode; |
| } |
| |
| abstract class Dart2JsProxyMirror implements Dart2JsMirror { |
| final Dart2JsMirrorSystem system; |
| |
| Dart2JsProxyMirror(this.system); |
| |
| String get displayName => simpleName; |
| |
| int get hashCode => qualifiedName.hashCode; |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Mirror system implementation. |
| //------------------------------------------------------------------------------ |
| |
| class Dart2JsMirrorSystem implements MirrorSystem, Dart2JsMirror { |
| final api.Compiler compiler; |
| Map<String, Dart2JsLibraryMirror> _libraries; |
| Map<LibraryElement, Dart2JsLibraryMirror> _libraryMap; |
| |
| Dart2JsMirrorSystem(this.compiler) |
| : _libraryMap = new Map<LibraryElement, Dart2JsLibraryMirror>(); |
| |
| void _ensureLibraries() { |
| if (_libraries == null) { |
| _libraries = <String, Dart2JsLibraryMirror>{}; |
| compiler.libraries.forEach((_, LibraryElement v) { |
| var mirror = new Dart2JsLibraryMirror(system, v); |
| _libraries[mirror.simpleName] = mirror; |
| _libraryMap[v] = mirror; |
| }); |
| } |
| } |
| |
| Map<String, LibraryMirror> get libraries { |
| _ensureLibraries(); |
| return new ImmutableMapWrapper<String, LibraryMirror>(_libraries); |
| } |
| |
| Dart2JsLibraryMirror getLibrary(LibraryElement element) { |
| return _libraryMap[element]; |
| } |
| |
| Dart2JsMirrorSystem get system => this; |
| |
| String get simpleName => "mirror"; |
| String get displayName => simpleName; |
| String get qualifiedName => simpleName; |
| |
| // TODO(johnniwinther): Hack! Dart2JsMirrorSystem need not be a Mirror. |
| int get hashCode => qualifiedName.hashCode; |
| } |
| |
| abstract class Dart2JsObjectMirror extends Dart2JsElementMirror |
| implements ObjectMirror { |
| Dart2JsObjectMirror(Dart2JsMirrorSystem system, Element element) |
| : super(system, element); |
| } |
| |
| class Dart2JsLibraryMirror extends Dart2JsObjectMirror |
| implements LibraryMirror { |
| Map<String, InterfaceMirror> _types; |
| Map<String, MemberMirror> _members; |
| |
| Dart2JsLibraryMirror(Dart2JsMirrorSystem system, LibraryElement library) |
| : super(system, library); |
| |
| LibraryElement get _library => _element; |
| |
| Uri get uri => _library.uri; |
| |
| LibraryMirror library() => this; |
| |
| /** |
| * Returns the library name (for libraries with a #library tag) or the script |
| * file name (for scripts without a #library tag). The latter case is used to |
| * provide a 'library name' for scripts, to use for instance in dartdoc. |
| */ |
| String get simpleName { |
| if (_library.libraryTag !== null) { |
| // TODO(ahe): Remove StringNode check when old syntax is removed. |
| StringNode name = _library.libraryTag.name.asStringNode(); |
| if (name !== null) { |
| return name.dartString.slowToString(); |
| } else { |
| return _library.libraryTag.name.toString(); |
| } |
| } else { |
| // Use the file name as script name. |
| String path = _library.uri.path; |
| return path.substring(path.lastIndexOf('/') + 1); |
| } |
| } |
| |
| String get qualifiedName => simpleName; |
| |
| void _ensureTypes() { |
| if (_types == null) { |
| _types = <String, InterfaceMirror>{}; |
| _library.forEachLocalMember((Element e) { |
| if (e.isClass()) { |
| e.ensureResolved(system.compiler); |
| var type = new Dart2JsInterfaceMirror.fromLibrary(this, e); |
| assert(invariant(_library, !_types.containsKey(type.simpleName), |
| message: "Type name '${type.simpleName}' " |
| "is not unique in $_library.")); |
| _types[type.simpleName] = type; |
| } else if (e.isTypedef()) { |
| var type = new Dart2JsTypedefMirror.fromLibrary(this, |
| e.computeType(system.compiler)); |
| assert(invariant(_library, !_types.containsKey(type.simpleName), |
| message: "Type name '${type.simpleName}' " |
| "is not unique in $_library.")); |
| _types[type.simpleName] = type; |
| } |
| }); |
| } |
| } |
| |
| void _ensureMembers() { |
| if (_members == null) { |
| _members = <String, MemberMirror>{}; |
| _library.forEachLocalMember((Element e) { |
| if (!e.isClass() && !e.isTypedef()) { |
| for (var member in _convertElementMemberToMemberMirrors(this, e)) { |
| assert(!_members.containsKey(member.simpleName)); |
| _members[member.simpleName] = member; |
| } |
| } |
| }); |
| } |
| } |
| |
| Map<String, MemberMirror> get declaredMembers { |
| _ensureMembers(); |
| return new ImmutableMapWrapper<String, MemberMirror>(_members); |
| } |
| |
| Map<String, InterfaceMirror> get types { |
| _ensureTypes(); |
| return new ImmutableMapWrapper<String, InterfaceMirror>(_types); |
| } |
| |
| Location get location { |
| var script = _library.getCompilationUnit().script; |
| return new Dart2JsLocation( |
| script, |
| new SourceSpan(script.uri, 0, script.text.length)); |
| } |
| } |
| |
| class Dart2JsLocation implements Location { |
| Script _script; |
| SourceSpan _span; |
| |
| Dart2JsLocation(this._script, this._span); |
| |
| int get start => _span.begin; |
| |
| int get end => _span.end; |
| |
| Source get source => new Dart2JsSource(_script); |
| |
| String get text => _script.text.substring(start, end); |
| } |
| |
| class Dart2JsSource implements Source { |
| Script _script; |
| |
| Dart2JsSource(this._script); |
| |
| Uri get uri => _script.uri; |
| |
| String get text => _script.text; |
| } |
| |
| class Dart2JsParameterMirror extends Dart2JsElementMirror |
| implements ParameterMirror { |
| final MethodMirror _method; |
| final bool isOptional; |
| |
| factory Dart2JsParameterMirror(Dart2JsMirrorSystem system, |
| MethodMirror method, |
| VariableElement element, |
| bool isOptional) { |
| if (element is FieldParameterElement) { |
| return new Dart2JsFieldParameterMirror(system, |
| method, element, isOptional); |
| } |
| return new Dart2JsParameterMirror._normal(system, |
| method, element, isOptional); |
| } |
| |
| Dart2JsParameterMirror._normal(Dart2JsMirrorSystem system, |
| this._method, |
| VariableElement element, |
| this.isOptional) |
| : super(system, element); |
| |
| VariableElement get _variableElement => _element; |
| |
| String get qualifiedName => '${_method.qualifiedName}#${simpleName}'; |
| |
| TypeMirror get type => _convertTypeToTypeMirror(system, |
| _variableElement.computeType(system.compiler), |
| system.compiler.types.dynamicType, |
| _variableElement.variables.functionSignature); |
| |
| String get defaultValue { |
| if (hasDefaultValue) { |
| SendSet expression = _variableElement.cachedNode.asSendSet(); |
| return unparse(expression.arguments.head); |
| } |
| return null; |
| } |
| bool get hasDefaultValue { |
| return _variableElement.cachedNode !== null && |
| _variableElement.cachedNode is SendSet; |
| } |
| |
| bool get isInitializingFormal => false; |
| |
| FieldMirror get initializedField => null; |
| } |
| |
| class Dart2JsFieldParameterMirror extends Dart2JsParameterMirror { |
| |
| Dart2JsFieldParameterMirror(Dart2JsMirrorSystem system, |
| MethodMirror method, |
| FieldParameterElement element, |
| bool isOptional) |
| : super._normal(system, method, element, isOptional); |
| |
| FieldParameterElement get _fieldParameterElement => _element; |
| |
| TypeMirror get type { |
| if (_fieldParameterElement.variables.cachedNode.type !== null) { |
| return super.type; |
| } |
| return _convertTypeToTypeMirror(system, |
| _fieldParameterElement.fieldElement.computeType(system.compiler), |
| system.compiler.types.dynamicType, |
| _variableElement.variables.functionSignature); |
| } |
| |
| bool get isInitializingFormal => true; |
| |
| FieldMirror get initializedField => new Dart2JsFieldMirror( |
| _method.surroundingDeclaration, _fieldParameterElement.fieldElement); |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Declarations |
| //------------------------------------------------------------------------------ |
| class Dart2JsInterfaceMirror extends Dart2JsObjectMirror |
| implements Dart2JsTypeMirror, InterfaceMirror { |
| final Dart2JsLibraryMirror library; |
| Map<String, Dart2JsMemberMirror> _members; |
| List<TypeVariableMirror> _typeVariables; |
| |
| Dart2JsInterfaceMirror(Dart2JsMirrorSystem system, ClassElement _class) |
| : this.library = system.getLibrary(_class.getLibrary()), |
| super(system, _class); |
| |
| ClassElement get _class => _element; |
| |
| Dart2JsInterfaceMirror.fromLibrary(Dart2JsLibraryMirror library, |
| ClassElement _class) |
| : this.library = library, |
| super(library.system, _class); |
| |
| String get qualifiedName => '${library.qualifiedName}.${simpleName}'; |
| |
| Location get location { |
| if (_class is PartialClassElement) { |
| var node = _class.parseNode(system.compiler); |
| if (node !== null) { |
| var script = _class.getCompilationUnit().script; |
| var span = system.compiler.spanFromNode(node, script.uri); |
| return new Dart2JsLocation(script, span); |
| } |
| } |
| return super.location; |
| } |
| |
| void _ensureMembers() { |
| if (_members == null) { |
| _members = <String, Dart2JsMemberMirror>{}; |
| _class.forEachMember((_, e) { |
| for (var member in _convertElementMemberToMemberMirrors(this, e)) { |
| assert(!_members.containsKey(member.simpleName)); |
| _members[member.simpleName] = member; |
| } |
| }); |
| } |
| } |
| |
| Map<String, MemberMirror> get declaredMembers { |
| _ensureMembers(); |
| return new ImmutableMapWrapper<String, MemberMirror>(_members); |
| } |
| |
| bool get isObject => _class == system.compiler.objectClass; |
| |
| bool get isDynamic => false; |
| |
| bool get isVoid => false; |
| |
| bool get isTypeVariable => false; |
| |
| bool get isTypedef => false; |
| |
| bool get isFunction => false; |
| |
| InterfaceMirror get declaration => this; |
| |
| InterfaceMirror get superclass { |
| if (_class.supertype != null) { |
| return new Dart2JsInterfaceTypeMirror(system, _class.supertype); |
| } |
| return null; |
| } |
| |
| List<InterfaceMirror> get interfaces { |
| var list = <InterfaceMirror>[]; |
| Link<DartType> link = _class.interfaces; |
| while (!link.isEmpty) { |
| var type = _convertTypeToTypeMirror(system, link.head, |
| system.compiler.types.dynamicType); |
| list.add(type); |
| link = link.tail; |
| } |
| return list; |
| } |
| |
| bool get isClass => !_class.isInterface(); |
| |
| bool get isInterface => _class.isInterface(); |
| |
| bool get isAbstract => _class.modifiers.isAbstract(); |
| |
| bool get isPrivate => _isPrivate(simpleName); |
| |
| bool get isDeclaration => true; |
| |
| List<TypeMirror> get typeArguments { |
| throw new UnsupportedError( |
| 'Declarations do not have type arguments'); |
| } |
| |
| List<TypeVariableMirror> get typeVariables { |
| if (_typeVariables == null) { |
| _typeVariables = <TypeVariableMirror>[]; |
| _class.ensureResolved(system.compiler); |
| for (TypeVariableType typeVariable in _class.typeVariables) { |
| _typeVariables.add( |
| new Dart2JsTypeVariableMirror(system, typeVariable)); |
| } |
| } |
| return _typeVariables; |
| } |
| |
| Map<String, MethodMirror> get constructors { |
| _ensureMembers(); |
| return new AsFilteredImmutableMap<String, MemberMirror, MethodMirror>( |
| _members, (m) => m.isConstructor ? m : null); |
| } |
| |
| /** |
| * Returns the default type for this interface. |
| */ |
| InterfaceMirror get defaultType { |
| if (_class.defaultClass != null) { |
| return new Dart2JsInterfaceTypeMirror(system, _class.defaultClass); |
| } |
| return null; |
| } |
| |
| bool operator ==(Object other) { |
| if (this === other) { |
| return true; |
| } |
| if (other is! InterfaceMirror) { |
| return false; |
| } |
| if (library != other.library) { |
| return false; |
| } |
| if (isDeclaration !== other.isDeclaration) { |
| return false; |
| } |
| return qualifiedName == other.qualifiedName; |
| } |
| } |
| |
| class Dart2JsTypedefMirror extends Dart2JsTypeElementMirror |
| implements Dart2JsTypeMirror, TypedefMirror { |
| final Dart2JsLibraryMirror _library; |
| List<TypeVariableMirror> _typeVariables; |
| TypeMirror _definition; |
| |
| Dart2JsTypedefMirror(Dart2JsMirrorSystem system, TypedefType _typedef) |
| : this._library = system.getLibrary(_typedef.element.getLibrary()), |
| super(system, _typedef); |
| |
| Dart2JsTypedefMirror.fromLibrary(Dart2JsLibraryMirror library, |
| TypedefType _typedef) |
| : this._library = library, |
| super(library.system, _typedef); |
| |
| TypedefType get _typedef => _type; |
| |
| String get qualifiedName => '${library.qualifiedName}.${simpleName}'; |
| |
| Location get location { |
| var node = _typedef.element.parseNode(_diagnosticListener); |
| if (node !== null) { |
| var script = _typedef.element.getCompilationUnit().script; |
| var span = system.compiler.spanFromNode(node, script.uri); |
| return new Dart2JsLocation(script, span); |
| } |
| return super.location; |
| } |
| |
| LibraryMirror get library => _library; |
| |
| bool get isTypedef => true; |
| |
| List<TypeMirror> get typeArguments { |
| throw new UnsupportedError( |
| 'Declarations do not have type arguments'); |
| } |
| |
| List<TypeVariableMirror> get typeVariables { |
| if (_typeVariables == null) { |
| _typeVariables = <TypeVariableMirror>[]; |
| for (TypeVariableType typeVariable in _typedef.typeArguments) { |
| _typeVariables.add( |
| new Dart2JsTypeVariableMirror(system, typeVariable)); |
| } |
| } |
| return _typeVariables; |
| } |
| |
| TypeMirror get definition { |
| if (_definition === null) { |
| // TODO(johnniwinther): Should be [ensureResolved]. |
| system.compiler.resolveTypedef(_typedef.element); |
| _definition = _convertTypeToTypeMirror( |
| system, |
| _typedef.element.alias, |
| system.compiler.types.dynamicType, |
| _typedef.element.functionSignature); |
| } |
| return _definition; |
| } |
| |
| Map<String, MemberMirror> get declaredMembers => |
| const <String, MemberMirror>{}; |
| |
| InterfaceMirror get declaration => this; |
| |
| // TODO(johnniwinther): How should a typedef respond to these? |
| InterfaceMirror get superclass => null; |
| |
| List<InterfaceMirror> get interfaces => const <InterfaceMirror>[]; |
| |
| bool get isClass => false; |
| |
| bool get isInterface => false; |
| |
| bool get isPrivate => _isPrivate(simpleName); |
| |
| bool get isDeclaration => true; |
| |
| bool get isAbstract => false; |
| |
| Map<String, MethodMirror> get constructors => |
| const <String, MethodMirror>{}; |
| |
| InterfaceMirror get defaultType => null; |
| } |
| |
| class Dart2JsTypeVariableMirror extends Dart2JsTypeElementMirror |
| implements TypeVariableMirror { |
| final TypeVariableType _typeVariableType; |
| InterfaceMirror _declarer; |
| |
| Dart2JsTypeVariableMirror(Dart2JsMirrorSystem system, |
| TypeVariableType typeVariableType) |
| : this._typeVariableType = typeVariableType, |
| super(system, typeVariableType) { |
| assert(_typeVariableType !== null); |
| } |
| |
| |
| String get qualifiedName => '${declarer.qualifiedName}.${simpleName}'; |
| |
| InterfaceMirror get declarer { |
| if (_declarer === null) { |
| if (_typeVariableType.element.enclosingElement.isClass()) { |
| _declarer = new Dart2JsInterfaceMirror(system, |
| _typeVariableType.element.enclosingElement); |
| } else if (_typeVariableType.element.enclosingElement.isTypedef()) { |
| _declarer = new Dart2JsTypedefMirror(system, |
| _typeVariableType.element.enclosingElement.computeType( |
| system.compiler)); |
| } |
| } |
| return _declarer; |
| } |
| |
| LibraryMirror get library => declarer.library; |
| |
| bool get isTypeVariable => true; |
| |
| TypeMirror get bound => _convertTypeToTypeMirror( |
| system, |
| _typeVariableType.element.bound, |
| system.compiler.objectClass.computeType(system.compiler)); |
| |
| bool operator ==(Object other) { |
| if (this === other) { |
| return true; |
| } |
| if (other is! TypeVariableMirror) { |
| return false; |
| } |
| if (declarer != other.declarer) { |
| return false; |
| } |
| return qualifiedName == other.qualifiedName; |
| } |
| } |
| |
| |
| //------------------------------------------------------------------------------ |
| // Types |
| //------------------------------------------------------------------------------ |
| |
| abstract class Dart2JsTypeElementMirror extends Dart2JsProxyMirror |
| implements Dart2JsTypeMirror { |
| final DartType _type; |
| |
| Dart2JsTypeElementMirror(Dart2JsMirrorSystem system, this._type) |
| : super(system); |
| |
| String get simpleName => _type.name.slowToString(); |
| |
| Location get location { |
| var script = _type.element.getCompilationUnit().script; |
| return new Dart2JsLocation(script, |
| system.compiler.spanFromElement(_type.element)); |
| } |
| |
| LibraryMirror get library { |
| return system.getLibrary(_type.element.getLibrary()); |
| } |
| |
| bool get isObject => false; |
| |
| bool get isVoid => false; |
| |
| bool get isDynamic => false; |
| |
| bool get isTypeVariable => false; |
| |
| bool get isTypedef => false; |
| |
| bool get isFunction => false; |
| |
| String toString() => _type.element.toString(); |
| } |
| |
| class Dart2JsInterfaceTypeMirror extends Dart2JsTypeElementMirror |
| implements InterfaceMirror { |
| List<TypeMirror> _typeArguments; |
| |
| Dart2JsInterfaceTypeMirror(Dart2JsMirrorSystem system, |
| InterfaceType interfaceType) |
| : super(system, interfaceType); |
| |
| InterfaceType get _interfaceType => _type; |
| |
| String get qualifiedName => declaration.qualifiedName; |
| |
| // TODO(johnniwinther): Substitute type arguments for type variables. |
| Map<String, MemberMirror> get declaredMembers => declaration.declaredMembers; |
| |
| bool get isObject => system.compiler.objectClass == _type.element; |
| |
| bool get isDynamic => system.compiler.dynamicClass == _type.element; |
| |
| InterfaceMirror get declaration |
| => new Dart2JsInterfaceMirror(system, _type.element); |
| |
| // TODO(johnniwinther): Substitute type arguments for type variables. |
| InterfaceMirror get superclass => declaration.superclass; |
| |
| // TODO(johnniwinther): Substitute type arguments for type variables. |
| List<InterfaceMirror> get interfaces => declaration.interfaces; |
| |
| bool get isClass => declaration.isClass; |
| |
| bool get isInterface => declaration.isInterface; |
| |
| bool get isAbstract => declaration.isAbstract; |
| |
| bool get isPrivate => declaration.isPrivate; |
| |
| bool get isDeclaration => false; |
| |
| List<TypeMirror> get typeArguments { |
| if (_typeArguments == null) { |
| _typeArguments = <TypeMirror>[]; |
| Link<DartType> type = _interfaceType.arguments; |
| while (type != null && type.head != null) { |
| _typeArguments.add(_convertTypeToTypeMirror(system, type.head, |
| system.compiler.types.dynamicType)); |
| type = type.tail; |
| } |
| } |
| return _typeArguments; |
| } |
| |
| List<TypeVariableMirror> get typeVariables => declaration.typeVariables; |
| |
| // TODO(johnniwinther): Substitute type arguments for type variables. |
| Map<String, MethodMirror> get constructors => declaration.constructors; |
| |
| // TODO(johnniwinther): Substitute type arguments for type variables? |
| InterfaceMirror get defaultType => declaration.defaultType; |
| |
| bool operator ==(Object other) { |
| if (this === other) { |
| return true; |
| } |
| if (other is! InterfaceMirror) { |
| return false; |
| } |
| if (other.isDeclaration) { |
| return false; |
| } |
| if (declaration != other.declaration) { |
| return false; |
| } |
| var thisTypeArguments = typeArguments.iterator(); |
| var otherTypeArguments = other.typeArguments.iterator(); |
| while (thisTypeArguments.hasNext && otherTypeArguments.hasNext) { |
| if (thisTypeArguments.next() != otherTypeArguments.next()) { |
| return false; |
| } |
| } |
| return !thisTypeArguments.hasNext && !otherTypeArguments.hasNext; |
| } |
| } |
| |
| |
| class Dart2JsFunctionTypeMirror extends Dart2JsTypeElementMirror |
| implements FunctionTypeMirror { |
| final FunctionSignature _functionSignature; |
| List<ParameterMirror> _parameters; |
| |
| Dart2JsFunctionTypeMirror(Dart2JsMirrorSystem system, |
| FunctionType functionType, this._functionSignature) |
| : super(system, functionType) { |
| assert (_functionSignature !== null); |
| } |
| |
| FunctionType get _functionType => _type; |
| |
| // TODO(johnniwinther): Is this the qualified name of a function type? |
| String get qualifiedName => declaration.qualifiedName; |
| |
| // TODO(johnniwinther): Substitute type arguments for type variables. |
| Map<String, MemberMirror> get declaredMembers { |
| var method = callMethod; |
| if (method !== null) { |
| var map = new Map<String, MemberMirror>.from( |
| declaration.declaredMembers); |
| var name = method.qualifiedName; |
| assert(!map.containsKey(name)); |
| map[name] = method; |
| return new ImmutableMapWrapper<String, MemberMirror>(map); |
| } |
| return declaration.declaredMembers; |
| } |
| |
| bool get isFunction => true; |
| |
| MethodMirror get callMethod => _convertElementMethodToMethodMirror( |
| system.getLibrary(_functionType.element.getLibrary()), |
| _functionType.element); |
| |
| InterfaceMirror get declaration |
| => new Dart2JsInterfaceMirror(system, system.compiler.functionClass); |
| |
| // TODO(johnniwinther): Substitute type arguments for type variables. |
| InterfaceMirror get superclass => declaration.superclass; |
| |
| // TODO(johnniwinther): Substitute type arguments for type variables. |
| List<InterfaceMirror> get interfaces => declaration.interfaces; |
| |
| bool get isClass => declaration.isClass; |
| |
| bool get isInterface => declaration.isInterface; |
| |
| bool get isPrivate => declaration.isPrivate; |
| |
| bool get isDeclaration => false; |
| |
| bool get isAbstract => false; |
| |
| List<TypeMirror> get typeArguments => const <TypeMirror>[]; |
| |
| List<TypeVariableMirror> get typeVariables => declaration.typeVariables; |
| |
| Map<String, MethodMirror> get constructors => <String, MethodMirror>{}; |
| |
| InterfaceMirror get defaultType => null; |
| |
| TypeMirror get returnType { |
| return _convertTypeToTypeMirror(system, _functionType.returnType, |
| system.compiler.types.dynamicType); |
| } |
| |
| List<ParameterMirror> get parameters { |
| if (_parameters === null) { |
| _parameters = _parametersFromFunctionSignature(system, callMethod, |
| _functionSignature); |
| } |
| return _parameters; |
| } |
| } |
| |
| class Dart2JsVoidMirror extends Dart2JsTypeElementMirror { |
| |
| Dart2JsVoidMirror(Dart2JsMirrorSystem system, VoidType voidType) |
| : super(system, voidType); |
| |
| VoidType get _voidType => _type; |
| |
| String get qualifiedName => simpleName; |
| |
| /** |
| * The void type has no location. |
| */ |
| Location get location => null; |
| |
| /** |
| * The void type has no library. |
| */ |
| LibraryMirror get library => null; |
| |
| bool get isVoid => true; |
| |
| bool operator ==(Object other) { |
| if (this === other) { |
| return true; |
| } |
| if (other is! TypeMirror) { |
| return false; |
| } |
| return other.isVoid; |
| } |
| } |
| |
| |
| class Dart2JsDynamicMirror extends Dart2JsTypeElementMirror { |
| Dart2JsDynamicMirror(Dart2JsMirrorSystem system, InterfaceType voidType) |
| : super(system, voidType); |
| |
| InterfaceType get _dynamicType => _type; |
| |
| String get qualifiedName => simpleName; |
| |
| /** |
| * The dynamic type has no location. |
| */ |
| Location get location => null; |
| |
| /** |
| * The dynamic type has no library. |
| */ |
| LibraryMirror get library => null; |
| |
| bool get isDynamic => true; |
| |
| bool operator ==(Object other) { |
| if (this === other) { |
| return true; |
| } |
| if (other is! TypeMirror) { |
| return false; |
| } |
| return other.isDynamic; |
| } |
| } |
| |
| //------------------------------------------------------------------------------ |
| // Member mirrors implementation. |
| //------------------------------------------------------------------------------ |
| |
| class Dart2JsMethodMirror extends Dart2JsElementMirror |
| implements Dart2JsMemberMirror, MethodMirror { |
| final Dart2JsObjectMirror _objectMirror; |
| String _simpleName; |
| String _displayName; |
| String _constructorName; |
| String _operatorName; |
| Dart2JsMethodKind _kind; |
| |
| Dart2JsMethodMirror(Dart2JsObjectMirror objectMirror, |
| FunctionElement function) |
| : this._objectMirror = objectMirror, |
| super(objectMirror.system, function) { |
| _simpleName = _element.name.slowToString(); |
| if (_function.kind == ElementKind.GETTER) { |
| _kind = Dart2JsMethodKind.GETTER; |
| _displayName = _simpleName; |
| } else if (_function.kind == ElementKind.SETTER) { |
| _kind = Dart2JsMethodKind.SETTER; |
| _displayName = _simpleName; |
| _simpleName = '$_simpleName='; |
| } else if (_function.kind == ElementKind.GENERATIVE_CONSTRUCTOR) { |
| _constructorName = ''; |
| int dollarPos = _simpleName.indexOf('\$'); |
| if (dollarPos != -1) { |
| _constructorName = _simpleName.substring(dollarPos + 1); |
| _simpleName = _simpleName.substring(0, dollarPos); |
| // Simple name is TypeName.constructorName. |
| _simpleName = '$_simpleName.$_constructorName'; |
| } else { |
| // Simple name is TypeName. |
| } |
| if (_function.modifiers.isConst()) { |
| _kind = Dart2JsMethodKind.CONST; |
| } else { |
| _kind = Dart2JsMethodKind.CONSTRUCTOR; |
| } |
| _displayName = _simpleName; |
| } else if (_function.modifiers.isFactory()) { |
| _kind = Dart2JsMethodKind.FACTORY; |
| _constructorName = ''; |
| int dollarPos = _simpleName.indexOf('\$'); |
| if (dollarPos != -1) { |
| _constructorName = _simpleName.substring(dollarPos+1); |
| _simpleName = _simpleName.substring(0, dollarPos); |
| _simpleName = '$_simpleName.$_constructorName'; |
| } |
| // Simple name is TypeName.constructorName. |
| _displayName = _simpleName; |
| } else if (_simpleName == 'negate') { |
| _kind = Dart2JsMethodKind.OPERATOR; |
| _operatorName = '-'; |
| // Simple name is 'unary-'. |
| _simpleName = Mirror.UNARY_MINUS; |
| // Display name is 'operator operatorName'. |
| _displayName = 'operator -'; |
| } else if (_simpleName.startsWith('operator\$')) { |
| String str = _simpleName.substring(9); |
| _simpleName = 'operator'; |
| _kind = Dart2JsMethodKind.OPERATOR; |
| _operatorName = _getOperatorFromOperatorName(str); |
| // Simple name is 'operator operatorName'. |
| _simpleName = _operatorName; |
| // Display name is 'operator operatorName'. |
| _displayName = 'operator $_operatorName'; |
| } else { |
| _kind = Dart2JsMethodKind.NORMAL; |
| _displayName = _simpleName; |
| } |
| } |
| |
| FunctionElement get _function => _element; |
| |
| String get simpleName => _simpleName; |
| |
| String get displayName => _displayName; |
| |
| String get qualifiedName |
| => '${surroundingDeclaration.qualifiedName}.$simpleName'; |
| |
| ObjectMirror get surroundingDeclaration => _objectMirror; |
| |
| bool get isTopLevel => _objectMirror is LibraryMirror; |
| |
| bool get isConstructor |
| => _kind == Dart2JsMethodKind.CONSTRUCTOR || isConst || isFactory; |
| |
| bool get isField => false; |
| |
| bool get isMethod => !isConstructor; |
| |
| bool get isPrivate => |
| isConstructor ? _isPrivate(constructorName) : _isPrivate(simpleName); |
| |
| bool get isStatic => _function.modifiers.isStatic(); |
| |
| List<ParameterMirror> get parameters { |
| return _parametersFromFunctionSignature(system, this, |
| _function.computeSignature(system.compiler)); |
| } |
| |
| TypeMirror get returnType => _convertTypeToTypeMirror( |
| system, _function.computeSignature(system.compiler).returnType, |
| system.compiler.types.dynamicType); |
| |
| bool get isAbstract => _function.modifiers.isAbstract(); |
| |
| bool get isConst => _kind == Dart2JsMethodKind.CONST; |
| |
| bool get isFactory => _kind == Dart2JsMethodKind.FACTORY; |
| |
| String get constructorName => _constructorName; |
| |
| bool get isGetter => _kind == Dart2JsMethodKind.GETTER; |
| |
| bool get isSetter => _kind == Dart2JsMethodKind.SETTER; |
| |
| bool get isOperator => _kind == Dart2JsMethodKind.OPERATOR; |
| |
| String get operatorName => _operatorName; |
| |
| Location get location { |
| var node = _function.parseNode(_diagnosticListener); |
| if (node !== null) { |
| var script = _function.getCompilationUnit().script; |
| var span = system.compiler.spanFromNode(node, script.uri); |
| return new Dart2JsLocation(script, span); |
| } |
| return super.location; |
| } |
| |
| } |
| |
| class Dart2JsFieldMirror extends Dart2JsElementMirror |
| implements Dart2JsMemberMirror, FieldMirror { |
| Dart2JsObjectMirror _objectMirror; |
| VariableElement _variable; |
| |
| Dart2JsFieldMirror(Dart2JsObjectMirror objectMirror, |
| VariableElement variable) |
| : this._objectMirror = objectMirror, |
| this._variable = variable, |
| super(objectMirror.system, variable); |
| |
| String get qualifiedName |
| => '${surroundingDeclaration.qualifiedName}.$simpleName'; |
| |
| ObjectMirror get surroundingDeclaration => _objectMirror; |
| |
| bool get isTopLevel => _objectMirror is LibraryMirror; |
| |
| bool get isConstructor => false; |
| |
| bool get isField => true; |
| |
| bool get isMethod => false; |
| |
| bool get isPrivate => _isPrivate(simpleName); |
| |
| bool get isStatic => _variable.modifiers.isStatic(); |
| |
| bool get isFinal => _variable.modifiers.isFinal(); |
| |
| bool get isConst => _variable.modifiers.isConst(); |
| |
| TypeMirror get type => _convertTypeToTypeMirror(system, |
| _variable.computeType(system.compiler), |
| system.compiler.types.dynamicType); |
| |
| Location get location { |
| var script = _variable.getCompilationUnit().script; |
| var node = _variable.variables.parseNode(_diagnosticListener); |
| if (node !== null) { |
| var span = system.compiler.spanFromNode(node, script.uri); |
| return new Dart2JsLocation(script, span); |
| } else { |
| var span = system.compiler.spanFromElement(_variable); |
| return new Dart2JsLocation(script, span); |
| } |
| } |
| } |
| |