Chromium Code Reviews| 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 |