OLD | NEW |
---|---|
1 // (c) 2015, the Dart Team. All rights reserved. Use of this | 1 // (c) 2015, the Dart Team. All rights reserved. Use of this |
2 // source code is governed by a BSD-style license that can be found in | 2 // source code is governed by a BSD-style license that can be found in |
3 // the LICENSE file. | 3 // the LICENSE file. |
4 | 4 |
5 library reflectable.src.transformer_implementation; | 5 library reflectable.src.transformer_implementation; |
6 | 6 |
7 import 'dart:async'; | 7 import 'dart:async'; |
8 import 'dart:convert'; | 8 import 'dart:convert'; |
9 import 'dart:io'; | 9 import 'dart:io'; |
10 import 'dart:math' show max; | 10 import 'dart:math' show max; |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
75 /// Information about reflectability for a given class. | 75 /// Information about reflectability for a given class. |
76 class ClassDomain { | 76 class ClassDomain { |
77 final ClassElement classElement; | 77 final ClassElement classElement; |
78 final Iterable<MethodElement> declaredMethods; | 78 final Iterable<MethodElement> declaredMethods; |
79 final Iterable<PropertyAccessorElement> declaredAccessors; | 79 final Iterable<PropertyAccessorElement> declaredAccessors; |
80 final Iterable<ConstructorElement> constructors; | 80 final Iterable<ConstructorElement> constructors; |
81 | 81 |
82 ReflectorDomain reflectorDomain; | 82 ReflectorDomain reflectorDomain; |
83 | 83 |
84 Iterable<MethodElement> get invokableMethods => instanceMembers | 84 Iterable<MethodElement> get invokableMethods => instanceMembers |
85 .where((ExecutableElement element) => element is MethodElement); | 85 .where((ExecutableElement element) => element is MethodElement); |
86 | 86 |
87 String staticClassMirrorName; | 87 String staticClassMirrorName; |
88 String staticInstanceMirrorName; | 88 String staticInstanceMirrorName; |
89 String get baseName => classElement.name; | 89 String get baseName => classElement.name; |
90 | 90 |
91 ClassDomain(this.classElement, this.declaredMethods, | 91 ClassDomain(this.classElement, this.declaredMethods, this.declaredAccessors, |
92 this.declaredAccessors, this.constructors, this.reflectorDomain); | 92 this.constructors, this.reflectorDomain); |
93 | 93 |
94 Iterable<ExecutableElement> get declarations { | 94 Iterable<ExecutableElement> get declarations { |
95 // TODO(sigurdm): Include fields. | 95 // TODO(sigurdm): Include fields. |
96 // TODO(sigurdm): Include type variables (if we decide to keep them). | 96 // TODO(sigurdm): Include type variables (if we decide to keep them). |
97 return [declaredMethods, declaredAccessors, constructors].expand((x) => x); | 97 return [declaredMethods, declaredAccessors, constructors].expand((x) => x); |
98 } | 98 } |
99 | 99 |
100 /// Finds all instance members by going through the class hierarchy. | 100 /// Finds all instance members by going through the class hierarchy. |
101 Iterable<ExecutableElement> get instanceMembers { | 101 Iterable<ExecutableElement> get instanceMembers { |
102 | |
103 Map<String, ExecutableElement> helper(ClassElement classElement) { | 102 Map<String, ExecutableElement> helper(ClassElement classElement) { |
104 if (reflectorDomain._instanceMemberCache[classElement] != null) { | 103 if (reflectorDomain._instanceMemberCache[classElement] != null) { |
105 return reflectorDomain._instanceMemberCache[classElement]; | 104 return reflectorDomain._instanceMemberCache[classElement]; |
106 } | 105 } |
107 Map<String, ExecutableElement> result = | 106 Map<String, ExecutableElement> result = |
108 new Map<String, ExecutableElement>(); | 107 new Map<String, ExecutableElement>(); |
109 | 108 |
110 void addIfCapable(ExecutableElement member) { | 109 void addIfCapable(ExecutableElement member) { |
111 if (reflectorDomain.capabilities.supportsInstanceInvoke(member.name)) { | 110 if (reflectorDomain.capabilities.supportsInstanceInvoke(member.name)) { |
112 result[member.name] = member; | 111 result[member.name] = member; |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
196 '${_declarationDescriptor(declaration)}, this)'; | 195 '${_declarationDescriptor(declaration)}, this)'; |
197 }); | 196 }); |
198 return "{${declarationParts.join(", ")}}"; | 197 return "{${declarationParts.join(", ")}}"; |
199 } | 198 } |
200 | 199 |
201 /// Returns a String with the textual representation of the | 200 /// Returns a String with the textual representation of the |
202 /// instanceMembers-map. | 201 /// instanceMembers-map. |
203 String get instanceMembersString { | 202 String get instanceMembersString { |
204 // TODO(sigurdm): Find out how to set the right owner. | 203 // TODO(sigurdm): Find out how to set the right owner. |
205 Iterable<String> instanceMemberParts = instanceMembers.map( | 204 Iterable<String> instanceMemberParts = instanceMembers.map( |
206 (ExecutableElement declaration) { | 205 (ExecutableElement declaration) { |
207 return '"${nameOfDeclaration(declaration)}": ' | 206 return '"${nameOfDeclaration(declaration)}": ' |
208 'new MethodMirrorImpl("${declaration.name}", ' | 207 'new MethodMirrorImpl("${declaration.name}", ' |
209 '${_declarationDescriptor(declaration)}, null)'; | 208 '${_declarationDescriptor(declaration)}, null)'; |
210 }); | 209 }); |
211 return "{${instanceMemberParts.join(", ")}}"; | 210 return "{${instanceMemberParts.join(", ")}}"; |
212 } | 211 } |
213 | 212 |
213 String get newInstanceString { | |
eernst
2015/06/18 13:35:41
I've been looking for a general hint (some DartDoc
sigurdm
2015/06/19 07:50:54
Your intuition is right. There is no exact defined
| |
214 // TODO(eernst, sigurdm, #8): Recreate the default values faithfully. | |
215 List<String> constructorLines = new List<String>(); | |
216 | |
217 String name(int i) { | |
218 String alphabet = "abcdefghijklmnopqrstuvwxyz"; | |
219 int alphabetLength = alphabet.length; | |
220 if (i < alphabetLength) { | |
221 return "_${alphabet[i]}"; | |
222 } | |
223 return "_${alphabet[i % alphabetLength]}${i ~/ alphabetLength}"; | |
224 } | |
225 for (ConstructorElement constructor in constructors) { | |
226 FunctionType type = constructor.type; | |
227 int positionalCount = type.normalParameterTypes.length; | |
228 int optionalCount = type.optionalParameterTypes.length; | |
229 List<String> argumentNames = type.namedParameterTypes.keys.toList(); | |
230 String positionals = new Iterable.generate( | |
231 positionalCount, (int i) => name(i)).join(", "); | |
232 String optionalsWithDefaults = new Iterable.generate(optionalCount, | |
233 (int i) { | |
234 String defaultValueCode = | |
235 constructor.parameters[positionalCount + i].defaultValueCode; | |
236 String defaultValueString = | |
237 defaultValueCode == null ? "" : " = $defaultValueCode"; | |
238 return "${name(i + positionalCount)}$defaultValueString"; | |
239 }).join(", "); | |
eernst
2015/06/18 13:35:41
Maybe
we can sell this style of
indentation to
sigurdm
2015/06/19 07:50:54
?
| |
240 String namedWithDefaults = new Iterable.generate(argumentNames.length, | |
241 (int i) { | |
242 String defaultValueCode = | |
243 constructor.parameters[positionalCount + i].defaultValueCode; | |
244 String defaultValueString = | |
245 defaultValueCode == null ? "" : ": $defaultValueCode"; | |
246 return "${argumentNames[i]}$defaultValueString"; | |
247 }).join(", "); | |
248 | |
249 String optionalArguments = new Iterable.generate( | |
250 optionalCount, (int i) => name(i + positionalCount)).join(", "); | |
251 String namedArguments = | |
252 argumentNames.map((String name) => "$name: $name").join(", "); | |
253 List<String> parameterParts = new List<String>(); | |
254 List<String> argumentParts = new List<String>(); | |
255 if (positionalCount != 0) { | |
256 parameterParts.add(positionals); | |
257 argumentParts.add(positionals); | |
258 } | |
259 if (optionalCount != 0) { | |
260 parameterParts.add("[$optionalsWithDefaults]"); | |
261 argumentParts.add(optionalArguments); | |
262 } | |
263 if (argumentNames.isNotEmpty) { | |
264 parameterParts.add("{${namedWithDefaults}}"); | |
265 argumentParts.add(namedArguments); | |
266 } | |
267 constructorLines.add('case "${constructor.name}": ' | |
268 'c = (${parameterParts.join(', ')}) => ' | |
269 'new ${nameOfDeclaration(constructor)}' | |
270 '(${argumentParts.join(", ")});'); | |
271 constructorLines.add(' break;'); | |
272 } | |
273 return """newInstance(String constructorName, List positionalArguments, | |
274 [Map<Symbol, dynamic> namedArguments]) { | |
275 Function c; | |
276 switch (constructorName) { | |
277 ${constructorLines.join("\n ")} | |
278 default: throw new NoSuchInvokeCapabilityError(${classElement.name}, | |
279 constructorName, positionalArguments, namedArguments); | |
280 } | |
281 return Function.apply(c, positionalArguments, namedArguments); | |
282 }"""; | |
283 } | |
284 | |
214 void computeNames(Namer namer) { | 285 void computeNames(Namer namer) { |
215 staticClassMirrorName = namer.freshName("Static_${baseName}_ClassMirror"); | 286 staticClassMirrorName = namer.freshName("Static_${baseName}_ClassMirror"); |
216 staticInstanceMirrorName = | 287 staticInstanceMirrorName = |
217 namer.freshName("Static_${baseName}_InstanceMirror"); | 288 namer.freshName("Static_${baseName}_InstanceMirror"); |
218 } | 289 } |
219 } | 290 } |
220 | 291 |
221 /// A wrapper around a list of Capabilities. | 292 /// A wrapper around a list of Capabilities. |
222 /// Supports queries about the methods supported by the set of capabilities. | 293 /// Supports queries about the methods supported by the set of capabilities. |
223 class Capabilities { | 294 class Capabilities { |
(...skipping 624 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
848 insert(""" | 919 insert(""" |
849 Iterable<${prefix}ClassMirror> get annotatedClasses { | 920 Iterable<${prefix}ClassMirror> get annotatedClasses { |
850 return [${annotatedClassesStrings.join(", ")}]; | 921 return [${annotatedClassesStrings.join(", ")}]; |
851 }"""); | 922 }"""); |
852 } | 923 } |
853 | 924 |
854 /// Returns the source code for the reflection free subclass of | 925 /// Returns the source code for the reflection free subclass of |
855 /// [ClassMirror] which is specialized for a `reflectedType` which | 926 /// [ClassMirror] which is specialized for a `reflectedType` which |
856 /// is the class modeled by [classElement]. | 927 /// is the class modeled by [classElement]. |
857 String _staticClassMirrorCode(ClassDomain classDomain) { | 928 String _staticClassMirrorCode(ClassDomain classDomain) { |
929 | |
858 String declarationsString = classDomain.declarationsString; | 930 String declarationsString = classDomain.declarationsString; |
859 String instanceMembersString = classDomain.instanceMembersString; | 931 String instanceMembersString = classDomain.instanceMembersString; |
932 List<String> memberStrings = new List<String>(); | |
933 if (!classDomain.classElement.isAbstract) { | |
934 memberStrings.add(classDomain.newInstanceString); | |
935 } | |
eernst
2015/06/18 13:35:41
This one would be new, but still related to the tr
sigurdm
2015/06/19 07:50:54
You cannot invoke abstract cosntructors directly,
| |
860 return """ | 936 return """ |
861 class ${classDomain.staticClassMirrorName} extends ClassMirrorUnimpl { | 937 class ${classDomain.staticClassMirrorName} extends ClassMirrorUnimpl { |
862 final String simpleName = "${classDomain.classElement.name}"; | 938 final String simpleName = "${classDomain.classElement.name}"; |
863 | 939 |
864 Map<String, MethodMirror> _declarationsCache; | 940 Map<String, MethodMirror> _declarationsCache; |
865 | 941 |
866 Map<String, MethodMirror> get declarations { | 942 Map<String, MethodMirror> get declarations { |
867 if (_declarationsCache == null) { | 943 if (_declarationsCache == null) { |
868 _declarationsCache = new UnmodifiableMapView($declarationsString); | 944 _declarationsCache = new UnmodifiableMapView($declarationsString); |
869 } | 945 } |
870 return _declarationsCache; | 946 return _declarationsCache; |
871 } | 947 } |
872 | 948 |
873 Map<String, MethodMirror> _instanceMembersCache; | 949 Map<String, MethodMirror> _instanceMembersCache; |
874 | 950 |
875 Map<String, MethodMirror> get instanceMembers { | 951 Map<String, MethodMirror> get instanceMembers { |
876 if (_instanceMembersCache == null) { | 952 if (_instanceMembersCache == null) { |
877 _instanceMembersCache = new UnmodifiableMapView($instanceMembersString); | 953 _instanceMembersCache = new UnmodifiableMapView($instanceMembersString); |
878 } | 954 } |
879 return _instanceMembersCache; | 955 return _instanceMembersCache; |
880 } | 956 } |
881 | 957 |
958 ${memberStrings.join("\n\n ")} | |
882 } | 959 } |
883 """; | 960 """; |
884 } | 961 } |
885 | 962 |
886 /// Perform some very simple steps that are consistent with Dart | 963 /// Perform some very simple steps that are consistent with Dart |
887 /// semantics for the evaluation of constant expressions, such that | 964 /// semantics for the evaluation of constant expressions, such that |
888 /// information about the value of a given `const` variable can be | 965 /// information about the value of a given `const` variable can be |
889 /// obtained. It is intended to help recognizing values of type | 966 /// obtained. It is intended to help recognizing values of type |
890 /// [ReflectCapability], so we only cover cases needed for that. | 967 /// [ReflectCapability], so we only cover cases needed for that. |
891 /// In particular, we cover lookup (e.g., with `const x = e` we can | 968 /// In particular, we cover lookup (e.g., with `const x = e` we can |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
969 case "InvokeMembersWithMetadataCapability": | 1046 case "InvokeMembersWithMetadataCapability": |
970 throw new UnimplementedError("$classElement not yet supported"); | 1047 throw new UnimplementedError("$classElement not yet supported"); |
971 case "InvokeInstanceMembersUpToSuperCapability": | 1048 case "InvokeInstanceMembersUpToSuperCapability": |
972 throw new UnimplementedError("$classElement not yet supported"); | 1049 throw new UnimplementedError("$classElement not yet supported"); |
973 case "_InvokeStaticMembersCapability": | 1050 case "_InvokeStaticMembersCapability": |
974 return invokeStaticMembersCapability; | 1051 return invokeStaticMembersCapability; |
975 case "InvokeInstanceMemberCapability": | 1052 case "InvokeInstanceMemberCapability": |
976 throw new UnimplementedError("$classElement not yet supported"); | 1053 throw new UnimplementedError("$classElement not yet supported"); |
977 case "InvokeStaticMemberCapability": | 1054 case "InvokeStaticMemberCapability": |
978 throw new UnimplementedError("$classElement not yet supported"); | 1055 throw new UnimplementedError("$classElement not yet supported"); |
1056 case "_InvokeConstructorsCapability": | |
1057 return invokeConstructorsCapability; | |
eernst
2015/06/18 13:35:41
I believe this is the same thing as the capability
sigurdm
2015/06/19 07:50:54
This was based on the previous incantation of capa
| |
979 default: | 1058 default: |
980 throw new UnimplementedError("Unexpected capability $classElement"); | 1059 throw new UnimplementedError("Unexpected capability $classElement"); |
981 } | 1060 } |
982 } | 1061 } |
983 | 1062 |
984 /// Returns the list of Capabilities given given as a superinitializer by the | 1063 /// Returns the list of Capabilities given given as a superinitializer by the |
985 /// reflector. | 1064 /// reflector. |
986 Capabilities _capabilitiesOf( | 1065 Capabilities _capabilitiesOf( |
987 LibraryElement capabilityLibrary, ClassElement reflector) { | 1066 LibraryElement capabilityLibrary, ClassElement reflector) { |
988 List<ConstructorElement> constructors = reflector.constructors; | 1067 List<ConstructorElement> constructors = reflector.constructors; |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1034 ListLiteral listLiteral = arguments[0]; | 1113 ListLiteral listLiteral = arguments[0]; |
1035 NodeList<Expression> expressions = listLiteral.elements; | 1114 NodeList<Expression> expressions = listLiteral.elements; |
1036 return new Capabilities(expressions.map(capabilityOfExpression).toList()); | 1115 return new Capabilities(expressions.map(capabilityOfExpression).toList()); |
1037 } | 1116 } |
1038 | 1117 |
1039 /// Returns a [String] containing generated code for the `invoke` | 1118 /// Returns a [String] containing generated code for the `invoke` |
1040 /// method of the static `InstanceMirror` class corresponding to | 1119 /// method of the static `InstanceMirror` class corresponding to |
1041 /// the given [classElement], bounded by the permissions given | 1120 /// the given [classElement], bounded by the permissions given |
1042 /// in [capabilities]. | 1121 /// in [capabilities]. |
1043 String _staticInstanceMirrorInvokeCode(ClassDomain classDomain) { | 1122 String _staticInstanceMirrorInvokeCode(ClassDomain classDomain) { |
1044 | |
1045 String tearOff(MethodElement methodElement) { | 1123 String tearOff(MethodElement methodElement) { |
1046 if (!methodElement.isOperator) return "reflectee.${methodElement.name}"; | 1124 if (!methodElement.isOperator) return "reflectee.${methodElement.name}"; |
1047 if (methodElement.name == "[]=") return "(x, v) => reflectee[x] = v"; | 1125 if (methodElement.name == "[]=") return "(x, v) => reflectee[x] = v"; |
1048 if (methodElement.name == "[]") return "(x) => reflectee[x]"; | 1126 if (methodElement.name == "[]") return "(x) => reflectee[x]"; |
1049 return "(x) => reflectee ${methodElement.name} x"; | 1127 return "(x) => reflectee ${methodElement.name} x"; |
1050 } | 1128 } |
1051 | 1129 |
1052 | |
1053 List<String> methodCases = new List<String>(); | 1130 List<String> methodCases = new List<String>(); |
1054 for (MethodElement methodElement in classDomain.invokableMethods) { | 1131 for (MethodElement methodElement in classDomain.invokableMethods) { |
1055 methodCases.add("if (memberName == '${methodElement.name}') {" | 1132 methodCases.add("if (memberName == '${methodElement.name}') {" |
1056 "method = ${tearOff(methodElement)}; }"); | 1133 "method = ${tearOff(methodElement)}; }"); |
1057 } | 1134 } |
1058 // TODO(eernst, sigurdm): Create an instance of [Invocation] in user code. | 1135 // TODO(eernst, sigurdm): Create an instance of [Invocation] in user code. |
1059 methodCases.add("if (instanceMethodFilter.hasMatch(memberName)) {" | 1136 methodCases.add("if (instanceMethodFilter.hasMatch(memberName)) {" |
1060 "throw new UnimplementedError('Should call noSuchMethod'); }"); | 1137 "throw new UnimplementedError('Should call noSuchMethod'); }"); |
1061 methodCases.add("{ throw new NoSuchInvokeCapabilityError(" | 1138 methodCases.add("{ throw new NoSuchInvokeCapabilityError(" |
1062 "reflectee, memberName, positionalArguments, namedArguments); }"); | 1139 "reflectee, memberName, positionalArguments, namedArguments); }"); |
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1322 TransformLogger get logger => _aggregateTransform.logger; | 1399 TransformLogger get logger => _aggregateTransform.logger; |
1323 Future<Asset> getInput(AssetId id) => _aggregateTransform.getInput(id); | 1400 Future<Asset> getInput(AssetId id) => _aggregateTransform.getInput(id); |
1324 Future<String> readInputAsString(AssetId id, {Encoding encoding}) { | 1401 Future<String> readInputAsString(AssetId id, {Encoding encoding}) { |
1325 return _aggregateTransform.readInputAsString(id, encoding: encoding); | 1402 return _aggregateTransform.readInputAsString(id, encoding: encoding); |
1326 } | 1403 } |
1327 Stream<List<int>> readInput(AssetId id) => _aggregateTransform.readInput(id); | 1404 Stream<List<int>> readInput(AssetId id) => _aggregateTransform.readInput(id); |
1328 Future<bool> hasInput(AssetId id) => _aggregateTransform.hasInput(id); | 1405 Future<bool> hasInput(AssetId id) => _aggregateTransform.hasInput(id); |
1329 void addOutput(Asset output) => _aggregateTransform.addOutput(output); | 1406 void addOutput(Asset output) => _aggregateTransform.addOutput(output); |
1330 void consumePrimary() => _aggregateTransform.consumePrimary(primaryInput.id); | 1407 void consumePrimary() => _aggregateTransform.consumePrimary(primaryInput.id); |
1331 } | 1408 } |
OLD | NEW |