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 /// URI 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 LinkedNode definition; | |
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 /// Used as temporary measure to get the dart2js-kernel adaptor working. | |
ahe
2017/02/02 16:24:01
Add TODO to remove?
asgerf
2017/02/03 10:31:16
Same as previous answer.
| |
75 /// | |
76 /// This canonical name cannot be used in serialization but can hold in-memory | |
77 /// references. | |
78 CanonicalName.dummy() | |
79 : parent = null, | |
80 name = 'dummy'; | |
81 | |
82 bool get isRoot => parent == null; | |
83 | |
84 /// True if this is a fake canonical name object used by the dart2js/kernel | |
ahe
2017/02/02 16:24:01
Ditto?
asgerf
2017/02/03 10:31:16
Same as previous answer.
| |
85 /// adaptor. | |
86 bool get isDummy => parent == null && name == 'dummy'; | |
87 | |
88 Iterable<CanonicalName> get children => | |
89 _children?.values ?? const <CanonicalName>[]; | |
90 | |
91 CanonicalName getChild(String name) { | |
92 var map = _children ??= <String, CanonicalName>{}; | |
93 return map[name] ??= new CanonicalName._(this, name); | |
94 } | |
95 | |
96 CanonicalName getChildFromUri(Uri uri) { | |
97 // Note that the Uri class caches its string representation, and all library | |
98 // URIs will be stringified for serialization anyway, so there is no | |
99 // significant cost for converting the Uri to a string here. | |
100 return getChild('$uri'); | |
101 } | |
102 | |
103 CanonicalName getChildFromQualifiedName(Name name) { | |
104 return name.isPrivate | |
105 ? getChild(name.libraryName.name).getChild(name.name) | |
106 : getChild(name.name); | |
107 } | |
108 | |
109 CanonicalName getChildFromMember(Member member) { | |
110 return getChild(getMemberQualifier(member)) | |
111 .getChildFromQualifiedName(member.name); | |
112 } | |
113 | |
114 void bindTo(LinkedNode target) { | |
115 if (definition == target) return; | |
116 if (definition != null) { | |
117 throw '$this is already bound'; | |
118 } | |
119 if (target.canonicalName != null) { | |
120 throw 'Cannot bind $this to $target, target is already bound'; | |
121 } | |
122 target.canonicalName = this; | |
123 this.definition = target; | |
124 } | |
125 | |
126 void unbind() { | |
127 if (definition == null) return; | |
128 assert(definition.canonicalName == this); | |
129 definition.canonicalName = null; | |
130 definition = null; | |
131 } | |
132 | |
133 String toString() => parent == null ? 'root' : '$parent::$name'; | |
134 | |
135 Library get asLibrary { | |
ahe
2017/02/02 16:24:01
Nice!
asgerf
2017/02/03 10:31:16
Acknowledged.
| |
136 if (definition == null) throw '$this is not bound'; | |
137 return definition as Library; | |
138 } | |
139 | |
140 Class get asClass { | |
141 if (definition == null) throw '$this is not bound'; | |
142 return definition as Class; | |
143 } | |
144 | |
145 Member get asMember { | |
146 if (definition == null) throw '$this is not bound'; | |
147 return definition as Member; | |
148 } | |
149 | |
150 Constructor get asConstructor { | |
151 if (definition == null) throw '$this is not bound'; | |
152 return definition as Constructor; | |
153 } | |
154 | |
155 Procedure get asProcedure { | |
156 if (definition == null) throw '$this is not bound'; | |
157 return definition as Procedure; | |
158 } | |
159 | |
160 Field get asField { | |
161 if (definition == null) throw '$this is not bound'; | |
162 return definition as Field; | |
163 } | |
164 | |
165 static String getMemberQualifier(Member member) { | |
166 if (member is Procedure) { | |
167 if (member.isGetter) return '@getters'; | |
168 if (member.isSetter) return '@setters'; | |
169 return '@methods'; | |
170 } | |
171 if (member is Field) { | |
172 return '@fields'; | |
173 } | |
174 if (member is Constructor) { | |
175 return '@constructors'; | |
176 } | |
177 throw 'Unexpected member: $member'; | |
178 } | |
179 } | |
OLD | NEW |