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

Side by Side Diff: pkg/analyzer/tool/summary/generate.dart

Issue 1576663002: Use FlatBuffers for summaries. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 4 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
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 4
5 /** 5 /**
6 * This file contains code to generate serialization/deserialization logic for 6 * This file contains code to generate serialization/deserialization logic for
7 * summaries based on an "IDL" description of the summary format (written in 7 * summaries based on an "IDL" description of the summary format (written in
8 * stylized Dart). 8 * stylized Dart).
9 * 9 *
10 * For each class in the "IDL" input, two corresponding classes are generated: 10 * For each class in the "IDL" input, two corresponding classes are generated:
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after
253 checkIdl(); 253 checkIdl();
254 out('// Copyright (c) 2015, the Dart project authors. Please see the AUTHOR S file'); 254 out('// Copyright (c) 2015, the Dart project authors. Please see the AUTHOR S file');
255 out('// for details. All rights reserved. Use of this source code is governe d by a'); 255 out('// for details. All rights reserved. Use of this source code is governe d by a');
256 out('// BSD-style license that can be found in the LICENSE file.'); 256 out('// BSD-style license that can be found in the LICENSE file.');
257 out('//'); 257 out('//');
258 out('// This file has been automatically generated. Please do not edit it m anually.'); 258 out('// This file has been automatically generated. Please do not edit it m anually.');
259 out('// To regenerate the file, use the script "pkg/analyzer/tool/generate_f iles".'); 259 out('// To regenerate the file, use the script "pkg/analyzer/tool/generate_f iles".');
260 out(); 260 out();
261 out('library analyzer.src.summary.format;'); 261 out('library analyzer.src.summary.format;');
262 out(); 262 out();
263 out("import 'dart:convert';");
264 out("import 'base.dart' as base;"); 263 out("import 'base.dart' as base;");
264 out("import 'flat_buffers.dart' as fb;");
265 out(); 265 out();
266 _idl.enums.forEach((String name, idlModel.EnumDeclaration enm) { 266 _idl.enums.forEach((String name, idlModel.EnumDeclaration enm) {
267 outDoc(enm.documentation); 267 outDoc(enm.documentation);
268 out('enum $name {'); 268 out('enum $name {');
269 indent(() { 269 indent(() {
270 for (String value in enm.values) { 270 for (String value in enm.values) {
271 out('$value,'); 271 out('$value,');
272 } 272 }
273 }); 273 });
274 out('}'); 274 out('}');
275 out(); 275 out();
276 }); 276 });
277 _idl.classes.forEach((String name, idlModel.ClassDeclaration cls) { 277 for (var cls in _idl.classes.values) {
278 outDoc(cls.documentation); 278 List<String> builderParams = _generateBuilder(cls);
279 out('class $name extends base.SummaryClass {'); 279 out();
280 indent(() { 280 _generateEncodeFunction(cls, builderParams);
281 for (idlModel.FieldDeclaration field in cls.fields) { 281 out();
282 String fieldName = field.name; 282 _generateInterface(cls);
283 idlModel.FieldType type = field.type; 283 out();
284 out('${dartType(type)} _$fieldName;'); 284 _generateReader(cls);
285 } 285 out();
286 out(); 286 }
287 out('$name.fromJson(Map json)');
288 indent(() {
289 List<String> initializers = <String>[];
290 for (idlModel.FieldDeclaration field in cls.fields) {
291 String fieldName = field.name;
292 idlModel.FieldType type = field.type;
293 String convert = 'json[${quoted(fieldName)}]';
294 if (type.isList) {
295 if (type.typeName == 'int' || type.typeName == 'String') {
296 // No conversion necessary.
297 } else {
298 convert =
299 '$convert?.map((x) => new ${type.typeName}.fromJson(x))?.toL ist()';
300 }
301 } else if (_idl.classes.containsKey(type.typeName)) {
302 convert =
303 '$convert == null ? null : new ${type.typeName}.fromJson($conv ert)';
304 } else if (_idl.enums.containsKey(type.typeName)) {
305 convert =
306 '$convert == null ? null : ${type.typeName}.values[$convert]';
307 }
308 initializers.add('_$fieldName = $convert');
309 }
310 for (int i = 0; i < initializers.length; i++) {
311 String prefix = i == 0 ? ': ' : ' ';
312 String suffix = i == initializers.length - 1 ? ';' : ',';
313 out('$prefix${initializers[i]}$suffix');
314 }
315 });
316 out();
317 out('@override');
318 out('Map<String, Object> toMap() => {');
319 indent(() {
320 for (idlModel.FieldDeclaration field in cls.fields) {
321 String fieldName = field.name;
322 out('${quoted(fieldName)}: $fieldName,');
323 }
324 });
325 out('};');
326 out();
327 if (cls.isTopLevel) {
328 out('$name.fromBuffer(List<int> buffer) : this.fromJson(JSON.decode(UT F8.decode(buffer)));');
329 out();
330 }
331 cls.fields.asMap().forEach((index, field) {
332 String fieldName = field.name;
333 idlModel.FieldType type = field.type;
334 if (index != 0) {
335 out();
336 }
337 String def = defaultValue(type);
338 String defaultSuffix = def == null ? '' : ' ?? $def';
339 outDoc(field.documentation);
340 out('${dartType(type)} get $fieldName => _$fieldName$defaultSuffix;');
341 });
342 });
343 out('}');
344 out();
345 List<String> builderParams = <String>[];
346 out('class ${name}Builder {');
347 indent(() {
348 out('final Map _json = {};');
349 out();
350 out('bool _finished = false;');
351 out();
352 out('${name}Builder(base.BuilderContext context);');
353 for (idlModel.FieldDeclaration field in cls.fields) {
354 String fieldName = field.name;
355 idlModel.FieldType type = field.type;
356 out();
357 outDoc(field.documentation);
358 String conversion = '_value';
359 String condition = '';
360 if (type.isList) {
361 if (_idl.classes.containsKey(type.typeName)) {
362 conversion = '$conversion.map((b) => b.finish()).toList()';
363 } else {
364 conversion = '$conversion.toList()';
365 }
366 condition = ' || _value.isEmpty';
367 } else if (_idl.enums.containsKey(type.typeName)) {
368 conversion = '$conversion.index';
369 condition = ' || _value == ${defaultValue(type)}';
370 } else if (_idl.classes.containsKey(type.typeName)) {
371 conversion = '$conversion.finish()';
372 }
373 builderParams.add('${encodedType(type)} $fieldName');
374 out('void set $fieldName(${encodedType(type)} _value) {');
375 indent(() {
376 out('assert(!_finished);');
377 out('assert(!_json.containsKey(${quoted(fieldName)}));');
378 if (condition.isEmpty) {
379 out('if (_value != null) {');
380 } else {
381 out('if (!(_value == null$condition)) {');
382 }
383 indent(() {
384 out('_json[${quoted(fieldName)}] = $conversion;');
385 });
386 out('}');
387 });
388 out('}');
389 }
390 if (cls.isTopLevel) {
391 out();
392 out('List<int> toBuffer() => UTF8.encode(JSON.encode(finish()));');
393 }
394 out();
395 out('Map finish() {');
396 indent(() {
397 out('assert(!_finished);');
398 out('_finished = true;');
399 out('return _json;');
400 });
401 out('}');
402 });
403 out('}');
404 out();
405 out('${name}Builder encode$name(base.BuilderContext builderContext, {${bui lderParams.join(', ')}}) {');
406 indent(() {
407 out('${name}Builder builder = new ${name}Builder(builderContext);');
408 for (idlModel.FieldDeclaration field in cls.fields) {
409 String fieldName = field.name;
410 out('builder.$fieldName = $fieldName;');
411 }
412 out('return builder;');
413 });
414 out('}');
415 out();
416 });
417 } 287 }
418 288
419 /** 289 /**
420 * Enclose [s] in quotes, escaping as necessary. 290 * Enclose [s] in quotes, escaping as necessary.
421 */ 291 */
422 String quoted(String s) { 292 String quoted(String s) {
423 return JSON.encode(s); 293 return JSON.encode(s);
424 } 294 }
425 295
296 List<String> _generateBuilder(idlModel.ClassDeclaration cls) {
297 String builderName = cls.name + 'Builder';
298 List<String> builderParams = <String>[];
299 out('class $builderName {');
300 indent(() {
301 out('bool _finished = false;');
302 // Generate fields.
303 out();
304 for (idlModel.FieldDeclaration field in cls.fields) {
305 String fieldName = field.name;
306 idlModel.FieldType type = field.type;
307 String typeStr = encodedType(type);
308 out('$typeStr _$fieldName;');
309 }
310 out();
311 for (idlModel.FieldDeclaration field in cls.fields) {
312 String fieldName = field.name;
313 String isSetFieldName = '_' + fieldName + 'IsSet';
314 out('bool $isSetFieldName = false;');
315 }
316 // Generate constructor.
317 out();
318 out('$builderName(base.BuilderContext context);');
319 // Generate setters.
320 for (idlModel.FieldDeclaration field in cls.fields) {
321 String fieldName = field.name;
322 String typeStr = encodedType(field.type);
323 out();
324 outDoc(field.documentation);
325 builderParams.add('$typeStr $fieldName');
326 out('void set $fieldName($typeStr _value) {');
327 indent(() {
328 String stateFieldName = '_' + fieldName;
329 String stateIsSetFieldName = stateFieldName + 'IsSet';
330 out('assert(!_finished);');
331 out('assert(!$stateIsSetFieldName);');
332 out('$stateIsSetFieldName = true;');
333 out('$stateFieldName = _value;');
334 });
335 out('}');
336 }
337 // Generate finish.
338 if (cls.isTopLevel) {
339 out();
340 out('List<int> toBuffer() {');
341 indent(() {
342 out('fb.Builder fbBuilder = new fb.Builder();');
343 out('return fbBuilder.finish(finish(fbBuilder));');
344 });
345 out('}');
346 }
347 out();
348 out('fb.Offset finish(fb.Builder fbBuilder) {');
349 indent(() {
350 out('assert(!_finished);');
351 out('_finished = true;');
352 // Write objects and remember Offset(s).
353 cls.fields.asMap().forEach((index, idlModel.FieldDeclaration field) {
354 idlModel.FieldType fieldType = field.type;
355 String offsetName = 'offset_' + field.name;
356 if (fieldType.isList ||
357 fieldType.typeName == 'String' ||
358 _idl.classes.containsKey(fieldType.typeName)) {
359 out('fb.Offset $offsetName;');
360 }
361 });
362 cls.fields.asMap().forEach((index, idlModel.FieldDeclaration field) {
363 idlModel.FieldType fieldType = field.type;
364 String valueName = '_' + field.name;
365 String offsetName = 'offset_' + field.name;
366 String condition;
367 String writeCode;
368 if (fieldType.isList) {
369 condition = ' || $valueName.isEmpty';
370 if (_idl.classes.containsKey(fieldType.typeName)) {
371 String itemCode = 'b.finish(fbBuilder)';
372 String listCode = '$valueName.map((b) => $itemCode).toList()';
373 writeCode = '$offsetName = fbBuilder.writeList($listCode);';
374 } else if (fieldType.typeName == 'int') {
375 writeCode = '$offsetName = fbBuilder.writeListInt32($valueName);';
376 } else {
377 assert(fieldType.typeName == 'String');
378 String itemCode = 'fbBuilder.writeString(b)';
379 String listCode = '$valueName.map((b) => $itemCode).toList()';
380 writeCode = '$offsetName = fbBuilder.writeList($listCode);';
381 }
382 } else if (fieldType.typeName == 'String') {
383 writeCode = '$offsetName = fbBuilder.writeString($valueName);';
384 } else if (_idl.classes.containsKey(fieldType.typeName)) {
385 writeCode = '$offsetName = $valueName.finish(fbBuilder);';
386 }
387 if (writeCode != null) {
388 if (condition == null) {
389 out('if ($valueName != null) {');
390 } else {
391 out('if (!($valueName == null$condition)) {');
392 }
393 indent(() {
394 out(writeCode);
395 });
396 out('}');
397 }
398 });
399 // Write the table.
400 out('fbBuilder.startTable();');
401 cls.fields.asMap().forEach((index, idlModel.FieldDeclaration field) {
402 idlModel.FieldType fieldType = field.type;
403 String valueName = '_' + field.name;
404 String offsetName = 'offset_' + field.name;
405 String condition = '$valueName != null';
406 String writeCode;
407 if (fieldType.isList ||
408 fieldType.typeName == 'String' ||
409 _idl.classes.containsKey(fieldType.typeName)) {
410 condition = '$offsetName != null';
411 writeCode = 'fbBuilder.addOffset($index, $offsetName);';
412 } else if (fieldType.typeName == 'bool') {
413 // TODO(scheglov) implement booleans merging?
414 condition = '$valueName == true';
415 writeCode = 'fbBuilder.addInt8($index, 1);';
416 } else if (fieldType.typeName == 'int') {
417 condition += ' && $valueName != ${defaultValue(fieldType)}';
418 writeCode = 'fbBuilder.addInt32($index, $valueName);';
419 } else if (_idl.enums.containsKey(fieldType.typeName)) {
420 condition += ' && $valueName != ${defaultValue(fieldType)}';
421 writeCode = 'fbBuilder.addInt32($index, $valueName.index);';
422 }
423 if (writeCode == null) {
424 throw new UnimplementedError('Writing type ${fieldType.typeName}');
425 }
426 out('if ($condition) {');
427 indent(() {
428 out(writeCode);
429 });
430 out('}');
431 });
432 out('return fbBuilder.endTable();');
433 });
434 out('}');
435 });
436 out('}');
437 return builderParams;
438 }
439
440 void _generateEncodeFunction(
441 idlModel.ClassDeclaration cls, List<String> builderParams) {
442 String className = cls.name;
443 String builderName = className + 'Builder';
444 out('$builderName encode$className(base.BuilderContext builderContext, {${bu ilderParams.join(', ')}}) {');
445 indent(() {
446 out('$builderName builder = new $builderName(builderContext);');
447 for (idlModel.FieldDeclaration field in cls.fields) {
448 String fieldName = field.name;
449 out('builder.$fieldName = $fieldName;');
450 }
451 out('return builder;');
452 });
453 out('}');
454 }
455
456 void _generateInterface(idlModel.ClassDeclaration cls) {
457 String name = cls.name;
458 outDoc(cls.documentation);
459 out('abstract class $name extends base.SummaryClass {');
460 indent(() {
461 if (cls.isTopLevel) {
462 out('factory $name.fromBuffer(List<int> buffer) {');
463 indent(() {
464 out('fb.BufferPointer rootRef = new fb.BufferPointer.fromBytes(buffer) ;');
465 out('return const _${name}Reader().read(rootRef);');
466 });
467 out('}');
468 }
469 cls.fields.asMap().forEach((index, field) {
470 String fieldName = field.name;
471 idlModel.FieldType type = field.type;
472 out();
473 outDoc(field.documentation);
474 out('${dartType(type)} get $fieldName;');
475 });
476 });
477 out('}');
478 }
479
480 void _generateReader(idlModel.ClassDeclaration cls) {
481 String name = cls.name;
482 String readerName = '_${name}Reader';
483 out('class $readerName extends fb.TableReader<$readerName> implements $name {');
484 indent(() {
485 out('final fb.BufferPointer _bp;');
486 out();
487 out('const $readerName([this._bp]);');
488 out();
489 out('@override');
490 out('$readerName createReader(fb.BufferPointer bp) => new $readerName(bp); ');
491 out();
492 out('@override');
493 out('Map<String, Object> toMap() => {};');
494 cls.fields.asMap().forEach((index, field) {
495 String fieldName = field.name;
496 idlModel.FieldType type = field.type;
497 String typeName = type.typeName;
498 // Prepare "readLines" or "readCode" + "def" + "readSuffix"
499 List<String> readLines;
500 String readCode;
501 String def = defaultValue(type);
502 String readSuffix = '';
503 if (type.isList) {
504 if (typeName == 'int') {
505 String itemCode = 'const fb.Int32Reader()';
506 readCode = 'const fb.ListReader<int>($itemCode)';
507 } else if (typeName == 'String') {
508 String itemCode = 'const fb.StringReader()';
509 readCode = 'const fb.ListReader<String>($itemCode)';
510 } else {
511 String itemCode = '$typeName>(const _${typeName}Reader()';
512 readCode = 'const fb.ListReader<$itemCode)';
513 }
514 } else if (typeName == 'bool') {
515 // TODO(scheglov) implement booleans merging?
516 def = '0';
517 readCode = 'const fb.Int8Reader()';
518 readSuffix = ' == 1';
519 } else if (typeName == 'int') {
520 readCode = 'const fb.Int32Reader()';
521 } else if (typeName == 'String') {
522 readCode = 'const fb.StringReader()';
523 } else if (_idl.enums.containsKey(typeName)) {
524 readLines = <String>[
525 'int index = const fb.Int32Reader().vTableGet(_bp, $index, 0);',
526 'return $typeName.values[index];'
527 ];
528 } else if (_idl.classes.containsKey(typeName)) {
529 readCode = 'const _${typeName}Reader()';
530 }
531 assert(readCode != null || readLines != null);
532 // Write the getter implementation.
533 out();
534 out('@override');
535 String returnType = dartType(type);
536 if (readLines != null) {
537 out('$returnType get $fieldName {');
538 indent(() {
539 readLines.forEach(out);
540 });
541 out('}');
542 } else {
543 String expr = '$readCode.vTableGet(_bp, $index, $def)$readSuffix';
544 out('$returnType get $fieldName => $expr;');
545 }
546 });
547 });
548 out('}');
549 }
550
426 /** 551 /**
427 * Return the documentation text of the given [node], or `null` if the [node] 552 * Return the documentation text of the given [node], or `null` if the [node]
428 * does not have a comment. Each line is `\n` separated. 553 * does not have a comment. Each line is `\n` separated.
429 */ 554 */
430 String _getNodeDoc(LineInfo lineInfo, AnnotatedNode node) { 555 String _getNodeDoc(LineInfo lineInfo, AnnotatedNode node) {
431 Comment comment = node.documentationComment; 556 Comment comment = node.documentationComment;
432 if (comment != null && 557 if (comment != null &&
433 comment.isDocumentation && 558 comment.isDocumentation &&
434 comment.tokens.length == 1 && 559 comment.tokens.length == 1 &&
435 comment.tokens.first.type == TokenType.MULTI_LINE_COMMENT) { 560 comment.tokens.first.type == TokenType.MULTI_LINE_COMMENT) {
436 Token token = comment.tokens.first; 561 Token token = comment.tokens.first;
437 int column = lineInfo.getLocation(token.offset).columnNumber; 562 int column = lineInfo.getLocation(token.offset).columnNumber;
438 String indent = ' ' * (column - 1); 563 String indent = ' ' * (column - 1);
439 return token.lexeme.split('\n').map((String line) { 564 return token.lexeme.split('\n').map((String line) {
440 if (line.startsWith(indent)) { 565 if (line.startsWith(indent)) {
441 line = line.substring(indent.length); 566 line = line.substring(indent.length);
442 } 567 }
443 return line; 568 return line;
444 }).join('\n'); 569 }).join('\n');
445 } 570 }
446 return null; 571 return null;
447 } 572 }
448 } 573 }
OLDNEW
« pkg/analyzer/lib/src/summary/format.dart ('K') | « pkg/analyzer/test/src/summary/summary_test.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698