OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 library dart2js.selector; | 5 library dart2js.selector; |
6 | 6 |
7 import '../common.dart'; | 7 import '../common.dart'; |
8 import '../common/names.dart' show | 8 import '../common/names.dart' show Names; |
9 Names; | 9 import '../elements/elements.dart' |
10 import '../elements/elements.dart' show | 10 show |
11 Element, | 11 Element, |
12 Elements, | 12 Elements, |
13 FunctionElement, | 13 FunctionElement, |
14 FunctionSignature, | 14 FunctionSignature, |
15 Name, | 15 Name, |
16 LibraryElement, | 16 LibraryElement, |
17 PublicName; | 17 PublicName; |
18 import '../util/util.dart' show | 18 import '../util/util.dart' show Hashing; |
19 Hashing; | 19 import '../world.dart' show World; |
20 import '../world.dart' show | |
21 World; | |
22 | 20 |
23 import 'call_structure.dart' show | 21 import 'call_structure.dart' show CallStructure; |
24 CallStructure; | |
25 | 22 |
26 class SelectorKind { | 23 class SelectorKind { |
27 final String name; | 24 final String name; |
28 final int hashCode; | 25 final int hashCode; |
29 const SelectorKind(this.name, this.hashCode); | 26 const SelectorKind(this.name, this.hashCode); |
30 | 27 |
31 static const SelectorKind GETTER = const SelectorKind('getter', 0); | 28 static const SelectorKind GETTER = const SelectorKind('getter', 0); |
32 static const SelectorKind SETTER = const SelectorKind('setter', 1); | 29 static const SelectorKind SETTER = const SelectorKind('setter', 1); |
33 static const SelectorKind CALL = const SelectorKind('call', 2); | 30 static const SelectorKind CALL = const SelectorKind('call', 2); |
34 static const SelectorKind OPERATOR = const SelectorKind('operator', 3); | 31 static const SelectorKind OPERATOR = const SelectorKind('operator', 3); |
35 static const SelectorKind INDEX = const SelectorKind('index', 4); | 32 static const SelectorKind INDEX = const SelectorKind('index', 4); |
36 | 33 |
37 int get index => hashCode; | 34 int get index => hashCode; |
38 | 35 |
39 String toString() => name; | 36 String toString() => name; |
40 | 37 |
41 static List<SelectorKind> values = | 38 static List<SelectorKind> values = const <SelectorKind>[ |
42 const <SelectorKind>[GETTER, SETTER, CALL, OPERATOR, INDEX]; | 39 GETTER, |
| 40 SETTER, |
| 41 CALL, |
| 42 OPERATOR, |
| 43 INDEX |
| 44 ]; |
43 } | 45 } |
44 | 46 |
45 class Selector { | 47 class Selector { |
46 final SelectorKind kind; | 48 final SelectorKind kind; |
47 final Name memberName; | 49 final Name memberName; |
48 final CallStructure callStructure; | 50 final CallStructure callStructure; |
49 | 51 |
50 final int hashCode; | 52 final int hashCode; |
51 | 53 |
52 int get argumentCount => callStructure.argumentCount; | 54 int get argumentCount => callStructure.argumentCount; |
53 int get namedArgumentCount => callStructure.namedArgumentCount; | 55 int get namedArgumentCount => callStructure.namedArgumentCount; |
54 int get positionalArgumentCount => callStructure.positionalArgumentCount; | 56 int get positionalArgumentCount => callStructure.positionalArgumentCount; |
55 List<String> get namedArguments => callStructure.namedArguments; | 57 List<String> get namedArguments => callStructure.namedArguments; |
56 | 58 |
57 String get name => memberName.text; | 59 String get name => memberName.text; |
58 | 60 |
59 LibraryElement get library => memberName.library; | 61 LibraryElement get library => memberName.library; |
60 | 62 |
61 Selector.internal(this.kind, | 63 Selector.internal( |
62 this.memberName, | 64 this.kind, this.memberName, this.callStructure, this.hashCode) { |
63 this.callStructure, | 65 assert(invariant( |
64 this.hashCode) { | 66 NO_LOCATION_SPANNABLE, |
65 assert(invariant(NO_LOCATION_SPANNABLE, | |
66 kind == SelectorKind.INDEX || | 67 kind == SelectorKind.INDEX || |
67 (memberName != Names.INDEX_NAME && | 68 (memberName != Names.INDEX_NAME && |
68 memberName != Names.INDEX_SET_NAME), | 69 memberName != Names.INDEX_SET_NAME), |
69 message: "kind=$kind,memberName=$memberName," | 70 message: "kind=$kind,memberName=$memberName," |
70 "callStructure:$callStructure")); | 71 "callStructure:$callStructure")); |
71 assert(invariant(NO_LOCATION_SPANNABLE, | 72 assert(invariant( |
| 73 NO_LOCATION_SPANNABLE, |
72 kind == SelectorKind.OPERATOR || | 74 kind == SelectorKind.OPERATOR || |
73 kind == SelectorKind.INDEX || | 75 kind == SelectorKind.INDEX || |
74 !Elements.isOperatorName(memberName.text) || | 76 !Elements.isOperatorName(memberName.text) || |
75 memberName.text == '??', | 77 memberName.text == '??', |
76 message: "kind=$kind,memberName=$memberName," | 78 message: "kind=$kind,memberName=$memberName," |
77 "callStructure:$callStructure")); | 79 "callStructure:$callStructure")); |
78 assert(invariant(NO_LOCATION_SPANNABLE, | 80 assert(invariant( |
| 81 NO_LOCATION_SPANNABLE, |
79 kind == SelectorKind.CALL || | 82 kind == SelectorKind.CALL || |
80 kind == SelectorKind.GETTER || | 83 kind == SelectorKind.GETTER || |
81 kind == SelectorKind.SETTER || | 84 kind == SelectorKind.SETTER || |
82 Elements.isOperatorName(memberName.text) || | 85 Elements.isOperatorName(memberName.text) || |
83 memberName.text == '??', | 86 memberName.text == '??', |
84 message: "kind=$kind,memberName=$memberName," | 87 message: "kind=$kind,memberName=$memberName," |
85 "callStructure:$callStructure")); | 88 "callStructure:$callStructure")); |
86 } | 89 } |
87 | 90 |
88 // TODO(johnniwinther): Extract caching. | 91 // TODO(johnniwinther): Extract caching. |
89 static Map<int, List<Selector>> canonicalizedValues = | 92 static Map<int, List<Selector>> canonicalizedValues = |
90 new Map<int, List<Selector>>(); | 93 new Map<int, List<Selector>>(); |
91 | 94 |
92 factory Selector(SelectorKind kind, | 95 factory Selector(SelectorKind kind, Name name, CallStructure callStructure) { |
93 Name name, | |
94 CallStructure callStructure) { | |
95 // TODO(johnniwinther): Maybe use equality instead of implicit hashing. | 96 // TODO(johnniwinther): Maybe use equality instead of implicit hashing. |
96 int hashCode = computeHashCode(kind, name, callStructure); | 97 int hashCode = computeHashCode(kind, name, callStructure); |
97 List<Selector> list = canonicalizedValues.putIfAbsent(hashCode, | 98 List<Selector> list = |
98 () => <Selector>[]); | 99 canonicalizedValues.putIfAbsent(hashCode, () => <Selector>[]); |
99 for (int i = 0; i < list.length; i++) { | 100 for (int i = 0; i < list.length; i++) { |
100 Selector existing = list[i]; | 101 Selector existing = list[i]; |
101 if (existing.match(kind, name, callStructure)) { | 102 if (existing.match(kind, name, callStructure)) { |
102 assert(existing.hashCode == hashCode); | 103 assert(existing.hashCode == hashCode); |
103 return existing; | 104 return existing; |
104 } | 105 } |
105 } | 106 } |
106 Selector result = new Selector.internal( | 107 Selector result = |
107 kind, name, callStructure, hashCode); | 108 new Selector.internal(kind, name, callStructure, hashCode); |
108 list.add(result); | 109 list.add(result); |
109 return result; | 110 return result; |
110 } | 111 } |
111 | 112 |
112 factory Selector.fromElement(Element element) { | 113 factory Selector.fromElement(Element element) { |
113 Name name = new Name(element.name, element.library); | 114 Name name = new Name(element.name, element.library); |
114 if (element.isFunction) { | 115 if (element.isFunction) { |
115 if (name == Names.INDEX_NAME) { | 116 if (name == Names.INDEX_NAME) { |
116 return new Selector.index(); | 117 return new Selector.index(); |
117 } else if (name == Names.INDEX_SET_NAME) { | 118 } else if (name == Names.INDEX_SET_NAME) { |
118 return new Selector.indexSet(); | 119 return new Selector.indexSet(); |
119 } | 120 } |
120 FunctionSignature signature = | 121 FunctionSignature signature = |
121 element.asFunctionElement().functionSignature; | 122 element.asFunctionElement().functionSignature; |
122 int arity = signature.parameterCount; | 123 int arity = signature.parameterCount; |
123 List<String> namedArguments = null; | 124 List<String> namedArguments = null; |
124 if (signature.optionalParametersAreNamed) { | 125 if (signature.optionalParametersAreNamed) { |
125 namedArguments = | 126 namedArguments = |
126 signature.orderedOptionalParameters.map((e) => e.name).toList(); | 127 signature.orderedOptionalParameters.map((e) => e.name).toList(); |
127 } | 128 } |
128 if (element.isOperator) { | 129 if (element.isOperator) { |
129 // Operators cannot have named arguments, however, that doesn't prevent | 130 // Operators cannot have named arguments, however, that doesn't prevent |
130 // a user from declaring such an operator. | 131 // a user from declaring such an operator. |
131 return new Selector( | 132 return new Selector(SelectorKind.OPERATOR, name, |
132 SelectorKind.OPERATOR, | |
133 name, | |
134 new CallStructure(arity, namedArguments)); | 133 new CallStructure(arity, namedArguments)); |
135 } else { | 134 } else { |
136 return new Selector.call( | 135 return new Selector.call( |
137 name, new CallStructure(arity, namedArguments)); | 136 name, new CallStructure(arity, namedArguments)); |
138 } | 137 } |
139 } else if (element.isSetter) { | 138 } else if (element.isSetter) { |
140 return new Selector.setter(name); | 139 return new Selector.setter(name); |
141 } else if (element.isGetter) { | 140 } else if (element.isGetter) { |
142 return new Selector.getter(name); | 141 return new Selector.getter(name); |
143 } else if (element.isField) { | 142 } else if (element.isField) { |
144 return new Selector.getter(name); | 143 return new Selector.getter(name); |
145 } else if (element.isConstructor) { | 144 } else if (element.isConstructor) { |
146 return new Selector.callConstructor(name); | 145 return new Selector.callConstructor(name); |
147 } else { | 146 } else { |
148 throw new SpannableAssertionFailure( | 147 throw new SpannableAssertionFailure( |
149 element, "Can't get selector from $element"); | 148 element, "Can't get selector from $element"); |
150 } | 149 } |
151 } | 150 } |
152 | 151 |
153 factory Selector.getter(Name name) | 152 factory Selector.getter(Name name) => |
154 => new Selector(SelectorKind.GETTER, | 153 new Selector(SelectorKind.GETTER, name.getter, CallStructure.NO_ARGS); |
155 name.getter, | |
156 CallStructure.NO_ARGS); | |
157 | 154 |
158 factory Selector.setter(Name name) | 155 factory Selector.setter(Name name) => |
159 => new Selector(SelectorKind.SETTER, | 156 new Selector(SelectorKind.SETTER, name.setter, CallStructure.ONE_ARG); |
160 name.setter, | |
161 CallStructure.ONE_ARG); | |
162 | 157 |
163 factory Selector.unaryOperator(String name) => new Selector( | 158 factory Selector.unaryOperator(String name) => new Selector( |
164 SelectorKind.OPERATOR, | 159 SelectorKind.OPERATOR, |
165 new PublicName(Elements.constructOperatorName(name, true)), | 160 new PublicName(Elements.constructOperatorName(name, true)), |
166 CallStructure.NO_ARGS); | 161 CallStructure.NO_ARGS); |
167 | 162 |
168 factory Selector.binaryOperator(String name) => new Selector( | 163 factory Selector.binaryOperator(String name) => new Selector( |
169 SelectorKind.OPERATOR, | 164 SelectorKind.OPERATOR, |
170 new PublicName(Elements.constructOperatorName(name, false)), | 165 new PublicName(Elements.constructOperatorName(name, false)), |
171 CallStructure.ONE_ARG); | 166 CallStructure.ONE_ARG); |
172 | 167 |
173 factory Selector.index() | 168 factory Selector.index() => |
174 => new Selector(SelectorKind.INDEX, Names.INDEX_NAME, | 169 new Selector(SelectorKind.INDEX, Names.INDEX_NAME, CallStructure.ONE_ARG); |
175 CallStructure.ONE_ARG); | |
176 | 170 |
177 factory Selector.indexSet() | 171 factory Selector.indexSet() => new Selector( |
178 => new Selector(SelectorKind.INDEX, Names.INDEX_SET_NAME, | 172 SelectorKind.INDEX, Names.INDEX_SET_NAME, CallStructure.TWO_ARGS); |
179 CallStructure.TWO_ARGS); | |
180 | 173 |
181 factory Selector.call(Name name, CallStructure callStructure) | 174 factory Selector.call(Name name, CallStructure callStructure) => |
182 => new Selector(SelectorKind.CALL, name, callStructure); | 175 new Selector(SelectorKind.CALL, name, callStructure); |
183 | 176 |
184 factory Selector.callClosure(int arity, [List<String> namedArguments]) | 177 factory Selector.callClosure(int arity, [List<String> namedArguments]) => |
185 => new Selector(SelectorKind.CALL, Names.call, | 178 new Selector(SelectorKind.CALL, Names.call, |
186 new CallStructure(arity, namedArguments)); | 179 new CallStructure(arity, namedArguments)); |
187 | 180 |
188 factory Selector.callClosureFrom(Selector selector) | 181 factory Selector.callClosureFrom(Selector selector) => |
189 => new Selector(SelectorKind.CALL, Names.call, selector.callStructure); | 182 new Selector(SelectorKind.CALL, Names.call, selector.callStructure); |
190 | 183 |
191 factory Selector.callConstructor(Name name, | 184 factory Selector.callConstructor(Name name, |
192 [int arity = 0, | 185 [int arity = 0, List<String> namedArguments]) => |
193 List<String> namedArguments]) | 186 new Selector( |
194 => new Selector(SelectorKind.CALL, name, | 187 SelectorKind.CALL, name, new CallStructure(arity, namedArguments)); |
195 new CallStructure(arity, namedArguments)); | |
196 | 188 |
197 factory Selector.callDefaultConstructor() | 189 factory Selector.callDefaultConstructor() => new Selector( |
198 => new Selector( | 190 SelectorKind.CALL, const PublicName(''), CallStructure.NO_ARGS); |
199 SelectorKind.CALL, | |
200 const PublicName(''), | |
201 CallStructure.NO_ARGS); | |
202 | 191 |
203 bool get isGetter => kind == SelectorKind.GETTER; | 192 bool get isGetter => kind == SelectorKind.GETTER; |
204 bool get isSetter => kind == SelectorKind.SETTER; | 193 bool get isSetter => kind == SelectorKind.SETTER; |
205 bool get isCall => kind == SelectorKind.CALL; | 194 bool get isCall => kind == SelectorKind.CALL; |
206 bool get isClosureCall => isCall && memberName == Names.CALL_NAME; | 195 bool get isClosureCall => isCall && memberName == Names.CALL_NAME; |
207 | 196 |
208 bool get isIndex => kind == SelectorKind.INDEX && argumentCount == 1; | 197 bool get isIndex => kind == SelectorKind.INDEX && argumentCount == 1; |
209 bool get isIndexSet => kind == SelectorKind.INDEX && argumentCount == 2; | 198 bool get isIndexSet => kind == SelectorKind.INDEX && argumentCount == 2; |
210 | 199 |
211 bool get isOperator => kind == SelectorKind.OPERATOR; | 200 bool get isOperator => kind == SelectorKind.OPERATOR; |
212 bool get isUnaryOperator => isOperator && argumentCount == 0; | 201 bool get isUnaryOperator => isOperator && argumentCount == 0; |
213 | 202 |
214 /** | 203 /** |
215 * The member name for invocation mirrors created from this selector. | 204 * The member name for invocation mirrors created from this selector. |
216 */ | 205 */ |
217 String get invocationMirrorMemberName => | 206 String get invocationMirrorMemberName => isSetter ? '$name=' : name; |
218 isSetter ? '$name=' : name; | |
219 | 207 |
220 int get invocationMirrorKind { | 208 int get invocationMirrorKind { |
221 const int METHOD = 0; | 209 const int METHOD = 0; |
222 const int GETTER = 1; | 210 const int GETTER = 1; |
223 const int SETTER = 2; | 211 const int SETTER = 2; |
224 int kind = METHOD; | 212 int kind = METHOD; |
225 if (isGetter) { | 213 if (isGetter) { |
226 kind = GETTER; | 214 kind = GETTER; |
227 } else if (isSetter) { | 215 } else if (isSetter) { |
228 kind = SETTER; | 216 kind = SETTER; |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 bool sameNameHack(Element element, World world) { | 252 bool sameNameHack(Element element, World world) { |
265 // TODO(ngeoffray): Remove workaround checks. | 253 // TODO(ngeoffray): Remove workaround checks. |
266 return element.isConstructor || name == element.name; | 254 return element.isConstructor || name == element.name; |
267 } | 255 } |
268 | 256 |
269 bool applies(Element element, World world) { | 257 bool applies(Element element, World world) { |
270 if (!sameNameHack(element, world)) return false; | 258 if (!sameNameHack(element, world)) return false; |
271 return appliesUnnamed(element, world); | 259 return appliesUnnamed(element, world); |
272 } | 260 } |
273 | 261 |
274 bool match(SelectorKind kind, | 262 bool match(SelectorKind kind, Name memberName, CallStructure callStructure) { |
275 Name memberName, | 263 return this.kind == kind && |
276 CallStructure callStructure) { | 264 this.memberName == memberName && |
277 return this.kind == kind | 265 this.callStructure.match(callStructure); |
278 && this.memberName == memberName | |
279 && this.callStructure.match(callStructure); | |
280 } | 266 } |
281 | 267 |
282 static int computeHashCode(SelectorKind kind, | 268 static int computeHashCode( |
283 Name name, | 269 SelectorKind kind, Name name, CallStructure callStructure) { |
284 CallStructure callStructure) { | |
285 // Add bits from name and kind. | 270 // Add bits from name and kind. |
286 int hash = Hashing.mixHashCodeBits(name.hashCode, kind.hashCode); | 271 int hash = Hashing.mixHashCodeBits(name.hashCode, kind.hashCode); |
287 // Add bits from the call structure. | 272 // Add bits from the call structure. |
288 return Hashing.mixHashCodeBits(hash, callStructure.hashCode); | 273 return Hashing.mixHashCodeBits(hash, callStructure.hashCode); |
289 } | 274 } |
290 | 275 |
291 String toString() { | 276 String toString() { |
292 return 'Selector($kind, $name, ${callStructure.structureToString()})'; | 277 return 'Selector($kind, $name, ${callStructure.structureToString()})'; |
293 } | 278 } |
294 | 279 |
295 Selector toCallSelector() => new Selector.callClosureFrom(this); | 280 Selector toCallSelector() => new Selector.callClosureFrom(this); |
296 } | 281 } |
OLD | NEW |