Chromium Code Reviews| 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.transformer; | 4 library initialize.transformer; |
| 5 | 5 |
| 6 import 'dart:async'; | 6 import 'dart:async'; |
| 7 import 'dart:collection' show Queue; | 7 import 'dart:collection' show Queue; |
| 8 import 'package:analyzer/src/generated/ast.dart'; | 8 import 'package:analyzer/src/generated/ast.dart'; |
| 9 import 'package:analyzer/src/generated/element.dart'; | 9 import 'package:analyzer/src/generated/element.dart'; |
| 10 import 'package:barback/barback.dart'; | 10 import 'package:barback/barback.dart'; |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 71 bool isPrimary(AssetId id) => _entryPoint == id.path; | 71 bool isPrimary(AssetId id) => _entryPoint == id.path; |
| 72 | 72 |
| 73 Future apply(Transform transform) { | 73 Future apply(Transform transform) { |
| 74 var newEntryPointId = | 74 var newEntryPointId = |
| 75 new AssetId(transform.primaryInput.id.package, _newEntryPoint); | 75 new AssetId(transform.primaryInput.id.package, _newEntryPoint); |
| 76 return transform.hasInput(newEntryPointId).then((exists) { | 76 return transform.hasInput(newEntryPointId).then((exists) { |
| 77 if (exists) { | 77 if (exists) { |
| 78 transform.logger | 78 transform.logger |
| 79 .error('New entry point file $newEntryPointId already exists.'); | 79 .error('New entry point file $newEntryPointId already exists.'); |
| 80 } else { | 80 } else { |
| 81 return _resolvers | 81 return _resolvers.get(transform).then((resolver) { |
| 82 .get(transform) | 82 new _BootstrapFileBuilder(resolver, transform, |
| 83 .then((resolver) => new _BootstrapFileBuilder(resolver, transform, | 83 transform.primaryInput.id, newEntryPointId).run(); |
| 84 transform.primaryInput.id, newEntryPointId).run()); | 84 resolver.release(); |
| 85 }); | |
| 85 } | 86 } |
| 86 }); | 87 }); |
| 87 } | 88 } |
| 88 } | 89 } |
| 89 | 90 |
| 90 class _BootstrapFileBuilder { | 91 class _BootstrapFileBuilder { |
| 91 final Resolver _resolver; | 92 final Resolver _resolver; |
| 92 final Transform _transform; | 93 final Transform _transform; |
| 93 AssetId _entryPoint; | 94 AssetId _entryPoint; |
| 94 AssetId _newEntryPoint; | 95 AssetId _newEntryPoint; |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 181 } | 182 } |
| 182 | 183 |
| 183 String _buildNewEntryPoint(LibraryElement entryLib) { | 184 String _buildNewEntryPoint(LibraryElement entryLib) { |
| 184 var importsBuffer = new StringBuffer(); | 185 var importsBuffer = new StringBuffer(); |
| 185 var initializersBuffer = new StringBuffer(); | 186 var initializersBuffer = new StringBuffer(); |
| 186 var libraryPrefixes = new Map<LibraryElement, String>(); | 187 var libraryPrefixes = new Map<LibraryElement, String>(); |
| 187 | 188 |
| 188 // Import the static_loader and original entry point. | 189 // Import the static_loader and original entry point. |
| 189 importsBuffer | 190 importsBuffer |
| 190 .writeln("import 'package:initialize/src/static_loader.dart';"); | 191 .writeln("import 'package:initialize/src/static_loader.dart';"); |
| 191 _maybeWriteImport(entryLib, libraryPrefixes, importsBuffer); | 192 libraryPrefixes[entryLib] = 'i0'; |
| 192 | 193 |
| 193 initializersBuffer.writeln(' initializers.addAll(['); | 194 initializersBuffer.writeln(' initializers.addAll(['); |
| 194 while (_initQueue.isNotEmpty) { | 195 while (_initQueue.isNotEmpty) { |
| 195 var next = _initQueue.removeFirst(); | 196 var next = _initQueue.removeFirst(); |
| 196 | 197 |
| 197 _maybeWriteImport(next.element.library, libraryPrefixes, importsBuffer); | 198 libraryPrefixes.putIfAbsent( |
| 198 _maybeWriteImport( | 199 next.element.library, () => 'i${libraryPrefixes.length}'); |
| 199 next.annotation.element.library, libraryPrefixes, importsBuffer); | 200 libraryPrefixes.putIfAbsent( |
| 201 next.annotation.element.library, () => 'i${libraryPrefixes.length}'); | |
| 200 | 202 |
| 201 _writeInitializer(next, libraryPrefixes, initializersBuffer); | 203 _writeInitializer(next, libraryPrefixes, initializersBuffer); |
| 202 } | 204 } |
| 203 initializersBuffer.writeln(' ]);'); | 205 initializersBuffer.writeln(' ]);'); |
| 204 | 206 |
| 207 libraryPrefixes | |
| 208 .forEach((lib, prefix) => _writeImport(lib, prefix, importsBuffer)); | |
| 209 | |
| 205 // TODO(jakemac): copyright and library declaration | 210 // TODO(jakemac): copyright and library declaration |
| 206 return ''' | 211 return ''' |
| 207 $importsBuffer | 212 $importsBuffer |
| 208 main() { | 213 main() { |
| 209 $initializersBuffer | 214 $initializersBuffer |
| 210 i0.main(); | 215 i0.main(); |
| 211 } | 216 } |
| 212 '''; | 217 '''; |
| 213 } | 218 } |
| 214 | 219 |
| 215 // Writes an import to library if it doesn't exist yet if libraries. | |
| 216 _maybeWriteImport(LibraryElement library, | |
| 217 Map<LibraryElement, String> libraries, StringBuffer buffer) { | |
| 218 if (libraries.containsKey(library)) return; | |
| 219 var prefix = 'i${libraries.length}'; | |
| 220 libraries[library] = prefix; | |
| 221 _writeImport(library, prefix, buffer); | |
| 222 } | |
| 223 | |
| 224 _writeImport(LibraryElement lib, String prefix, StringBuffer buffer) { | 220 _writeImport(LibraryElement lib, String prefix, StringBuffer buffer) { |
| 225 AssetId id = (lib.source as dynamic).assetId; | 221 AssetId id = (lib.source as dynamic).assetId; |
| 226 | 222 |
| 227 if (id.path.startsWith('lib/')) { | 223 if (id.path.startsWith('lib/')) { |
| 228 var packagePath = id.path.replaceFirst('lib/', ''); | 224 var packagePath = id.path.replaceFirst('lib/', ''); |
| 229 buffer.write("import 'package:${id.package}/${packagePath}'"); | 225 buffer.write("import 'package:${id.package}/${packagePath}'"); |
| 230 } else if (id.package != _newEntryPoint.package) { | 226 } else if (id.package != _newEntryPoint.package) { |
| 231 _logger.error("Can't import `${id}` from `${_newEntryPoint}`"); | 227 _logger.error("Can't import `${id}` from `${_newEntryPoint}`"); |
| 232 } else if (path.url.split(id.path)[0] == | 228 } else if (path.url.split(id.path)[0] == |
| 233 path.url.split(_newEntryPoint.path)[0]) { | 229 path.url.split(_newEntryPoint.path)[0]) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 270 'and top level methods. Found $node.'); | 266 'and top level methods. Found $node.'); |
| 271 } | 267 } |
| 272 final annotation = | 268 final annotation = |
| 273 astMeta.firstWhere((m) => m.elementAnnotation == data.annotation); | 269 astMeta.firstWhere((m) => m.elementAnnotation == data.annotation); |
| 274 final clazz = annotation.name; | 270 final clazz = annotation.name; |
| 275 final constructor = annotation.constructorName == null | 271 final constructor = annotation.constructorName == null |
| 276 ? '' | 272 ? '' |
| 277 : '.${annotation.constructorName}'; | 273 : '.${annotation.constructorName}'; |
| 278 // TODO(jakemac): Support more than raw values here | 274 // TODO(jakemac): Support more than raw values here |
| 279 // https://github.com/dart-lang/static_init/issues/5 | 275 // https://github.com/dart-lang/static_init/issues/5 |
| 280 final args = annotation.arguments; | 276 final args = _buildArgsString(annotation.arguments, libraryPrefixes); |
| 281 buffer.write(''' | 277 buffer.write(''' |
| 282 new InitEntry(const $metaPrefix.${clazz}$constructor$args, $elementString), | 278 new InitEntry(const $metaPrefix.${clazz}$constructor$args, $elementString), |
| 283 '''); | 279 '''); |
| 284 } else if (annotationElement is PropertyAccessorElement) { | 280 } else if (annotationElement is PropertyAccessorElement) { |
| 285 buffer.write(''' | 281 buffer.write(''' |
| 286 new InitEntry($metaPrefix.${annotationElement.name}, $elementString), | 282 new InitEntry($metaPrefix.${annotationElement.name}, $elementString), |
| 287 '''); | 283 '''); |
| 284 } else { | |
| 285 _logger.error('Unsupported annotation type. Only constructors and ' | |
| 286 'properties are supported as initializers.'); | |
| 288 } | 287 } |
| 289 } | 288 } |
| 290 | 289 |
| 290 String _buildArgsString( | |
| 291 ArgumentList args, Map<LibraryElement, String> libraryPrefixes) { | |
| 292 var buffer = new StringBuffer(); | |
| 293 buffer.write('('); | |
| 294 var first = true; | |
| 295 for (var arg in args.arguments) { | |
| 296 if (!first) buffer.write(', '); | |
| 297 first = false; | |
| 298 | |
| 299 Expression expression; | |
| 300 if (arg is NamedExpression) { | |
| 301 buffer.write('${arg.name.label.name}: '); | |
| 302 expression = arg.expression; | |
| 303 } else { | |
| 304 expression = arg; | |
| 305 } | |
| 306 | |
| 307 buffer.write(_expressionString(expression, libraryPrefixes)); | |
| 308 } | |
| 309 buffer.write(')'); | |
| 310 return buffer.toString(); | |
| 311 } | |
| 312 | |
| 313 String _expressionString(Expression expression, | |
| 314 Map<LibraryElement, String> libraryPrefixes) { | |
| 315 var buffer = new StringBuffer(); | |
| 316 if (expression is StringLiteral) { | |
| 317 var value = expression.stringValue; | |
| 318 if (value == null) { | |
| 319 _logger.error('Only const strings are allowed in initializer ' | |
| 320 'expressions, found $expression'); | |
| 321 } | |
| 322 value = value.replaceAll(r'\', r'\\').replaceAll(r"'", r"\'"); | |
| 323 buffer.write("'$value'"); | |
| 324 } else if (expression is BooleanLiteral || | |
| 325 expression is DoubleLiteral || | |
| 326 expression is IntegerLiteral) { | |
| 327 buffer.write((expression as dynamic).value.toString()); | |
|
Siggi Cherem (dart-lang)
2015/01/23 17:56:28
nit: use the shorter '${e}' instead of e.toString(
jakemac
2015/01/23 21:34:38
Done.
| |
| 328 } else if (expression is NullLiteral) { | |
|
Siggi Cherem (dart-lang)
2015/01/23 17:56:28
you can include this with boolean, double and int,
jakemac
2015/01/23 21:34:38
Done, I originally had it because of the .value ac
Siggi Cherem (dart-lang)
2015/01/23 21:44:23
Ah, good point, I had not seen the .value. Glad it
| |
| 329 buffer.write('null'); | |
| 330 } else if (expression is ListLiteral) { | |
| 331 var constKeyword = expression.constKeyword; | |
| 332 if (constKeyword != null) buffer.write('$constKeyword '); | |
|
Siggi Cherem (dart-lang)
2015/01/23 17:56:28
it should always be const. If it's not const, the
jakemac
2015/01/23 21:34:38
Done.
| |
| 333 buffer.write('['); | |
| 334 var first = true; | |
| 335 for (Expression listExpression in expression.elements) { | |
| 336 if (!first) buffer.write(', '); | |
| 337 first = false; | |
| 338 buffer.write(_expressionString(listExpression, libraryPrefixes)); | |
| 339 } | |
| 340 buffer.write(']'); | |
| 341 } else if (expression is MapLiteral) { | |
| 342 var constKeyword = expression.constKeyword; | |
| 343 if (constKeyword != null) buffer.write('$constKeyword '); | |
|
Siggi Cherem (dart-lang)
2015/01/23 17:56:28
same here
jakemac
2015/01/23 21:34:38
Done.
| |
| 344 buffer.write('{'); | |
| 345 var first = true; | |
| 346 for (MapLiteralEntry entry in expression.entries) { | |
| 347 if (!first) buffer.write(', '); | |
| 348 first = false; | |
| 349 buffer.write(_expressionString(entry.key, libraryPrefixes)); | |
| 350 buffer.write(': '); | |
| 351 buffer.write(_expressionString(entry.value, libraryPrefixes)); | |
| 352 } | |
| 353 buffer.write('}'); | |
| 354 } else if (expression is Identifier) { | |
| 355 var element = expression.bestElement; | |
| 356 if (element == null || !element.isPublic) { | |
| 357 _logger.error('Private constants are not supported in intializer ' | |
| 358 'constructors, found $element.'); | |
| 359 } | |
| 360 libraryPrefixes.putIfAbsent( | |
| 361 element.library, () => 'i${libraryPrefixes.length}'); | |
| 362 | |
| 363 buffer.write('${libraryPrefixes[element.library]}.'); | |
| 364 if (element is ClassElement) { | |
| 365 buffer.write(element.name); | |
| 366 } else if (element is PropertyAccessorElement) { | |
| 367 var variable = element.variable; | |
| 368 if (variable is FieldElement) { | |
| 369 buffer.write('${variable.enclosingElement.name}.'); | |
| 370 } | |
| 371 buffer.write('${variable.name}'); | |
| 372 } else { | |
| 373 _logger.error('Unsupported argument to initializer constructor.'); | |
| 374 } | |
| 375 } else { | |
| 376 _logger.error('Only literals and identifiers are allowed for initializer ' | |
| 377 'expressions, found $expression.'); | |
| 378 } | |
| 379 return buffer.toString(); | |
| 380 } | |
| 381 | |
| 291 bool _isInitializer(InterfaceType type) { | 382 bool _isInitializer(InterfaceType type) { |
| 292 if (type == null) return false; | 383 if (type == null) return false; |
| 293 if (type.element.type == _initializer.type) return true; | 384 if (type.element.type == _initializer.type) return true; |
| 294 if (_isInitializer(type.superclass)) return true; | 385 if (_isInitializer(type.superclass)) return true; |
| 295 for (var interface in type.interfaces) { | 386 for (var interface in type.interfaces) { |
| 296 if (_isInitializer(interface)) return true; | 387 if (_isInitializer(interface)) return true; |
| 297 } | 388 } |
| 298 return false; | 389 return false; |
| 299 } | 390 } |
| 300 | 391 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 374 })).map((import) => import.importedLibrary); | 465 })).map((import) => import.importedLibrary); |
| 375 } | 466 } |
| 376 | 467 |
| 377 // Element/ElementAnnotation pair. | 468 // Element/ElementAnnotation pair. |
| 378 class _InitializerData { | 469 class _InitializerData { |
| 379 final Element element; | 470 final Element element; |
| 380 final ElementAnnotation annotation; | 471 final ElementAnnotation annotation; |
| 381 | 472 |
| 382 _InitializerData(this.element, this.annotation); | 473 _InitializerData(this.element, this.annotation); |
| 383 } | 474 } |
| OLD | NEW |