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 library initialize.build.initializer_plugin; | 4 library initialize.build.initializer_plugin; |
5 | 5 |
6 import 'package:analyzer/src/generated/ast.dart'; | 6 import 'package:analyzer/src/generated/ast.dart'; |
7 import 'package:analyzer/src/generated/element.dart'; | 7 import 'package:analyzer/src/generated/element.dart'; |
8 import 'package:barback/barback.dart'; | 8 import 'package:barback/barback.dart'; |
9 import 'package:code_transformers/resolver.dart'; | 9 import 'package:code_transformers/resolver.dart'; |
10 import 'package:initialize/transformer.dart'; | 10 import 'package:initialize/transformer.dart'; |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 var annotation = pluginData.initializer.annotationNode; | 85 var annotation = pluginData.initializer.annotationNode; |
86 if (annotation == null) { | 86 if (annotation == null) { |
87 logger.error( | 87 logger.error( |
88 'Initializer annotations are only supported on libraries, classes, ' | 88 'Initializer annotations are only supported on libraries, classes, ' |
89 'and top level methods. Found $node.'); | 89 'and top level methods. Found $node.'); |
90 } | 90 } |
91 var clazz = annotation.name; | 91 var clazz = annotation.name; |
92 var constructor = annotation.constructorName == null | 92 var constructor = annotation.constructorName == null |
93 ? '' | 93 ? '' |
94 : '.${annotation.constructorName}'; | 94 : '.${annotation.constructorName}'; |
95 // TODO(jakemac): Support more than raw values here | |
96 // https://github.com/dart-lang/static_init/issues/5 | |
97 var args = buildArgumentList(annotation.arguments, pluginData); | 95 var args = buildArgumentList(annotation.arguments, pluginData); |
98 return 'const $metaPrefix.${clazz}$constructor$args'; | 96 return 'const $metaPrefix.${clazz}$constructor$args'; |
99 } | 97 } |
100 | 98 |
101 /// Builds a [String] representing the meta of an [InitEntry] given an | 99 /// Builds a [String] representing the meta of an [InitEntry] given an |
102 /// [ElementAnnotation] whose element was a [PropertyAccessorElement]. | 100 /// [ElementAnnotation] whose element was a [PropertyAccessorElement]. |
103 String buildPropertyMeta( | 101 String buildPropertyMeta( |
104 ElementAnnotation annotation, InitializerPluginData pluginData) { | 102 ElementAnnotation annotation, InitializerPluginData pluginData) { |
105 var metaPrefix = pluginData.libraryPrefixes[annotation.element.library]; | 103 var metaPrefix = pluginData.libraryPrefixes[annotation.element.library]; |
106 return '$metaPrefix.${annotation.element.name}'; | 104 return '$metaPrefix.${annotation.element.name}'; |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
195 return buffer.toString(); | 193 return buffer.toString(); |
196 } | 194 } |
197 | 195 |
198 /// Builds a [String] representing [expression] taking into account the | 196 /// Builds a [String] representing [expression] taking into account the |
199 /// [libraryPrefixes] from [pluginData]. | 197 /// [libraryPrefixes] from [pluginData]. |
200 String buildExpression( | 198 String buildExpression( |
201 Expression expression, InitializerPluginData pluginData) { | 199 Expression expression, InitializerPluginData pluginData) { |
202 var logger = pluginData.logger; | 200 var logger = pluginData.logger; |
203 var libraryPrefixes = pluginData.libraryPrefixes; | 201 var libraryPrefixes = pluginData.libraryPrefixes; |
204 var buffer = new StringBuffer(); | 202 var buffer = new StringBuffer(); |
205 if (expression is StringLiteral) { | 203 if (expression is StringLiteral && expression.stringValue != null) { |
206 var value = expression.stringValue; | 204 buffer.write(_stringValue(expression.stringValue)); |
207 if (value == null) { | |
208 logger.error('Only const strings are allowed in initializer ' | |
209 'expressions, found $expression'); | |
210 } | |
211 value = value.replaceAll(r'\', r'\\').replaceAll(r"'", r"\'"); | |
212 buffer.write("'$value'"); | |
213 } else if (expression is BooleanLiteral || | 205 } else if (expression is BooleanLiteral || |
214 expression is DoubleLiteral || | 206 expression is DoubleLiteral || |
215 expression is IntegerLiteral || | 207 expression is IntegerLiteral || |
216 expression is NullLiteral) { | 208 expression is NullLiteral) { |
217 buffer.write('${expression}'); | 209 buffer.write('${expression}'); |
218 } else if (expression is ListLiteral) { | 210 } else if (expression is ListLiteral) { |
219 buffer.write('const ['); | 211 buffer.write('const ['); |
220 var first = true; | 212 var first = true; |
221 for (Expression listExpression in expression.elements) { | 213 for (Expression listExpression in expression.elements) { |
222 if (!first) buffer.write(', '); | 214 if (!first) buffer.write(', '); |
223 first = false; | 215 first = false; |
224 buffer.write(buildExpression(listExpression, pluginData)); | 216 buffer.write(buildExpression(listExpression, pluginData)); |
225 } | 217 } |
226 buffer.write(']'); | 218 buffer.write(']'); |
227 } else if (expression is MapLiteral) { | 219 } else if (expression is MapLiteral) { |
228 buffer.write('const {'); | 220 buffer.write('const {'); |
229 var first = true; | 221 var first = true; |
230 for (MapLiteralEntry entry in expression.entries) { | 222 for (MapLiteralEntry entry in expression.entries) { |
231 if (!first) buffer.write(', '); | 223 if (!first) buffer.write(', '); |
232 first = false; | 224 first = false; |
233 buffer.write(buildExpression(entry.key, pluginData)); | 225 buffer.write(buildExpression(entry.key, pluginData)); |
234 buffer.write(': '); | 226 buffer.write(': '); |
235 buffer.write(buildExpression(entry.value, pluginData)); | 227 buffer.write(buildExpression(entry.value, pluginData)); |
236 } | 228 } |
237 buffer.write('}'); | 229 buffer.write('}'); |
238 } else if (expression is Identifier) { | 230 } else if (expression is Identifier) { |
239 var element = expression.bestElement; | 231 var element = expression.bestElement; |
240 if (element == null || !element.isPublic) { | 232 if (element == null || !element.isPublic) { |
241 logger.error('Private constants are not supported in intializer ' | 233 logger.error('Private constants are not supported in intializer ' |
242 'constructors, found $element.'); | 234 'constructors, found $element.'); |
243 } | 235 } |
244 libraryPrefixes.putIfAbsent( | 236 libraryPrefixes.putIfAbsent( |
245 element.library, () => 'i${libraryPrefixes.length}'); | 237 element.library, () => 'i${libraryPrefixes.length}'); |
246 | 238 |
247 buffer.write('${libraryPrefixes[element.library]}.'); | 239 buffer.write('${libraryPrefixes[element.library]}.'); |
248 if (element is ClassElement) { | 240 if (element is ClassElement) { |
249 buffer.write(element.name); | 241 buffer.write(element.name); |
250 } else if (element is PropertyAccessorElement) { | 242 } else if (element is PropertyAccessorElement) { |
251 var variable = element.variable; | 243 var variable = element.variable; |
252 if (variable is FieldElement) { | 244 if (variable is FieldElement) { |
253 buffer.write('${variable.enclosingElement.name}.'); | 245 buffer.write('${variable.enclosingElement.name}.'); |
254 } | 246 } |
255 buffer.write('${variable.name}'); | 247 buffer.write('${variable.name}'); |
256 } else { | 248 } else { |
257 logger.error('Unsupported argument to initializer constructor.'); | 249 logger.error('Unsupported argument to initializer constructor.'); |
258 } | 250 } |
| 251 } else if (expression is PropertyAccess) { |
| 252 buffer.write(buildExpression(expression.target, pluginData)); |
| 253 buffer.write('.${expression.propertyName}'); |
| 254 } else if (expression is InstanceCreationExpression) { |
| 255 logger.error('Unsupported expression in initializer, found $expression. ' |
| 256 'Instance creation expressions are not supported (yet). Instead, ' |
| 257 'please assign it to a const variable and use that instead.'); |
259 } else { | 258 } else { |
260 logger.error('Only literals and identifiers are allowed for initializer ' | 259 // Try to evaluate the constant and use that. |
261 'expressions, found $expression.'); | 260 var result = pluginData.resolver.evaluateConstant( |
| 261 pluginData.initializer.targetElement.library, expression); |
| 262 if (!result.isValid) { |
| 263 logger.error('Invalid expression in initializer, found $expression. ' |
| 264 'And got the following errors: ${result.errors}.'); |
| 265 } |
| 266 var value = result.value.value; |
| 267 if (value == null) { |
| 268 logger.error('Unsupported expression in initializer, found ' |
| 269 '$expression. Please file a bug at ' |
| 270 'https://github.com/dart-lang/initialize/issues'); |
| 271 } |
| 272 |
| 273 if (value is String) value = _stringValue(value); |
| 274 buffer.write(value); |
262 } | 275 } |
263 return buffer.toString(); | 276 return buffer.toString(); |
264 } | 277 } |
| 278 |
| 279 // Returns an expression for a string value. Wraps it in single quotes and |
| 280 // escapes existing single quotes and escapes. |
| 281 _stringValue(String value) { |
| 282 value = value.replaceAll(r'\', r'\\').replaceAll(r"'", r"\'"); |
| 283 return "'$value'"; |
| 284 } |
265 } | 285 } |
OLD | NEW |