| 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 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 } | 86 } |
| 87 | 87 |
| 88 Future _buildBootstrapFile(Transform transform) { | 88 Future _buildBootstrapFile(Transform transform) { |
| 89 var newEntryPointId = | 89 var newEntryPointId = |
| 90 new AssetId(transform.primaryInput.id.package, _newEntryPoint); | 90 new AssetId(transform.primaryInput.id.package, _newEntryPoint); |
| 91 return transform.hasInput(newEntryPointId).then((exists) { | 91 return transform.hasInput(newEntryPointId).then((exists) { |
| 92 if (exists) { | 92 if (exists) { |
| 93 transform.logger | 93 transform.logger |
| 94 .error('New entry point file $newEntryPointId already exists.'); | 94 .error('New entry point file $newEntryPointId already exists.'); |
| 95 } else { | 95 } else { |
| 96 return _resolvers | 96 return _resolvers.get(transform).then((resolver) { |
| 97 .get(transform) | 97 new _BootstrapFileBuilder(resolver, transform, |
| 98 .then((resolver) => new _BootstrapFileBuilder(resolver, transform, | 98 transform.primaryInput.id, newEntryPointId).run(); |
| 99 transform.primaryInput.id, newEntryPointId).run()); | 99 resolver.release(); |
| 100 }); |
| 100 } | 101 } |
| 101 }); | 102 }); |
| 102 } | 103 } |
| 103 | 104 |
| 104 Future _replaceEntryWithBootstrap(Transform transform) { | 105 Future _replaceEntryWithBootstrap(Transform transform) { |
| 105 // For now at least, _htmlEntryPoint, _entryPoint, and _newEntryPoint need | 106 // For now at least, _htmlEntryPoint, _entryPoint, and _newEntryPoint need |
| 106 // to be in the same folder. | 107 // to be in the same folder. |
| 107 // TODO(jakemac): support package urls with _entryPoint or _newEntryPoint | 108 // TODO(jakemac): support package urls with _entryPoint or _newEntryPoint |
| 108 // in `lib`, and _htmlEntryPoint in another directory. | 109 // in `lib`, and _htmlEntryPoint in another directory. |
| 109 var _expectedDir = path.split(_htmlEntryPoint)[0]; | 110 var _expectedDir = path.split(_htmlEntryPoint)[0]; |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 237 } | 238 } |
| 238 | 239 |
| 239 String _buildNewEntryPoint(LibraryElement entryLib) { | 240 String _buildNewEntryPoint(LibraryElement entryLib) { |
| 240 var importsBuffer = new StringBuffer(); | 241 var importsBuffer = new StringBuffer(); |
| 241 var initializersBuffer = new StringBuffer(); | 242 var initializersBuffer = new StringBuffer(); |
| 242 var libraryPrefixes = new Map<LibraryElement, String>(); | 243 var libraryPrefixes = new Map<LibraryElement, String>(); |
| 243 | 244 |
| 244 // Import the static_loader and original entry point. | 245 // Import the static_loader and original entry point. |
| 245 importsBuffer | 246 importsBuffer |
| 246 .writeln("import 'package:initialize/src/static_loader.dart';"); | 247 .writeln("import 'package:initialize/src/static_loader.dart';"); |
| 247 _maybeWriteImport(entryLib, libraryPrefixes, importsBuffer); | 248 libraryPrefixes[entryLib] = 'i0'; |
| 248 | 249 |
| 249 initializersBuffer.writeln(' initializers.addAll(['); | 250 initializersBuffer.writeln(' initializers.addAll(['); |
| 250 while (_initQueue.isNotEmpty) { | 251 while (_initQueue.isNotEmpty) { |
| 251 var next = _initQueue.removeFirst(); | 252 var next = _initQueue.removeFirst(); |
| 252 | 253 |
| 253 _maybeWriteImport(next.element.library, libraryPrefixes, importsBuffer); | 254 libraryPrefixes.putIfAbsent( |
| 254 _maybeWriteImport( | 255 next.element.library, () => 'i${libraryPrefixes.length}'); |
| 255 next.annotation.element.library, libraryPrefixes, importsBuffer); | 256 libraryPrefixes.putIfAbsent( |
| 257 next.annotation.element.library, () => 'i${libraryPrefixes.length}'); |
| 256 | 258 |
| 257 _writeInitializer(next, libraryPrefixes, initializersBuffer); | 259 _writeInitializer(next, libraryPrefixes, initializersBuffer); |
| 258 } | 260 } |
| 259 initializersBuffer.writeln(' ]);'); | 261 initializersBuffer.writeln(' ]);'); |
| 260 | 262 |
| 263 libraryPrefixes |
| 264 .forEach((lib, prefix) => _writeImport(lib, prefix, importsBuffer)); |
| 265 |
| 261 // TODO(jakemac): copyright and library declaration | 266 // TODO(jakemac): copyright and library declaration |
| 262 return ''' | 267 return ''' |
| 263 $importsBuffer | 268 $importsBuffer |
| 264 main() { | 269 main() { |
| 265 $initializersBuffer | 270 $initializersBuffer |
| 266 i0.main(); | 271 i0.main(); |
| 267 } | 272 } |
| 268 '''; | 273 '''; |
| 269 } | 274 } |
| 270 | 275 |
| 271 // Writes an import to library if it doesn't exist yet if libraries. | |
| 272 _maybeWriteImport(LibraryElement library, | |
| 273 Map<LibraryElement, String> libraries, StringBuffer buffer) { | |
| 274 if (libraries.containsKey(library)) return; | |
| 275 var prefix = 'i${libraries.length}'; | |
| 276 libraries[library] = prefix; | |
| 277 _writeImport(library, prefix, buffer); | |
| 278 } | |
| 279 | |
| 280 _writeImport(LibraryElement lib, String prefix, StringBuffer buffer) { | 276 _writeImport(LibraryElement lib, String prefix, StringBuffer buffer) { |
| 281 AssetId id = (lib.source as dynamic).assetId; | 277 AssetId id = (lib.source as dynamic).assetId; |
| 282 | 278 |
| 283 if (id.path.startsWith('lib/')) { | 279 if (id.path.startsWith('lib/')) { |
| 284 var packagePath = id.path.replaceFirst('lib/', ''); | 280 var packagePath = id.path.replaceFirst('lib/', ''); |
| 285 buffer.write("import 'package:${id.package}/${packagePath}'"); | 281 buffer.write("import 'package:${id.package}/${packagePath}'"); |
| 286 } else if (id.package != _newEntryPoint.package) { | 282 } else if (id.package != _newEntryPoint.package) { |
| 287 _logger.error("Can't import `${id}` from `${_newEntryPoint}`"); | 283 _logger.error("Can't import `${id}` from `${_newEntryPoint}`"); |
| 288 } else if (path.url.split(id.path)[0] == | 284 } else if (path.url.split(id.path)[0] == |
| 289 path.url.split(_newEntryPoint.path)[0]) { | 285 path.url.split(_newEntryPoint.path)[0]) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 326 'and top level methods. Found $node.'); | 322 'and top level methods. Found $node.'); |
| 327 } | 323 } |
| 328 final annotation = | 324 final annotation = |
| 329 astMeta.firstWhere((m) => m.elementAnnotation == data.annotation); | 325 astMeta.firstWhere((m) => m.elementAnnotation == data.annotation); |
| 330 final clazz = annotation.name; | 326 final clazz = annotation.name; |
| 331 final constructor = annotation.constructorName == null | 327 final constructor = annotation.constructorName == null |
| 332 ? '' | 328 ? '' |
| 333 : '.${annotation.constructorName}'; | 329 : '.${annotation.constructorName}'; |
| 334 // TODO(jakemac): Support more than raw values here | 330 // TODO(jakemac): Support more than raw values here |
| 335 // https://github.com/dart-lang/static_init/issues/5 | 331 // https://github.com/dart-lang/static_init/issues/5 |
| 336 final args = annotation.arguments; | 332 final args = _buildArgsString(annotation.arguments, libraryPrefixes); |
| 337 buffer.write(''' | 333 buffer.write(''' |
| 338 new InitEntry(const $metaPrefix.${clazz}$constructor$args, $elementString), | 334 new InitEntry(const $metaPrefix.${clazz}$constructor$args, $elementString), |
| 339 '''); | 335 '''); |
| 340 } else if (annotationElement is PropertyAccessorElement) { | 336 } else if (annotationElement is PropertyAccessorElement) { |
| 341 buffer.write(''' | 337 buffer.write(''' |
| 342 new InitEntry($metaPrefix.${annotationElement.name}, $elementString), | 338 new InitEntry($metaPrefix.${annotationElement.name}, $elementString), |
| 343 '''); | 339 '''); |
| 340 } else { |
| 341 _logger.error('Unsupported annotation type. Only constructors and ' |
| 342 'properties are supported as initializers.'); |
| 344 } | 343 } |
| 345 } | 344 } |
| 346 | 345 |
| 346 String _buildArgsString( |
| 347 ArgumentList args, Map<LibraryElement, String> libraryPrefixes) { |
| 348 var buffer = new StringBuffer(); |
| 349 buffer.write('('); |
| 350 var first = true; |
| 351 for (var arg in args.arguments) { |
| 352 if (!first) buffer.write(', '); |
| 353 first = false; |
| 354 |
| 355 Expression expression; |
| 356 if (arg is NamedExpression) { |
| 357 buffer.write('${arg.name.label.name}: '); |
| 358 expression = arg.expression; |
| 359 } else { |
| 360 expression = arg; |
| 361 } |
| 362 |
| 363 buffer.write(_expressionString(expression, libraryPrefixes)); |
| 364 } |
| 365 buffer.write(')'); |
| 366 return buffer.toString(); |
| 367 } |
| 368 |
| 369 String _expressionString( |
| 370 Expression expression, Map<LibraryElement, String> libraryPrefixes) { |
| 371 var buffer = new StringBuffer(); |
| 372 if (expression is StringLiteral) { |
| 373 var value = expression.stringValue; |
| 374 if (value == null) { |
| 375 _logger.error('Only const strings are allowed in initializer ' |
| 376 'expressions, found $expression'); |
| 377 } |
| 378 value = value.replaceAll(r'\', r'\\').replaceAll(r"'", r"\'"); |
| 379 buffer.write("'$value'"); |
| 380 } else if (expression is BooleanLiteral || |
| 381 expression is DoubleLiteral || |
| 382 expression is IntegerLiteral || |
| 383 expression is NullLiteral) { |
| 384 buffer.write('${expression}'); |
| 385 } else if (expression is ListLiteral) { |
| 386 buffer.write('const ['); |
| 387 var first = true; |
| 388 for (Expression listExpression in expression.elements) { |
| 389 if (!first) buffer.write(', '); |
| 390 first = false; |
| 391 buffer.write(_expressionString(listExpression, libraryPrefixes)); |
| 392 } |
| 393 buffer.write(']'); |
| 394 } else if (expression is MapLiteral) { |
| 395 buffer.write('const {'); |
| 396 var first = true; |
| 397 for (MapLiteralEntry entry in expression.entries) { |
| 398 if (!first) buffer.write(', '); |
| 399 first = false; |
| 400 buffer.write(_expressionString(entry.key, libraryPrefixes)); |
| 401 buffer.write(': '); |
| 402 buffer.write(_expressionString(entry.value, libraryPrefixes)); |
| 403 } |
| 404 buffer.write('}'); |
| 405 } else if (expression is Identifier) { |
| 406 var element = expression.bestElement; |
| 407 if (element == null || !element.isPublic) { |
| 408 _logger.error('Private constants are not supported in intializer ' |
| 409 'constructors, found $element.'); |
| 410 } |
| 411 libraryPrefixes.putIfAbsent( |
| 412 element.library, () => 'i${libraryPrefixes.length}'); |
| 413 |
| 414 buffer.write('${libraryPrefixes[element.library]}.'); |
| 415 if (element is ClassElement) { |
| 416 buffer.write(element.name); |
| 417 } else if (element is PropertyAccessorElement) { |
| 418 var variable = element.variable; |
| 419 if (variable is FieldElement) { |
| 420 buffer.write('${variable.enclosingElement.name}.'); |
| 421 } |
| 422 buffer.write('${variable.name}'); |
| 423 } else { |
| 424 _logger.error('Unsupported argument to initializer constructor.'); |
| 425 } |
| 426 } else { |
| 427 _logger.error('Only literals and identifiers are allowed for initializer ' |
| 428 'expressions, found $expression.'); |
| 429 } |
| 430 return buffer.toString(); |
| 431 } |
| 432 |
| 347 bool _isInitializer(InterfaceType type) { | 433 bool _isInitializer(InterfaceType type) { |
| 348 if (type == null) return false; | 434 if (type == null) return false; |
| 349 if (type.element.type == _initializer.type) return true; | 435 if (type.element.type == _initializer.type) return true; |
| 350 if (_isInitializer(type.superclass)) return true; | 436 if (_isInitializer(type.superclass)) return true; |
| 351 for (var interface in type.interfaces) { | 437 for (var interface in type.interfaces) { |
| 352 if (_isInitializer(interface)) return true; | 438 if (_isInitializer(interface)) return true; |
| 353 } | 439 } |
| 354 return false; | 440 return false; |
| 355 } | 441 } |
| 356 | 442 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 430 })).map((import) => import.importedLibrary); | 516 })).map((import) => import.importedLibrary); |
| 431 } | 517 } |
| 432 | 518 |
| 433 // Element/ElementAnnotation pair. | 519 // Element/ElementAnnotation pair. |
| 434 class _InitializerData { | 520 class _InitializerData { |
| 435 final Element element; | 521 final Element element; |
| 436 final ElementAnnotation annotation; | 522 final ElementAnnotation annotation; |
| 437 | 523 |
| 438 _InitializerData(this.element, this.annotation); | 524 _InitializerData(this.element, this.annotation); |
| 439 } | 525 } |
| OLD | NEW |