OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 library kernel.canonical_name; |
| 5 |
| 6 import 'ast.dart'; |
| 7 |
| 8 /// A string sequence that identifies a library, class, or member. |
| 9 /// |
| 10 /// Canonical names are organized in a prefix tree. Each node knows its |
| 11 /// parent, children, and the AST node it is currently bound to. |
| 12 /// |
| 13 /// The following schema specifies how the canonical name of a given object |
| 14 /// is defined: |
| 15 /// |
| 16 /// Library: |
| 17 /// URI of library |
| 18 /// |
| 19 /// Class: |
| 20 /// Canonical name of enclosing library |
| 21 /// Name of class |
| 22 /// |
| 23 /// Constructor: |
| 24 /// Canonical name of enclosing class or library |
| 25 /// "@constructors" |
| 26 /// Qualified name |
| 27 /// |
| 28 /// Field: |
| 29 /// Canonical name of enclosing class or library |
| 30 /// "@fields" |
| 31 /// Qualified name |
| 32 /// |
| 33 /// Procedure that is not an accessor: |
| 34 /// Canonical name of enclosing class or library |
| 35 /// "@methods" |
| 36 /// Qualified name |
| 37 /// |
| 38 /// Procedure that is a getter: |
| 39 /// Canonical name of enclosing class or library |
| 40 /// "@getters" |
| 41 /// Qualified name |
| 42 /// |
| 43 /// Procedure that is a setter: |
| 44 /// Canonical name of enclosing class or library |
| 45 /// "@setters" |
| 46 /// Qualified name |
| 47 /// |
| 48 /// Qualified name: |
| 49 /// if private: URI of library |
| 50 /// Name text |
| 51 /// |
| 52 /// The "qualified name" allows a member to have a name that is private to |
| 53 /// a library other than the one containing that member. |
| 54 class CanonicalName { |
| 55 final CanonicalName parent; |
| 56 final String name; |
| 57 |
| 58 Map<String, CanonicalName> _children; |
| 59 |
| 60 /// The library, class, or member bound to this name. |
| 61 Reference reference; |
| 62 |
| 63 /// Temporary index used during serialization. |
| 64 int index = -1; |
| 65 |
| 66 CanonicalName._(this.parent, this.name) { |
| 67 assert(name != null); |
| 68 } |
| 69 |
| 70 CanonicalName.root() |
| 71 : parent = null, |
| 72 name = ''; |
| 73 |
| 74 bool get isRoot => parent == null; |
| 75 |
| 76 Iterable<CanonicalName> get children => |
| 77 _children?.values ?? const <CanonicalName>[]; |
| 78 |
| 79 CanonicalName getChild(String name) { |
| 80 var map = _children ??= <String, CanonicalName>{}; |
| 81 return map[name] ??= new CanonicalName._(this, name); |
| 82 } |
| 83 |
| 84 CanonicalName getChildFromUri(Uri uri) { |
| 85 // Note that the Uri class caches its string representation, and all library |
| 86 // URIs will be stringified for serialization anyway, so there is no |
| 87 // significant cost for converting the Uri to a string here. |
| 88 return getChild('$uri'); |
| 89 } |
| 90 |
| 91 CanonicalName getChildFromQualifiedName(Name name) { |
| 92 return name.isPrivate |
| 93 ? getChildFromUri(name.library.importUri).getChild(name.name) |
| 94 : getChild(name.name); |
| 95 } |
| 96 |
| 97 CanonicalName getChildFromMember(Member member) { |
| 98 return getChild(getMemberQualifier(member)) |
| 99 .getChildFromQualifiedName(member.name); |
| 100 } |
| 101 |
| 102 void bindTo(Reference target) { |
| 103 if (reference == target) return; |
| 104 if (reference != null) { |
| 105 throw '$this is already bound'; |
| 106 } |
| 107 if (target.canonicalName != null) { |
| 108 throw 'Cannot bind $this to ${target.node}, target is already bound to ' |
| 109 '${target.canonicalName}'; |
| 110 } |
| 111 target.canonicalName = this; |
| 112 this.reference = target; |
| 113 } |
| 114 |
| 115 void unbind() { |
| 116 if (reference == null) return; |
| 117 assert(reference.canonicalName == this); |
| 118 reference.canonicalName = null; |
| 119 reference = null; |
| 120 } |
| 121 |
| 122 void unbindAll() { |
| 123 unbind(); |
| 124 for (var child in children) { |
| 125 child.unbindAll(); |
| 126 } |
| 127 } |
| 128 |
| 129 String toString() => parent == null ? 'root' : '$parent::$name'; |
| 130 |
| 131 Reference getReference() { |
| 132 return reference ??= (new Reference()..canonicalName = this); |
| 133 } |
| 134 |
| 135 static String getMemberQualifier(Member member) { |
| 136 if (member is Procedure) { |
| 137 if (member.isGetter) return '@getters'; |
| 138 if (member.isSetter) return '@setters'; |
| 139 return '@methods'; |
| 140 } |
| 141 if (member is Field) { |
| 142 return '@fields'; |
| 143 } |
| 144 if (member is Constructor) { |
| 145 return '@constructors'; |
| 146 } |
| 147 throw 'Unexpected member: $member'; |
| 148 } |
| 149 } |
OLD | NEW |