Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1000)

Side by Side Diff: lib/transformer.dart

Issue 865293002: support basic identifiers in constructors (Closed) Base URL: git@github.com:dart-lang/static-init.git@master
Patch Set: add support for list and map literals Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « CHANGELOG.md ('k') | pubspec.yaml » ('j') | test/common.dart » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « CHANGELOG.md ('k') | pubspec.yaml » ('j') | test/common.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698