| Index: pkg/kernel/lib/canonical_name.dart
|
| diff --git a/pkg/kernel/lib/canonical_name.dart b/pkg/kernel/lib/canonical_name.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..7bf05dc4507ccf12ad724daf9d10de4e9a5a5f29
|
| --- /dev/null
|
| +++ b/pkg/kernel/lib/canonical_name.dart
|
| @@ -0,0 +1,149 @@
|
| +// Copyright (c) 2016, 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 kernel.canonical_name;
|
| +
|
| +import 'ast.dart';
|
| +
|
| +/// A string sequence that identifies a library, class, or member.
|
| +///
|
| +/// Canonical names are organized in a prefix tree. Each node knows its
|
| +/// parent, children, and the AST node it is currently bound to.
|
| +///
|
| +/// The following schema specifies how the canonical name of a given object
|
| +/// is defined:
|
| +///
|
| +/// Library:
|
| +/// URI of library
|
| +///
|
| +/// Class:
|
| +/// Canonical name of enclosing library
|
| +/// Name of class
|
| +///
|
| +/// Constructor:
|
| +/// Canonical name of enclosing class or library
|
| +/// "@constructors"
|
| +/// Qualified name
|
| +///
|
| +/// Field:
|
| +/// Canonical name of enclosing class or library
|
| +/// "@fields"
|
| +/// Qualified name
|
| +///
|
| +/// Procedure that is not an accessor:
|
| +/// Canonical name of enclosing class or library
|
| +/// "@methods"
|
| +/// Qualified name
|
| +///
|
| +/// Procedure that is a getter:
|
| +/// Canonical name of enclosing class or library
|
| +/// "@getters"
|
| +/// Qualified name
|
| +///
|
| +/// Procedure that is a setter:
|
| +/// Canonical name of enclosing class or library
|
| +/// "@setters"
|
| +/// Qualified name
|
| +///
|
| +/// Qualified name:
|
| +/// if private: URI of library
|
| +/// Name text
|
| +///
|
| +/// The "qualified name" allows a member to have a name that is private to
|
| +/// a library other than the one containing that member.
|
| +class CanonicalName {
|
| + final CanonicalName parent;
|
| + final String name;
|
| +
|
| + Map<String, CanonicalName> _children;
|
| +
|
| + /// The library, class, or member bound to this name.
|
| + Reference reference;
|
| +
|
| + /// Temporary index used during serialization.
|
| + int index = -1;
|
| +
|
| + CanonicalName._(this.parent, this.name) {
|
| + assert(name != null);
|
| + }
|
| +
|
| + CanonicalName.root()
|
| + : parent = null,
|
| + name = '';
|
| +
|
| + bool get isRoot => parent == null;
|
| +
|
| + Iterable<CanonicalName> get children =>
|
| + _children?.values ?? const <CanonicalName>[];
|
| +
|
| + CanonicalName getChild(String name) {
|
| + var map = _children ??= <String, CanonicalName>{};
|
| + return map[name] ??= new CanonicalName._(this, name);
|
| + }
|
| +
|
| + CanonicalName getChildFromUri(Uri uri) {
|
| + // Note that the Uri class caches its string representation, and all library
|
| + // URIs will be stringified for serialization anyway, so there is no
|
| + // significant cost for converting the Uri to a string here.
|
| + return getChild('$uri');
|
| + }
|
| +
|
| + CanonicalName getChildFromQualifiedName(Name name) {
|
| + return name.isPrivate
|
| + ? getChildFromUri(name.library.importUri).getChild(name.name)
|
| + : getChild(name.name);
|
| + }
|
| +
|
| + CanonicalName getChildFromMember(Member member) {
|
| + return getChild(getMemberQualifier(member))
|
| + .getChildFromQualifiedName(member.name);
|
| + }
|
| +
|
| + void bindTo(Reference target) {
|
| + if (reference == target) return;
|
| + if (reference != null) {
|
| + throw '$this is already bound';
|
| + }
|
| + if (target.canonicalName != null) {
|
| + throw 'Cannot bind $this to ${target.node}, target is already bound to '
|
| + '${target.canonicalName}';
|
| + }
|
| + target.canonicalName = this;
|
| + this.reference = target;
|
| + }
|
| +
|
| + void unbind() {
|
| + if (reference == null) return;
|
| + assert(reference.canonicalName == this);
|
| + reference.canonicalName = null;
|
| + reference = null;
|
| + }
|
| +
|
| + void unbindAll() {
|
| + unbind();
|
| + for (var child in children) {
|
| + child.unbindAll();
|
| + }
|
| + }
|
| +
|
| + String toString() => parent == null ? 'root' : '$parent::$name';
|
| +
|
| + Reference getReference() {
|
| + return reference ??= (new Reference()..canonicalName = this);
|
| + }
|
| +
|
| + static String getMemberQualifier(Member member) {
|
| + if (member is Procedure) {
|
| + if (member.isGetter) return '@getters';
|
| + if (member.isSetter) return '@setters';
|
| + return '@methods';
|
| + }
|
| + if (member is Field) {
|
| + return '@fields';
|
| + }
|
| + if (member is Constructor) {
|
| + return '@constructors';
|
| + }
|
| + throw 'Unexpected member: $member';
|
| + }
|
| +}
|
|
|