| 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 |