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 | 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 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
56 final GeneratedFile schemaTarget = | 56 final GeneratedFile schemaTarget = |
57 new GeneratedFile('lib/src/summary/format.fbs', (String pkgPath) { | 57 new GeneratedFile('lib/src/summary/format.fbs', (String pkgPath) { |
58 _CodeGenerator codeGenerator = new _CodeGenerator(pkgPath); | 58 _CodeGenerator codeGenerator = new _CodeGenerator(pkgPath); |
59 codeGenerator.generateFlatBufferSchema(); | 59 codeGenerator.generateFlatBufferSchema(); |
60 return codeGenerator._outBuffer.toString(); | 60 return codeGenerator._outBuffer.toString(); |
61 }); | 61 }); |
62 | 62 |
63 typedef String _StringToString(String s); | 63 typedef String _StringToString(String s); |
64 | 64 |
65 class _CodeGenerator { | 65 class _CodeGenerator { |
| 66 static const String _throwDeprecated = |
| 67 "throw new UnimplementedError('attempt to access deprecated field')"; |
| 68 |
66 /** | 69 /** |
67 * Buffer in which generated code is accumulated. | 70 * Buffer in which generated code is accumulated. |
68 */ | 71 */ |
69 final StringBuffer _outBuffer = new StringBuffer(); | 72 final StringBuffer _outBuffer = new StringBuffer(); |
70 | 73 |
71 /** | 74 /** |
72 * Current indentation level. | 75 * Current indentation level. |
73 */ | 76 */ |
74 String _indentation = ''; | 77 String _indentation = ''; |
75 | 78 |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
270 if (type.name.name == 'List' && | 273 if (type.name.name == 'List' && |
271 type.typeArguments != null && | 274 type.typeArguments != null && |
272 type.typeArguments.arguments.length == 1) { | 275 type.typeArguments.arguments.length == 1) { |
273 isList = true; | 276 isList = true; |
274 type = type.typeArguments.arguments[0]; | 277 type = type.typeArguments.arguments[0]; |
275 } | 278 } |
276 if (type.typeArguments != null) { | 279 if (type.typeArguments != null) { |
277 throw new Exception('Cannot handle type arguments in `$type`'); | 280 throw new Exception('Cannot handle type arguments in `$type`'); |
278 } | 281 } |
279 int id; | 282 int id; |
| 283 bool isDeprecated = false; |
280 for (Annotation annotation in classMember.metadata) { | 284 for (Annotation annotation in classMember.metadata) { |
281 if (annotation.name.name == 'Id') { | 285 if (annotation.name.name == 'Id') { |
282 if (id != null) { | 286 if (id != null) { |
283 throw new Exception( | 287 throw new Exception( |
284 'Duplicate @id annotation ($classMember)'); | 288 'Duplicate @id annotation ($classMember)'); |
285 } | 289 } |
286 if (annotation.arguments.arguments.length != 1) { | 290 if (annotation.arguments.arguments.length != 1) { |
287 throw new Exception( | 291 throw new Exception( |
288 '@Id must be passed exactly one argument ($desc)'); | 292 '@Id must be passed exactly one argument ($desc)'); |
289 } | 293 } |
290 Expression expression = annotation.arguments.arguments[0]; | 294 Expression expression = annotation.arguments.arguments[0]; |
291 if (expression is IntegerLiteral) { | 295 if (expression is IntegerLiteral) { |
292 id = expression.value; | 296 id = expression.value; |
293 } else { | 297 } else { |
294 throw new Exception( | 298 throw new Exception( |
295 '@Id parameter must be an integer literal ($desc)'); | 299 '@Id parameter must be an integer literal ($desc)'); |
296 } | 300 } |
| 301 } else if (annotation.name.name == 'deprecated') { |
| 302 if (annotation.arguments != null) { |
| 303 throw new Exception('@deprecated does not take args ($desc)'); |
| 304 } |
| 305 isDeprecated = true; |
297 } | 306 } |
298 } | 307 } |
299 if (id == null) { | 308 if (id == null) { |
300 throw new Exception('Missing @id annotation ($desc)'); | 309 throw new Exception('Missing @id annotation ($desc)'); |
301 } | 310 } |
302 String doc = _getNodeDoc(lineInfo, classMember); | 311 String doc = _getNodeDoc(lineInfo, classMember); |
303 idlModel.FieldType fieldType = | 312 idlModel.FieldType fieldType = |
304 new idlModel.FieldType(type.name.name, isList); | 313 new idlModel.FieldType(type.name.name, isList); |
305 cls.fields.add(new idlModel.FieldDeclaration( | 314 cls.allFields.add(new idlModel.FieldDeclaration( |
306 doc, classMember.name.name, fieldType, id)); | 315 doc, classMember.name.name, fieldType, id, isDeprecated)); |
307 } else if (classMember is ConstructorDeclaration && | 316 } else if (classMember is ConstructorDeclaration && |
308 classMember.name.name == 'fromBuffer') { | 317 classMember.name.name == 'fromBuffer') { |
309 // Ignore `fromBuffer` declarations; they simply forward to the | 318 // Ignore `fromBuffer` declarations; they simply forward to the |
310 // read functions generated by [_generateReadFunction]. | 319 // read functions generated by [_generateReadFunction]. |
311 } else { | 320 } else { |
312 throw new Exception('Unexpected class member `$classMember`'); | 321 throw new Exception('Unexpected class member `$classMember`'); |
313 } | 322 } |
314 } | 323 } |
315 } else if (decl is EnumDeclaration) { | 324 } else if (decl is EnumDeclaration) { |
316 String doc = _getNodeDoc(lineInfo, decl); | 325 String doc = _getNodeDoc(lineInfo, decl); |
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
381 out('${value.name}$suffix'); | 390 out('${value.name}$suffix'); |
382 } | 391 } |
383 }); | 392 }); |
384 out('}'); | 393 out('}'); |
385 } | 394 } |
386 for (idlModel.ClassDeclaration cls in _idl.classes.values) { | 395 for (idlModel.ClassDeclaration cls in _idl.classes.values) { |
387 out(); | 396 out(); |
388 outDoc(cls.documentation); | 397 outDoc(cls.documentation); |
389 out('table ${cls.name} {'); | 398 out('table ${cls.name} {'); |
390 indent(() { | 399 indent(() { |
391 for (int i = 0; i < cls.fields.length; i++) { | 400 for (int i = 0; i < cls.allFields.length; i++) { |
392 idlModel.FieldDeclaration field = cls.fields[i]; | 401 idlModel.FieldDeclaration field = cls.allFields[i]; |
393 if (i != 0) { | 402 if (i != 0) { |
394 out(); | 403 out(); |
395 } | 404 } |
396 outDoc(field.documentation); | 405 outDoc(field.documentation); |
397 out('${field.name}:${fbsType(field.type)} (id: ${field.id});'); | 406 List<String> attributes = <String>['id: ${field.id}']; |
| 407 if (field.isDeprecated) { |
| 408 attributes.add('deprecated'); |
| 409 } |
| 410 String attrText = attributes.join(', '); |
| 411 out('${field.name}:${fbsType(field.type)} ($attrText);'); |
398 } | 412 } |
399 }); | 413 }); |
400 out('}'); | 414 out('}'); |
401 } | 415 } |
402 out(); | 416 out(); |
403 // Standard flatbuffers only support one root type. We support multiple | 417 // Standard flatbuffers only support one root type. We support multiple |
404 // root types. For now work around this by forcing PackageBundle to be the | 418 // root types. For now work around this by forcing PackageBundle to be the |
405 // root type. TODO(paulberry): come up with a better solution. | 419 // root type. TODO(paulberry): come up with a better solution. |
406 idlModel.ClassDeclaration rootType = _idl.classes['PackageBundle']; | 420 idlModel.ClassDeclaration rootType = _idl.classes['PackageBundle']; |
407 out('root_type ${rootType.name};'); | 421 out('root_type ${rootType.name};'); |
(...skipping 109 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
517 out('bool _finished = false;'); | 531 out('bool _finished = false;'); |
518 // Generate fields. | 532 // Generate fields. |
519 out(); | 533 out(); |
520 for (idlModel.FieldDeclaration field in cls.fields) { | 534 for (idlModel.FieldDeclaration field in cls.fields) { |
521 String fieldName = field.name; | 535 String fieldName = field.name; |
522 idlModel.FieldType type = field.type; | 536 idlModel.FieldType type = field.type; |
523 String typeStr = encodedType(type); | 537 String typeStr = encodedType(type); |
524 out('$typeStr _$fieldName;'); | 538 out('$typeStr _$fieldName;'); |
525 } | 539 } |
526 // Generate getters and setters. | 540 // Generate getters and setters. |
527 for (idlModel.FieldDeclaration field in cls.fields) { | 541 for (idlModel.FieldDeclaration field in cls.allFields) { |
528 String fieldName = field.name; | 542 String fieldName = field.name; |
529 idlModel.FieldType fieldType = field.type; | 543 idlModel.FieldType fieldType = field.type; |
530 String typeStr = encodedType(fieldType); | 544 String typeStr = encodedType(fieldType); |
531 String def = defaultValue(fieldType, true); | 545 String def = defaultValue(fieldType, true); |
532 String defSuffix = def == null ? '' : ' ??= $def'; | 546 String defSuffix = def == null ? '' : ' ??= $def'; |
533 out(); | 547 out(); |
534 out('@override'); | 548 out('@override'); |
535 out('$typeStr get $fieldName => _$fieldName$defSuffix;'); | 549 if (field.isDeprecated) { |
536 out(); | 550 out('$typeStr get $fieldName => $_throwDeprecated;'); |
537 outDoc(field.documentation); | 551 } else { |
538 constructorParams.add('$typeStr $fieldName'); | 552 out('$typeStr get $fieldName => _$fieldName$defSuffix;'); |
539 out('void set $fieldName($typeStr _value) {'); | 553 out(); |
540 indent(() { | 554 outDoc(field.documentation); |
541 String stateFieldName = '_' + fieldName; | 555 constructorParams.add('$typeStr $fieldName'); |
542 out('assert(!_finished);'); | 556 out('void set $fieldName($typeStr _value) {'); |
543 // Validate that int(s) are non-negative. | 557 indent(() { |
544 if (fieldType.typeName == 'int') { | 558 String stateFieldName = '_' + fieldName; |
545 if (!fieldType.isList) { | 559 out('assert(!_finished);'); |
546 out('assert(_value == null || _value >= 0);'); | 560 // Validate that int(s) are non-negative. |
547 } else { | 561 if (fieldType.typeName == 'int') { |
548 out('assert(_value == null || _value.every((e) => e >= 0));'); | 562 if (!fieldType.isList) { |
| 563 out('assert(_value == null || _value >= 0);'); |
| 564 } else { |
| 565 out('assert(_value == null || _value.every((e) => e >= 0));'); |
| 566 } |
549 } | 567 } |
550 } | 568 // Set the value. |
551 // Set the value. | 569 out('$stateFieldName = _value;'); |
552 out('$stateFieldName = _value;'); | 570 }); |
553 }); | 571 out('}'); |
554 out('}'); | 572 } |
555 } | 573 } |
556 // Generate constructor. | 574 // Generate constructor. |
557 out(); | 575 out(); |
558 out('$builderName({${constructorParams.join(', ')}})'); | 576 out('$builderName({${constructorParams.join(', ')}})'); |
559 for (int i = 0; i < cls.fields.length; i++) { | 577 List<idlModel.FieldDeclaration> fields = cls.fields.toList(); |
560 idlModel.FieldDeclaration field = cls.fields[i]; | 578 for (int i = 0; i < fields.length; i++) { |
| 579 idlModel.FieldDeclaration field = fields[i]; |
561 String prefix = i == 0 ? ' : ' : ' '; | 580 String prefix = i == 0 ? ' : ' : ' '; |
562 String suffix = i == cls.fields.length - 1 ? ';' : ','; | 581 String suffix = i == fields.length - 1 ? ';' : ','; |
563 out('${prefix}_${field.name} = ${field.name}$suffix'); | 582 out('${prefix}_${field.name} = ${field.name}$suffix'); |
564 } | 583 } |
565 // Generate finish. | 584 // Generate finish. |
566 if (cls.isTopLevel) { | 585 if (cls.isTopLevel) { |
567 out(); | 586 out(); |
568 out('List<int> toBuffer() {'); | 587 out('List<int> toBuffer() {'); |
569 indent(() { | 588 indent(() { |
570 out('fb.Builder fbBuilder = new fb.Builder();'); | 589 out('fb.Builder fbBuilder = new fb.Builder();'); |
571 String fileId = cls.fileIdentifier == null | 590 String fileId = cls.fileIdentifier == null |
572 ? '' | 591 ? '' |
(...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
707 out(); | 726 out(); |
708 out('$implName(this._bp);'); | 727 out('$implName(this._bp);'); |
709 out(); | 728 out(); |
710 // Write cache fields. | 729 // Write cache fields. |
711 for (idlModel.FieldDeclaration field in cls.fields) { | 730 for (idlModel.FieldDeclaration field in cls.fields) { |
712 String returnType = dartType(field.type); | 731 String returnType = dartType(field.type); |
713 String fieldName = field.name; | 732 String fieldName = field.name; |
714 out('$returnType _$fieldName;'); | 733 out('$returnType _$fieldName;'); |
715 } | 734 } |
716 // Write getters. | 735 // Write getters. |
717 for (idlModel.FieldDeclaration field in cls.fields) { | 736 for (idlModel.FieldDeclaration field in cls.allFields) { |
718 int index = field.id; | 737 int index = field.id; |
719 String fieldName = field.name; | 738 String fieldName = field.name; |
720 idlModel.FieldType type = field.type; | 739 idlModel.FieldType type = field.type; |
721 String typeName = type.typeName; | 740 String typeName = type.typeName; |
722 // Prepare "readCode" + "def" | 741 // Prepare "readCode" + "def" |
723 String readCode; | 742 String readCode; |
724 String def = defaultValue(type, false); | 743 String def = defaultValue(type, false); |
725 if (type.isList) { | 744 if (type.isList) { |
726 if (typeName == 'int') { | 745 if (typeName == 'int') { |
727 readCode = 'const fb.Uint32ListReader()'; | 746 readCode = 'const fb.Uint32ListReader()'; |
(...skipping 19 matching lines...) Expand all Loading... |
747 } else if (_idl.enums.containsKey(typeName)) { | 766 } else if (_idl.enums.containsKey(typeName)) { |
748 readCode = 'const _${typeName}Reader()'; | 767 readCode = 'const _${typeName}Reader()'; |
749 } else if (_idl.classes.containsKey(typeName)) { | 768 } else if (_idl.classes.containsKey(typeName)) { |
750 readCode = 'const _${typeName}Reader()'; | 769 readCode = 'const _${typeName}Reader()'; |
751 } | 770 } |
752 assert(readCode != null); | 771 assert(readCode != null); |
753 // Write the getter implementation. | 772 // Write the getter implementation. |
754 out(); | 773 out(); |
755 out('@override'); | 774 out('@override'); |
756 String returnType = dartType(type); | 775 String returnType = dartType(type); |
757 out('$returnType get $fieldName {'); | 776 if (field.isDeprecated) { |
758 indent(() { | 777 out('$returnType get $fieldName => $_throwDeprecated;'); |
759 String readExpr = '$readCode.vTableGet(_bp, $index, $def)'; | 778 } else { |
760 out('_$fieldName ??= $readExpr;'); | 779 out('$returnType get $fieldName {'); |
761 out('return _$fieldName;'); | 780 indent(() { |
762 }); | 781 String readExpr = '$readCode.vTableGet(_bp, $index, $def)'; |
763 out('}'); | 782 out('_$fieldName ??= $readExpr;'); |
| 783 out('return _$fieldName;'); |
| 784 }); |
| 785 out('}'); |
| 786 } |
764 } | 787 } |
765 }); | 788 }); |
766 out('}'); | 789 out('}'); |
767 } | 790 } |
768 | 791 |
769 void _generateMixin(idlModel.ClassDeclaration cls) { | 792 void _generateMixin(idlModel.ClassDeclaration cls) { |
770 String name = cls.name; | 793 String name = cls.name; |
771 String mixinName = '_${name}Mixin'; | 794 String mixinName = '_${name}Mixin'; |
772 out('abstract class $mixinName implements ${idlPrefix(name)} {'); | 795 out('abstract class $mixinName implements ${idlPrefix(name)} {'); |
773 indent(() { | 796 indent(() { |
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
868 return token.lexeme.split('\n').map((String line) { | 891 return token.lexeme.split('\n').map((String line) { |
869 if (line.startsWith(indent)) { | 892 if (line.startsWith(indent)) { |
870 line = line.substring(indent.length); | 893 line = line.substring(indent.length); |
871 } | 894 } |
872 return line; | 895 return line; |
873 }).join('\n'); | 896 }).join('\n'); |
874 } | 897 } |
875 return null; | 898 return null; |
876 } | 899 } |
877 } | 900 } |
OLD | NEW |