| Index: lib/dartdoc/frog/library.dart
|
| diff --git a/lib/dartdoc/frog/library.dart b/lib/dartdoc/frog/library.dart
|
| deleted file mode 100644
|
| index 3a0beefbbb848a0f301222a4fc494d234342857c..0000000000000000000000000000000000000000
|
| --- a/lib/dartdoc/frog/library.dart
|
| +++ /dev/null
|
| @@ -1,509 +0,0 @@
|
| -// 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.
|
| -
|
| -class LibraryImport {
|
| - final String prefix;
|
| - final Library library;
|
| - final SourceSpan span;
|
| - LibraryImport(this.library, [this.prefix, this.span]);
|
| -}
|
| -
|
| -// TODO(jimhug): Make this more useful for good error messages.
|
| -class AmbiguousMember extends Member {
|
| - List<Member> members;
|
| - AmbiguousMember(String name, this.members): super(name, null);
|
| -}
|
| -
|
| -
|
| -/** Represents a Dart library. */
|
| -class Library extends Element {
|
| - final SourceFile baseSource;
|
| - Map<String, DefinedType> types;
|
| - List<LibraryImport> imports;
|
| - String sourceDir;
|
| - List<SourceFile> natives;
|
| - List<SourceFile> sources;
|
| -
|
| - Map<String, Member> _topNames;
|
| - Map<String, MemberSet> _privateMembers;
|
| -
|
| - /** The type that holds top level types in the library. */
|
| - DefinedType topType;
|
| -
|
| - /** Set to true by [WorldGenerator] once this type has been written. */
|
| - bool isWritten = false;
|
| -
|
| - Library(this.baseSource) : super(null, null) {
|
| - sourceDir = dirname(baseSource.filename);
|
| - topType = new DefinedType(null, this, null, true);
|
| - types = { '': topType };
|
| - imports = [];
|
| - natives = [];
|
| - sources = [];
|
| - _privateMembers = {};
|
| - }
|
| -
|
| - Element get enclosingElement() => null;
|
| - Library get library() => this;
|
| -
|
| - bool get isNative() => topType.isNative;
|
| -
|
| - bool get isCore() => this == world.corelib;
|
| - bool get isCoreImpl() => this == world.coreimpl;
|
| -
|
| - // TODO(jmesserly): we shouldn't be special casing DOM anywhere.
|
| - bool get isDomOrHtml() => this == world.dom || this == world.html;
|
| -
|
| - SourceSpan get span() => new SourceSpan(baseSource, 0, 0);
|
| -
|
| - String makeFullPath(String filename) {
|
| - if (filename.startsWith('dart:')) return filename;
|
| - if (filename.startsWith('package:')) return filename;
|
| - // TODO(jmesserly): replace with node.js path.resolve
|
| - if (filename.startsWith('/')) return filename;
|
| - if (filename.startsWith('file:///')) return filename;
|
| - if (filename.startsWith('http://')) return filename;
|
| - if (const RegExp('^[a-zA-Z]:/').hasMatch(filename)) return filename;
|
| - return joinPaths(sourceDir, filename);
|
| - }
|
| -
|
| - /** Adds an import to the library. */
|
| - addImport(String fullname, String prefix, SourceSpan span) {
|
| - var newLib = world.getOrAddLibrary(fullname);
|
| - // Special exemption in spec to ensure core is only imported once
|
| - if (newLib.isCore) return;
|
| - imports.add(new LibraryImport(newLib, prefix, span));
|
| - return newLib;
|
| - }
|
| -
|
| - addNative(String fullname) {
|
| - natives.add(world.reader.readFile(fullname));
|
| - }
|
| -
|
| - MemberSet _findMembers(String name) {
|
| - if (name.startsWith('_')) {
|
| - return _privateMembers[name];
|
| - } else {
|
| - return world._members[name];
|
| - }
|
| - }
|
| -
|
| - _addMember(Member member) {
|
| - if (member.isPrivate) {
|
| - if (member.isStatic) {
|
| - if (member.declaringType.isTop) {
|
| - world._addTopName(member);
|
| - }
|
| - } else {
|
| - var members = _privateMembers[member.name];
|
| - if (members == null) {
|
| - members = new MemberSet(member, isVar: true);
|
| - _privateMembers[member.name] = members;
|
| - } else {
|
| - members.add(member);
|
| - }
|
| - }
|
| - } else {
|
| - world._addMember(member);
|
| - }
|
| - }
|
| -
|
| - // TODO(jimhug): Cache and share the types as interfaces!
|
| - Type getOrAddFunctionType(Element enclosingElement, String name,
|
| - FunctionDefinition func, MethodData data) {
|
| - // TODO(jimhug): This is redundant now that FunctionDef has type params.
|
| - final def = new FunctionTypeDefinition(func, null, func.span);
|
| - final type = new DefinedType(name, this, def, false);
|
| - type.addMethod(':call', func);
|
| - var m = type.members[':call'];
|
| - m.enclosingElement = enclosingElement;
|
| - m.resolve();
|
| - m._methodData = data;
|
| - // Function types implement the Function interface.
|
| - type.interfaces = [world.functionType];
|
| - return type;
|
| - }
|
| -
|
| - /** Adds a type to the library. */
|
| - DefinedType addType(String name, Node definition, bool isClass) {
|
| - if (types.containsKey(name)) {
|
| - var existingType = types[name];
|
| - if ((isCore || isCoreImpl) && existingType.definition == null) {
|
| - // TODO(jimhug): Validate compatibility with natives.
|
| - existingType.setDefinition(definition);
|
| - } else {
|
| - world.warning('duplicate definition of $name', definition.span,
|
| - existingType.span);
|
| - }
|
| - } else {
|
| - types[name] = new DefinedType(name, this, definition, isClass);
|
| - }
|
| -
|
| - return types[name];
|
| - }
|
| -
|
| - Type findType(NameTypeReference type) {
|
| - Type result = findTypeByName(type.name.name);
|
| - if (result == null) return null;
|
| -
|
| - if (type.names != null) {
|
| - if (type.names.length > 1) {
|
| - // TODO(jmesserly): can we ever get legitimate types with more than one
|
| - // name after the library prefix?
|
| - return null;
|
| - }
|
| -
|
| - if (!result.isTop) {
|
| - // No inner type support. If we get first-class types, this should
|
| - // perform a lookup on the type.
|
| - return null;
|
| - }
|
| -
|
| - // The type we got back was the "top level" library type.
|
| - // Now perform a lookup in that library for the next name.
|
| - return result.library.findTypeByName(type.names[0].name);
|
| - }
|
| - return result;
|
| - }
|
| -
|
| - // TODO(jimhug): Should be merged with new lookup method's logic.
|
| - Type findTypeByName(String name) {
|
| - var ret = types[name];
|
| -
|
| - // Check all imports even if ret != null to detect conflicting names.
|
| - // TODO(jimhug): Only do this on first lookup.
|
| - for (var imported in imports) {
|
| - var newRet = null;
|
| - if (imported.prefix == null) {
|
| - newRet = imported.library.types[name];
|
| - } else if (imported.prefix == name) {
|
| - newRet = imported.library.topType;
|
| - }
|
| - if (newRet != null) {
|
| - // TODO(jimhug): Should not need ret != newRet here or below.
|
| - if (ret != null && ret != newRet) {
|
| - world.error('conflicting types for "$name"', ret.span, newRet.span);
|
| - } else {
|
| - ret = newRet;
|
| - }
|
| - }
|
| - }
|
| - return ret;
|
| - }
|
| -
|
| -
|
| - // TODO(jimhug): Why is it okay to assume node is NameTypeReference in here?
|
| - Type resolveType(TypeReference node, bool typeErrors, bool allowTypeParams) {
|
| - if (node == null) return world.varType;
|
| -
|
| - var ret = findType(node);
|
| -
|
| - if (ret == null) {
|
| - var message = 'cannot find type ${_getDottedName(node)}';
|
| - if (typeErrors) {
|
| - world.error(message, node.span);
|
| - return world.objectType;
|
| - } else {
|
| - world.warning(message, node.span);
|
| - return world.varType;
|
| - }
|
| - }
|
| - return ret;
|
| - }
|
| -
|
| - static String _getDottedName(NameTypeReference type) {
|
| - if (type.names != null) {
|
| - var names = map(type.names, (n) => n.name);
|
| - return '${type.name.name}.${Strings.join(names, ".")}';
|
| - } else {
|
| - return type.name.name;
|
| - }
|
| - }
|
| -
|
| - Member lookup(String name, SourceSpan span) {
|
| - return _topNames[name];
|
| - }
|
| -
|
| - resolve() {
|
| - if (name == null) {
|
| - // TODO(jimhug): More fodder for io library.
|
| - name = baseSource.filename;
|
| - var index = name.lastIndexOf('/', name.length);
|
| - if (index >= 0) {
|
| - name = name.substring(index+1);
|
| - }
|
| - index = name.indexOf('.');
|
| - if (index > 0) {
|
| - name = name.substring(0, index);
|
| - }
|
| - }
|
| - // TODO(jimhug): Expand to handle all illegal id characters
|
| - _jsname =
|
| - name.replaceAll('.', '_').replaceAll(':', '_').replaceAll(' ', '_');
|
| -
|
| - for (var type in types.getValues()) {
|
| - type.resolve();
|
| - }
|
| - }
|
| -
|
| - _addTopName(String name, Member member, [SourceSpan localSpan]) {
|
| - var existing = _topNames[name];
|
| - if (existing === null) {
|
| - _topNames[name] = member;
|
| - } else {
|
| - if (existing is AmbiguousMember) {
|
| - existing.members.add(member);
|
| - } else {
|
| - var newMember = new AmbiguousMember(name, [existing, member]);
|
| - world.error('conflicting members for "$name"',
|
| - existing.span, member.span, localSpan);
|
| - _topNames[name] = newMember;
|
| - }
|
| - }
|
| - }
|
| -
|
| - _addTopNames(Library lib) {
|
| - for (var member in lib.topType.members.getValues()) {
|
| - if (member.isPrivate && lib != this) continue;
|
| - _addTopName(member.name, member);
|
| - }
|
| - for (var type in lib.types.getValues()) {
|
| - if (!type.isTop) {
|
| - if (lib != this && type.typeMember.isPrivate) continue;
|
| - _addTopName(type.name, type.typeMember);
|
| - }
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * This method will check for any conflicts in top-level names in this
|
| - * library. It will also build up a map from top-level names to a single
|
| - * member to be used for future lookups both to keep error messages clean
|
| - * and as a minor perf optimization.
|
| - */
|
| - postResolveChecks() {
|
| - _topNames = {};
|
| - // check for conflicts between top-level names
|
| - _addTopNames(this);
|
| - for (var imported in imports) {
|
| - if (imported.prefix == null) {
|
| - _addTopNames(imported.library);
|
| - } else {
|
| - _addTopName(imported.prefix, imported.library.topType.typeMember,
|
| - imported.span);
|
| - }
|
| - }
|
| - }
|
| -
|
| - visitSources() {
|
| - var visitor = new _LibraryVisitor(this);
|
| - visitor.addSource(baseSource);
|
| - }
|
| -
|
| - toString() => baseSource.filename;
|
| -
|
| - int hashCode() => baseSource.filename.hashCode();
|
| -
|
| - bool operator ==(other) => other is Library &&
|
| - other.baseSource.filename == baseSource.filename;
|
| -}
|
| -
|
| -
|
| -class _LibraryVisitor implements TreeVisitor {
|
| - final Library library;
|
| - DefinedType currentType;
|
| - List<SourceFile> sources;
|
| -
|
| - bool seenImport = false;
|
| - bool seenSource = false;
|
| - bool seenResource = false;
|
| - bool isTop = true;
|
| -
|
| - _LibraryVisitor(this.library) {
|
| - currentType = library.topType;
|
| - sources = [];
|
| - }
|
| -
|
| - addSourceFromName(String name, SourceSpan span) {
|
| - var filename = library.makeFullPath(name);
|
| - if (filename == library.baseSource.filename) {
|
| - world.error('library cannot source itself', span);
|
| - return;
|
| - } else if (sources.some((s) => s.filename == filename)) {
|
| - world.error('file "$filename" has already been sourced', span);
|
| - return;
|
| - }
|
| -
|
| - var source = world.readFile(library.makeFullPath(name));
|
| - sources.add(source);
|
| - }
|
| -
|
| - addSource(SourceFile source) {
|
| - if (library.sources.some((s) => s.filename == source.filename)) {
|
| - // TODO(jimhug): good error location.
|
| - world.error('duplicate source file "${source.filename}"', null);
|
| - return;
|
| - }
|
| - library.sources.add(source);
|
| - final parser = new Parser(source, diet: options.dietParse);
|
| - final unit = parser.compilationUnit();
|
| -
|
| - unit.forEach((def) => def.visit(this));
|
| -
|
| - assert(sources.length == 0 || isTop);
|
| - isTop = false;
|
| - var newSources = sources;
|
| - sources = [];
|
| - for (var newSource in newSources) {
|
| - addSource(newSource);
|
| - }
|
| - }
|
| -
|
| - void visitDirectiveDefinition(DirectiveDefinition node) {
|
| - if (!isTop) {
|
| - world.error('directives not allowed in sourced file', node.span);
|
| - return;
|
| - }
|
| -
|
| - var name;
|
| - switch (node.name.name) {
|
| - case "library":
|
| - name = getSingleStringArg(node);
|
| - if (library.name == null) {
|
| - library.name = name;
|
| - if (seenImport || seenSource || seenResource) {
|
| - world.error('#library must be first directive in file', node.span);
|
| - }
|
| - } else {
|
| - world.error('already specified library name', node.span);
|
| - }
|
| - break;
|
| -
|
| - case "import":
|
| - seenImport = true;
|
| - name = getFirstStringArg(node);
|
| - var prefix = tryGetNamedStringArg(node, 'prefix');
|
| - if (node.arguments.length > 2 ||
|
| - node.arguments.length == 2 && prefix == null) {
|
| - world.error(
|
| - 'expected at most one "name" argument and one optional "prefix"'
|
| - ' but found ${node.arguments.length}', node.span);
|
| - } else if (prefix != null && prefix.indexOf('.') >= 0) {
|
| - world.error('library prefix canot contain "."', node.span);
|
| - } else if (seenSource || seenResource) {
|
| - world.error('#imports must come before any #source or #resource',
|
| - node.span);
|
| - }
|
| -
|
| - // Empty prefix and no prefix are equivalent
|
| - if (prefix == '') prefix = null;
|
| -
|
| - var filename = library.makeFullPath(name);
|
| -
|
| - if (library.imports.some((li) => li.library.baseSource == filename)) {
|
| - // TODO(jimhug): Can you import a lib twice with different prefixes?
|
| - world.error('duplicate import of "$name"', node.span);
|
| - return;
|
| - }
|
| -
|
| - var newLib = library.addImport(filename, prefix, node.span);
|
| - // TODO(jimhug): Add check that imported library has a #library
|
| - break;
|
| -
|
| - case "source":
|
| - seenSource = true;
|
| - name = getSingleStringArg(node);
|
| - addSourceFromName(name, node.span);
|
| - if (seenResource) {
|
| - world.error('#sources must come before any #resource', node.span);
|
| - }
|
| - break;
|
| -
|
| - case "native":
|
| - // TODO(jimhug): Fit this into spec?
|
| - name = getSingleStringArg(node);
|
| - library.addNative(library.makeFullPath(name));
|
| - break;
|
| -
|
| - case "resource":
|
| - // TODO(jmesserly): should we do anything else here?
|
| - seenResource = true;
|
| - getFirstStringArg(node);
|
| - break;
|
| -
|
| - default:
|
| - world.error('unknown directive: ${node.name.name}', node.span);
|
| - }
|
| - }
|
| -
|
| - String getSingleStringArg(DirectiveDefinition node) {
|
| - if (node.arguments.length != 1) {
|
| - world.error(
|
| - 'expected exactly one argument but found ${node.arguments.length}',
|
| - node.span);
|
| - }
|
| - return getFirstStringArg(node);
|
| - }
|
| -
|
| - String getFirstStringArg(DirectiveDefinition node) {
|
| - if (node.arguments.length < 1) {
|
| - world.error(
|
| - 'expected at least one argument but found ${node.arguments.length}',
|
| - node.span);
|
| - }
|
| - var arg = node.arguments[0];
|
| - if (arg.label != null) {
|
| - world.error('label not allowed for directive', node.span);
|
| - }
|
| - return _parseStringArgument(arg);
|
| - }
|
| -
|
| - String tryGetNamedStringArg(DirectiveDefinition node, String argName) {
|
| - var args = node.arguments.filter(
|
| - (a) => a.label != null && a.label.name == argName);
|
| -
|
| - if (args.length == 0) {
|
| - return null;
|
| - }
|
| - if (args.length > 1) {
|
| - world.error('expected at most one "${argName}" argument but found '
|
| - '${node.arguments.length}', node.span);
|
| - }
|
| - // Even though the collection has one arg, this is the easiest way to get
|
| - // the first item.
|
| - for (var arg in args) {
|
| - return _parseStringArgument(arg);
|
| - }
|
| - }
|
| -
|
| - String _parseStringArgument(ArgumentNode arg) {
|
| - var expr = arg.value;
|
| - if (expr is! LiteralExpression || !expr.value.type.isString) {
|
| - world.error('expected string literal', expr.span);
|
| - }
|
| - return expr.value.actualValue;
|
| - }
|
| -
|
| - void visitTypeDefinition(TypeDefinition node) {
|
| - var oldType = currentType;
|
| - currentType = library.addType(node.name.name, node, node.isClass);
|
| - for (var member in node.body) {
|
| - member.visit(this);
|
| - }
|
| - currentType = oldType;
|
| - }
|
| -
|
| - void visitVariableDefinition(VariableDefinition node) {
|
| - currentType.addField(node);
|
| - }
|
| -
|
| - void visitFunctionDefinition(FunctionDefinition node) {
|
| - currentType.addMethod(node.name.name, node);
|
| - }
|
| -
|
| - void visitFunctionTypeDefinition(FunctionTypeDefinition node) {
|
| - var type = library.addType(node.func.name.name, node, false);
|
| - type.addMethod(':call', node.func);
|
| - }
|
| -}
|
|
|