OLD | NEW |
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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 library codegen.protocol; | 5 library codegen.protocol; |
6 | 6 |
7 import 'dart:convert'; | 7 import 'dart:convert'; |
8 | 8 |
9 import 'package:html/dom.dart' as dom; | 9 import 'package:html/dom.dart' as dom; |
10 | 10 |
(...skipping 18 matching lines...) Expand all Loading... |
29 const Map<String, String> specialElementFlags = const { | 29 const Map<String, String> specialElementFlags = const { |
30 'abstract': '0x01', | 30 'abstract': '0x01', |
31 'const': '0x02', | 31 'const': '0x02', |
32 'final': '0x04', | 32 'final': '0x04', |
33 'static': '0x08', | 33 'static': '0x08', |
34 'private': '0x10', | 34 'private': '0x10', |
35 'deprecated': '0x20' | 35 'deprecated': '0x20' |
36 }; | 36 }; |
37 | 37 |
38 final GeneratedFile target = | 38 final GeneratedFile target = |
39 new GeneratedFile('../../lib/src/generated_protocol.dart', () { | 39 new GeneratedFile('../../lib/plugin/protocol/generated_protocol.dart', () { |
40 CodegenProtocolVisitor visitor = new CodegenProtocolVisitor(readApi()); | 40 CodegenProtocolVisitor visitor = new CodegenProtocolVisitor(readApi()); |
41 return visitor.collectCode(visitor.visitApi); | 41 return visitor.collectCode(visitor.visitApi); |
42 }); | 42 }); |
43 | 43 |
44 /** | 44 /** |
45 * Callback type used to represent arbitrary code generation. | 45 * Callback type used to represent arbitrary code generation. |
46 */ | 46 */ |
47 typedef void CodegenCallback(); | 47 typedef void CodegenCallback(); |
48 | 48 |
49 typedef String FromJsonSnippetCallback(String jsonPath, String json); | 49 typedef String FromJsonSnippetCallback(String jsonPath, String json); |
(...skipping 10 matching lines...) Expand all Loading... |
60 * the constructor will default the member to the empty list. | 60 * the constructor will default the member to the empty list. |
61 */ | 61 */ |
62 static const Map<String, List<String>> _optionalConstructorArguments = const { | 62 static const Map<String, List<String>> _optionalConstructorArguments = const { |
63 'AnalysisErrorFixes': const ['fixes'], | 63 'AnalysisErrorFixes': const ['fixes'], |
64 'SourceChange': const ['edits', 'linkedEditGroups'], | 64 'SourceChange': const ['edits', 'linkedEditGroups'], |
65 'SourceFileEdit': const ['edits'], | 65 'SourceFileEdit': const ['edits'], |
66 'TypeHierarchyItem': const ['interfaces', 'mixins', 'subclasses'], | 66 'TypeHierarchyItem': const ['interfaces', 'mixins', 'subclasses'], |
67 }; | 67 }; |
68 | 68 |
69 /** | 69 /** |
| 70 * The disclaimer added to the documentation comment for each of the classes |
| 71 * that are generated. |
| 72 */ |
| 73 static const String disclaimer = |
| 74 'Clients are not expected to subtype this class.'; |
| 75 |
| 76 /** |
70 * Visitor used to produce doc comments. | 77 * Visitor used to produce doc comments. |
71 */ | 78 */ |
72 final ToHtmlVisitor toHtmlVisitor; | 79 final ToHtmlVisitor toHtmlVisitor; |
73 | 80 |
74 /** | 81 /** |
75 * Types implied by the API. This includes types explicitly named in the | 82 * Types implied by the API. This includes types explicitly named in the |
76 * API as well as those implied by the definitions of requests, responses, | 83 * API as well as those implied by the definitions of requests, responses, |
77 * notifications, etc. | 84 * notifications, etc. |
78 */ | 85 */ |
79 final Map<String, ImpliedType> impliedTypes; | 86 final Map<String, ImpliedType> impliedTypes; |
(...skipping 13 matching lines...) Expand all Loading... |
93 TypeDecl resolvedType = resolveTypeReferenceChain(type); | 100 TypeDecl resolvedType = resolveTypeReferenceChain(type); |
94 if (resolvedType is TypeReference || | 101 if (resolvedType is TypeReference || |
95 resolvedType is TypeEnum || | 102 resolvedType is TypeEnum || |
96 resolvedType is TypeObject || | 103 resolvedType is TypeObject || |
97 resolvedType is TypeUnion) { | 104 resolvedType is TypeUnion) { |
98 return '$thisVar == $otherVar'; | 105 return '$thisVar == $otherVar'; |
99 } else if (resolvedType is TypeList) { | 106 } else if (resolvedType is TypeList) { |
100 String itemTypeName = dartType(resolvedType.itemType); | 107 String itemTypeName = dartType(resolvedType.itemType); |
101 String subComparison = compareEqualsCode(resolvedType.itemType, 'a', 'b'); | 108 String subComparison = compareEqualsCode(resolvedType.itemType, 'a', 'b'); |
102 String closure = '($itemTypeName a, $itemTypeName b) => $subComparison'; | 109 String closure = '($itemTypeName a, $itemTypeName b) => $subComparison'; |
103 return '_listEqual($thisVar, $otherVar, $closure)'; | 110 return 'listEqual($thisVar, $otherVar, $closure)'; |
104 } else if (resolvedType is TypeMap) { | 111 } else if (resolvedType is TypeMap) { |
105 String valueTypeName = dartType(resolvedType.valueType); | 112 String valueTypeName = dartType(resolvedType.valueType); |
106 String subComparison = | 113 String subComparison = |
107 compareEqualsCode(resolvedType.valueType, 'a', 'b'); | 114 compareEqualsCode(resolvedType.valueType, 'a', 'b'); |
108 String closure = '($valueTypeName a, $valueTypeName b) => $subComparison'; | 115 String closure = '($valueTypeName a, $valueTypeName b) => $subComparison'; |
109 return '_mapEqual($thisVar, $otherVar, $closure)'; | 116 return 'mapEqual($thisVar, $otherVar, $closure)'; |
110 } | 117 } |
111 throw new Exception( | 118 throw new Exception( |
112 "Don't know how to compare for equality: $resolvedType"); | 119 "Don't know how to compare for equality: $resolvedType"); |
113 } | 120 } |
114 | 121 |
115 /** | 122 /** |
116 * Translate each type implied by the API to a class. | 123 * Translate each type implied by the API to a class. |
117 */ | 124 */ |
118 void emitClasses() { | 125 void emitClasses() { |
119 for (ImpliedType impliedType in impliedTypes.values) { | 126 for (ImpliedType impliedType in impliedTypes.values) { |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
205 /** | 212 /** |
206 * Emit a class representing an data structure that doesn't exist in the | 213 * Emit a class representing an data structure that doesn't exist in the |
207 * protocol because it is empty (e.g. the "params" object for a request that | 214 * protocol because it is empty (e.g. the "params" object for a request that |
208 * doesn't have any parameters). | 215 * doesn't have any parameters). |
209 */ | 216 */ |
210 void emitEmptyObjectClass(String className, ImpliedType impliedType) { | 217 void emitEmptyObjectClass(String className, ImpliedType impliedType) { |
211 docComment(toHtmlVisitor.collectHtml(() { | 218 docComment(toHtmlVisitor.collectHtml(() { |
212 toHtmlVisitor.p(() { | 219 toHtmlVisitor.p(() { |
213 toHtmlVisitor.write(impliedType.humanReadableName); | 220 toHtmlVisitor.write(impliedType.humanReadableName); |
214 }); | 221 }); |
| 222 toHtmlVisitor.p(() { |
| 223 toHtmlVisitor.write(disclaimer); |
| 224 }); |
215 })); | 225 })); |
216 writeln('class $className {'); | 226 writeln('class $className {'); |
217 indent(() { | 227 indent(() { |
218 if (emitToRequestMember(impliedType)) { | 228 if (emitToRequestMember(impliedType)) { |
219 writeln(); | 229 writeln(); |
220 } | 230 } |
221 if (emitToResponseMember(impliedType)) { | 231 if (emitToResponseMember(impliedType)) { |
222 writeln(); | 232 writeln(); |
223 } | 233 } |
224 if (emitToNotificationMember(impliedType)) { | 234 if (emitToNotificationMember(impliedType)) { |
(...skipping 10 matching lines...) Expand all Loading... |
235 * Emit a class to encapsulate an enum. | 245 * Emit a class to encapsulate an enum. |
236 */ | 246 */ |
237 void emitEnumClass(String className, TypeEnum type, ImpliedType impliedType) { | 247 void emitEnumClass(String className, TypeEnum type, ImpliedType impliedType) { |
238 docComment(toHtmlVisitor.collectHtml(() { | 248 docComment(toHtmlVisitor.collectHtml(() { |
239 toHtmlVisitor.p(() { | 249 toHtmlVisitor.p(() { |
240 toHtmlVisitor.write(impliedType.humanReadableName); | 250 toHtmlVisitor.write(impliedType.humanReadableName); |
241 }); | 251 }); |
242 if (impliedType.type != null) { | 252 if (impliedType.type != null) { |
243 toHtmlVisitor.showType(null, impliedType.type); | 253 toHtmlVisitor.showType(null, impliedType.type); |
244 } | 254 } |
| 255 toHtmlVisitor.p(() { |
| 256 toHtmlVisitor.write(disclaimer); |
| 257 }); |
245 })); | 258 })); |
246 writeln('class $className implements Enum {'); | 259 writeln('class $className implements Enum {'); |
247 indent(() { | 260 indent(() { |
248 if (emitSpecialStaticMembers(className)) { | 261 if (emitSpecialStaticMembers(className)) { |
249 writeln(); | 262 writeln(); |
250 } | 263 } |
251 for (TypeEnumValue value in type.values) { | 264 for (TypeEnumValue value in type.values) { |
252 docComment(toHtmlVisitor.collectHtml(() { | 265 docComment(toHtmlVisitor.collectHtml(() { |
253 toHtmlVisitor.translateHtml(value.html); | 266 toHtmlVisitor.translateHtml(value.html); |
254 })); | 267 })); |
(...skipping 104 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
359 */ | 372 */ |
360 void emitObjectClass( | 373 void emitObjectClass( |
361 String className, TypeObject type, ImpliedType impliedType) { | 374 String className, TypeObject type, ImpliedType impliedType) { |
362 docComment(toHtmlVisitor.collectHtml(() { | 375 docComment(toHtmlVisitor.collectHtml(() { |
363 toHtmlVisitor.p(() { | 376 toHtmlVisitor.p(() { |
364 toHtmlVisitor.write(impliedType.humanReadableName); | 377 toHtmlVisitor.write(impliedType.humanReadableName); |
365 }); | 378 }); |
366 if (impliedType.type != null) { | 379 if (impliedType.type != null) { |
367 toHtmlVisitor.showType(null, impliedType.type); | 380 toHtmlVisitor.showType(null, impliedType.type); |
368 } | 381 } |
| 382 toHtmlVisitor.p(() { |
| 383 toHtmlVisitor.write(disclaimer); |
| 384 }); |
369 })); | 385 })); |
370 write('class $className'); | 386 write('class $className'); |
371 if (impliedType.kind == 'refactoringFeedback') { | 387 if (impliedType.kind == 'refactoringFeedback') { |
372 write(' extends RefactoringFeedback'); | 388 write(' extends RefactoringFeedback'); |
373 } | 389 } |
374 if (impliedType.kind == 'refactoringOptions') { | 390 if (impliedType.kind == 'refactoringOptions') { |
375 write(' extends RefactoringOptions'); | 391 write(' extends RefactoringOptions'); |
376 } | 392 } |
377 writeln(' implements HasToJson {'); | 393 writeln(' implements HasToJson {'); |
378 indent(() { | 394 indent(() { |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
546 * Emit the method for decoding an object from JSON. | 562 * Emit the method for decoding an object from JSON. |
547 */ | 563 */ |
548 void emitObjectFromJsonConstructor( | 564 void emitObjectFromJsonConstructor( |
549 String className, TypeObject type, ImpliedType impliedType) { | 565 String className, TypeObject type, ImpliedType impliedType) { |
550 String humanReadableNameString = | 566 String humanReadableNameString = |
551 literalString(impliedType.humanReadableName); | 567 literalString(impliedType.humanReadableName); |
552 if (className == 'RefactoringFeedback') { | 568 if (className == 'RefactoringFeedback') { |
553 writeln('factory RefactoringFeedback.fromJson(JsonDecoder jsonDecoder, ' | 569 writeln('factory RefactoringFeedback.fromJson(JsonDecoder jsonDecoder, ' |
554 'String jsonPath, Object json, Map responseJson) {'); | 570 'String jsonPath, Object json, Map responseJson) {'); |
555 indent(() { | 571 indent(() { |
556 writeln('return _refactoringFeedbackFromJson(jsonDecoder, jsonPath, ' | 572 writeln('return refactoringFeedbackFromJson(jsonDecoder, jsonPath, ' |
557 'json, responseJson);'); | 573 'json, responseJson);'); |
558 }); | 574 }); |
559 writeln('}'); | 575 writeln('}'); |
560 return; | 576 return; |
561 } | 577 } |
562 if (className == 'RefactoringOptions') { | 578 if (className == 'RefactoringOptions') { |
563 writeln('factory RefactoringOptions.fromJson(JsonDecoder jsonDecoder, ' | 579 writeln('factory RefactoringOptions.fromJson(JsonDecoder jsonDecoder, ' |
564 'String jsonPath, Object json, RefactoringKind kind) {'); | 580 'String jsonPath, Object json, RefactoringKind kind) {'); |
565 indent(() { | 581 indent(() { |
566 writeln('return _refactoringOptionsFromJson(jsonDecoder, jsonPath, ' | 582 writeln('return refactoringOptionsFromJson(jsonDecoder, jsonPath, ' |
567 'json, kind);'); | 583 'json, kind);'); |
568 }); | 584 }); |
569 writeln('}'); | 585 writeln('}'); |
570 return; | 586 return; |
571 } | 587 } |
572 writeln( | 588 writeln( |
573 'factory $className.fromJson(JsonDecoder jsonDecoder, String jsonPath, O
bject json) {'); | 589 'factory $className.fromJson(JsonDecoder jsonDecoder, String jsonPath, O
bject json) {'); |
574 indent(() { | 590 indent(() { |
575 writeln('if (json == null) {'); | 591 writeln('if (json == null) {'); |
576 indent(() { | 592 indent(() { |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
645 writeln('return ${className.hashCode};'); | 661 writeln('return ${className.hashCode};'); |
646 } else { | 662 } else { |
647 writeln('int hash = 0;'); | 663 writeln('int hash = 0;'); |
648 for (TypeObjectField field in type.fields) { | 664 for (TypeObjectField field in type.fields) { |
649 String valueToCombine; | 665 String valueToCombine; |
650 if (field.value != null) { | 666 if (field.value != null) { |
651 valueToCombine = field.value.hashCode.toString(); | 667 valueToCombine = field.value.hashCode.toString(); |
652 } else { | 668 } else { |
653 valueToCombine = '${field.name}.hashCode'; | 669 valueToCombine = '${field.name}.hashCode'; |
654 } | 670 } |
655 writeln('hash = _JenkinsSmiHash.combine(hash, $valueToCombine);'); | 671 writeln('hash = JenkinsSmiHash.combine(hash, $valueToCombine);'); |
656 } | 672 } |
657 writeln('return _JenkinsSmiHash.finish(hash);'); | 673 writeln('return JenkinsSmiHash.finish(hash);'); |
658 } | 674 } |
659 }); | 675 }); |
660 writeln('}'); | 676 writeln('}'); |
661 } | 677 } |
662 | 678 |
663 /** | 679 /** |
664 * If the class named [className] requires special constructors, emit them | 680 * If the class named [className] requires special constructors, emit them |
665 * and return true. | 681 * and return true. |
666 */ | 682 */ |
667 bool emitSpecialConstructors(String className) { | 683 bool emitSpecialConstructors(String className) { |
668 switch (className) { | 684 switch (className) { |
669 case 'LinkedEditGroup': | 685 case 'LinkedEditGroup': |
670 docComment([new dom.Text('Construct an empty LinkedEditGroup.')]); | 686 docComment([new dom.Text('Construct an empty LinkedEditGroup.')]); |
671 writeln( | 687 writeln( |
672 'LinkedEditGroup.empty() : this(<Position>[], 0, <LinkedEditSuggesti
on>[]);'); | 688 'LinkedEditGroup.empty() : this(<Position>[], 0, <LinkedEditSuggesti
on>[]);'); |
673 return true; | 689 return true; |
674 case 'RefactoringProblemSeverity': | 690 case 'RefactoringProblemSeverity': |
675 docComment([ | 691 docComment([ |
676 new dom.Text( | 692 new dom.Text( |
677 'Returns the [RefactoringProblemSeverity] with the maximal severit
y.') | 693 'Returns the [RefactoringProblemSeverity] with the maximal severit
y.') |
678 ]); | 694 ]); |
679 writeln( | 695 writeln( |
680 'static RefactoringProblemSeverity max(RefactoringProblemSeverity a,
RefactoringProblemSeverity b) =>'); | 696 'static RefactoringProblemSeverity max(RefactoringProblemSeverity a,
RefactoringProblemSeverity b) =>'); |
681 writeln(' _maxRefactoringProblemSeverity(a, b);'); | 697 writeln(' maxRefactoringProblemSeverity(a, b);'); |
682 return true; | 698 return true; |
683 default: | 699 default: |
684 return false; | 700 return false; |
685 } | 701 } |
686 } | 702 } |
687 | 703 |
688 /** | 704 /** |
689 * If the class named [className] requires special getters, emit them and | 705 * If the class named [className] requires special getters, emit them and |
690 * return true. | 706 * return true. |
691 */ | 707 */ |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
727 indent(() { | 743 indent(() { |
728 writeln('suggestions.add(suggestion);'); | 744 writeln('suggestions.add(suggestion);'); |
729 }); | 745 }); |
730 writeln('}'); | 746 writeln('}'); |
731 return true; | 747 return true; |
732 case 'SourceChange': | 748 case 'SourceChange': |
733 docComment([ | 749 docComment([ |
734 new dom.Text('Adds [edit] to the [FileEdit] for the given [file].') | 750 new dom.Text('Adds [edit] to the [FileEdit] for the given [file].') |
735 ]); | 751 ]); |
736 writeln('void addEdit(String file, int fileStamp, SourceEdit edit) =>'); | 752 writeln('void addEdit(String file, int fileStamp, SourceEdit edit) =>'); |
737 writeln(' _addEditToSourceChange(this, file, fileStamp, edit);'); | 753 writeln(' addEditToSourceChange(this, file, fileStamp, edit);'); |
738 writeln(); | 754 writeln(); |
739 docComment([new dom.Text('Adds the given [FileEdit].')]); | 755 docComment([new dom.Text('Adds the given [FileEdit].')]); |
740 writeln('void addFileEdit(SourceFileEdit edit) {'); | 756 writeln('void addFileEdit(SourceFileEdit edit) {'); |
741 indent(() { | 757 indent(() { |
742 writeln('edits.add(edit);'); | 758 writeln('edits.add(edit);'); |
743 }); | 759 }); |
744 writeln('}'); | 760 writeln('}'); |
745 writeln(); | 761 writeln(); |
746 docComment([new dom.Text('Adds the given [LinkedEditGroup].')]); | 762 docComment([new dom.Text('Adds the given [LinkedEditGroup].')]); |
747 writeln('void addLinkedEditGroup(LinkedEditGroup linkedEditGroup) {'); | 763 writeln('void addLinkedEditGroup(LinkedEditGroup linkedEditGroup) {'); |
748 indent(() { | 764 indent(() { |
749 writeln('linkedEditGroups.add(linkedEditGroup);'); | 765 writeln('linkedEditGroups.add(linkedEditGroup);'); |
750 }); | 766 }); |
751 writeln('}'); | 767 writeln('}'); |
752 writeln(); | 768 writeln(); |
753 docComment([ | 769 docComment([ |
754 new dom.Text( | 770 new dom.Text( |
755 'Returns the [FileEdit] for the given [file], maybe `null`.') | 771 'Returns the [FileEdit] for the given [file], maybe `null`.') |
756 ]); | 772 ]); |
757 writeln('SourceFileEdit getFileEdit(String file) =>'); | 773 writeln('SourceFileEdit getFileEdit(String file) =>'); |
758 writeln(' _getChangeFileEdit(this, file);'); | 774 writeln(' getChangeFileEdit(this, file);'); |
759 return true; | 775 return true; |
760 case 'SourceEdit': | 776 case 'SourceEdit': |
761 docComment([ | 777 docComment([ |
762 new dom.Text( | 778 new dom.Text( |
763 'Get the result of applying the edit to the given [code].') | 779 'Get the result of applying the edit to the given [code].') |
764 ]); | 780 ]); |
765 writeln('String apply(String code) => _applyEdit(code, this);'); | 781 writeln('String apply(String code) => applyEdit(code, this);'); |
766 return true; | 782 return true; |
767 case 'SourceFileEdit': | 783 case 'SourceFileEdit': |
768 docComment([new dom.Text('Adds the given [Edit] to the list.')]); | 784 docComment([new dom.Text('Adds the given [Edit] to the list.')]); |
769 writeln('void add(SourceEdit edit) => _addEditForSource(this, edit);'); | 785 writeln('void add(SourceEdit edit) => addEditForSource(this, edit);'); |
770 writeln(); | 786 writeln(); |
771 docComment([new dom.Text('Adds the given [Edit]s.')]); | 787 docComment([new dom.Text('Adds the given [Edit]s.')]); |
772 writeln('void addAll(Iterable<SourceEdit> edits) =>'); | 788 writeln('void addAll(Iterable<SourceEdit> edits) =>'); |
773 writeln(' _addAllEditsForSource(this, edits);'); | 789 writeln(' addAllEditsForSource(this, edits);'); |
774 return true; | 790 return true; |
775 default: | 791 default: |
776 return false; | 792 return false; |
777 } | 793 } |
778 } | 794 } |
779 | 795 |
780 /** | 796 /** |
781 * If the class named [className] requires special static members, emit them | 797 * If the class named [className] requires special static members, emit them |
782 * and return true. | 798 * and return true. |
783 */ | 799 */ |
(...skipping 21 matching lines...) Expand all Loading... |
805 writeln('}'); | 821 writeln('}'); |
806 return true; | 822 return true; |
807 case 'SourceEdit': | 823 case 'SourceEdit': |
808 docComment([ | 824 docComment([ |
809 new dom.Text('Get the result of applying a set of ' + | 825 new dom.Text('Get the result of applying a set of ' + |
810 '[edits] to the given [code]. Edits are applied in the order ' + | 826 '[edits] to the given [code]. Edits are applied in the order ' + |
811 'they appear in [edits].') | 827 'they appear in [edits].') |
812 ]); | 828 ]); |
813 writeln( | 829 writeln( |
814 'static String applySequence(String code, Iterable<SourceEdit> edits
) =>'); | 830 'static String applySequence(String code, Iterable<SourceEdit> edits
) =>'); |
815 writeln(' _applySequence(code, edits);'); | 831 writeln(' applySequenceOfEdits(code, edits);'); |
816 return true; | 832 return true; |
817 default: | 833 default: |
818 return false; | 834 return false; |
819 } | 835 } |
820 } | 836 } |
821 | 837 |
822 /** | 838 /** |
823 * Emit the toJson() code for an object class. | 839 * Emit the toJson() code for an object class. |
824 */ | 840 */ |
825 void emitToJsonMember(TypeObject type) { | 841 void emitToJsonMember(TypeObject type) { |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
922 } else { | 938 } else { |
923 return 'new $typeName.fromJson(jsonDecoder, $jsonPath, $json)'; | 939 return 'new $typeName.fromJson(jsonDecoder, $jsonPath, $json)'; |
924 } | 940 } |
925 }); | 941 }); |
926 } else { | 942 } else { |
927 return fromJsonCode(referencedType); | 943 return fromJsonCode(referencedType); |
928 } | 944 } |
929 } else { | 945 } else { |
930 switch (type.typeName) { | 946 switch (type.typeName) { |
931 case 'String': | 947 case 'String': |
932 return new FromJsonFunction('jsonDecoder._decodeString'); | 948 return new FromJsonFunction('jsonDecoder.decodeString'); |
933 case 'bool': | 949 case 'bool': |
934 return new FromJsonFunction('jsonDecoder._decodeBool'); | 950 return new FromJsonFunction('jsonDecoder.decodeBool'); |
935 case 'int': | 951 case 'int': |
936 case 'long': | 952 case 'long': |
937 return new FromJsonFunction('jsonDecoder._decodeInt'); | 953 return new FromJsonFunction('jsonDecoder.decodeInt'); |
938 case 'object': | 954 case 'object': |
939 return new FromJsonIdentity(); | 955 return new FromJsonIdentity(); |
940 default: | 956 default: |
941 throw new Exception('Unexpected type name ${type.typeName}'); | 957 throw new Exception('Unexpected type name ${type.typeName}'); |
942 } | 958 } |
943 } | 959 } |
944 } else if (type is TypeMap) { | 960 } else if (type is TypeMap) { |
945 FromJsonCode keyCode; | 961 FromJsonCode keyCode; |
946 if (dartType(type.keyType) != 'String') { | 962 if (dartType(type.keyType) != 'String') { |
947 keyCode = fromJsonCode(type.keyType); | 963 keyCode = fromJsonCode(type.keyType); |
948 } else { | 964 } else { |
949 keyCode = new FromJsonIdentity(); | 965 keyCode = new FromJsonIdentity(); |
950 } | 966 } |
951 FromJsonCode valueCode = fromJsonCode(type.valueType); | 967 FromJsonCode valueCode = fromJsonCode(type.valueType); |
952 if (keyCode.isIdentity && valueCode.isIdentity) { | 968 if (keyCode.isIdentity && valueCode.isIdentity) { |
953 return new FromJsonFunction('jsonDecoder._decodeMap'); | 969 return new FromJsonFunction('jsonDecoder.decodeMap'); |
954 } else { | 970 } else { |
955 return new FromJsonSnippet((String jsonPath, String json) { | 971 return new FromJsonSnippet((String jsonPath, String json) { |
956 StringBuffer result = new StringBuffer(); | 972 StringBuffer result = new StringBuffer(); |
957 result.write('jsonDecoder._decodeMap($jsonPath, $json'); | 973 result.write('jsonDecoder.decodeMap($jsonPath, $json'); |
958 if (!keyCode.isIdentity) { | 974 if (!keyCode.isIdentity) { |
959 result.write(', keyDecoder: ${keyCode.asClosure}'); | 975 result.write(', keyDecoder: ${keyCode.asClosure}'); |
960 } | 976 } |
961 if (!valueCode.isIdentity) { | 977 if (!valueCode.isIdentity) { |
962 result.write(', valueDecoder: ${valueCode.asClosure}'); | 978 result.write(', valueDecoder: ${valueCode.asClosure}'); |
963 } | 979 } |
964 result.write(')'); | 980 result.write(')'); |
965 return result.toString(); | 981 return result.toString(); |
966 }); | 982 }); |
967 } | 983 } |
968 } else if (type is TypeList) { | 984 } else if (type is TypeList) { |
969 FromJsonCode itemCode = fromJsonCode(type.itemType); | 985 FromJsonCode itemCode = fromJsonCode(type.itemType); |
970 if (itemCode.isIdentity) { | 986 if (itemCode.isIdentity) { |
971 return new FromJsonFunction('jsonDecoder._decodeList'); | 987 return new FromJsonFunction('jsonDecoder.decodeList'); |
972 } else { | 988 } else { |
973 return new FromJsonSnippet((String jsonPath, String json) => | 989 return new FromJsonSnippet((String jsonPath, String json) => |
974 'jsonDecoder._decodeList($jsonPath, $json, ${itemCode.asClosure})'); | 990 'jsonDecoder.decodeList($jsonPath, $json, ${itemCode.asClosure})'); |
975 } | 991 } |
976 } else if (type is TypeUnion) { | 992 } else if (type is TypeUnion) { |
977 List<String> decoders = <String>[]; | 993 List<String> decoders = <String>[]; |
978 for (TypeDecl choice in type.choices) { | 994 for (TypeDecl choice in type.choices) { |
979 TypeDecl resolvedChoice = resolveTypeReferenceChain(choice); | 995 TypeDecl resolvedChoice = resolveTypeReferenceChain(choice); |
980 if (resolvedChoice is TypeObject) { | 996 if (resolvedChoice is TypeObject) { |
981 TypeObjectField field = resolvedChoice.getField(type.field); | 997 TypeObjectField field = resolvedChoice.getField(type.field); |
982 if (field == null) { | 998 if (field == null) { |
983 throw new Exception( | 999 throw new Exception( |
984 'Each choice in the union needs a field named ${type.field}'); | 1000 'Each choice in the union needs a field named ${type.field}'); |
985 } | 1001 } |
986 if (field.value == null) { | 1002 if (field.value == null) { |
987 throw new Exception( | 1003 throw new Exception( |
988 'Each choice in the union needs a constant value for the field $
{type.field}'); | 1004 'Each choice in the union needs a constant value for the field $
{type.field}'); |
989 } | 1005 } |
990 String closure = fromJsonCode(choice).asClosure; | 1006 String closure = fromJsonCode(choice).asClosure; |
991 decoders.add('${literalString(field.value)}: $closure'); | 1007 decoders.add('${literalString(field.value)}: $closure'); |
992 } else { | 1008 } else { |
993 throw new Exception('Union types must be unions of objects.'); | 1009 throw new Exception('Union types must be unions of objects.'); |
994 } | 1010 } |
995 } | 1011 } |
996 return new FromJsonSnippet((String jsonPath, String json) => | 1012 return new FromJsonSnippet((String jsonPath, String json) => |
997 'jsonDecoder._decodeUnion($jsonPath, $json, ${literalString(type.field
)}, {${decoders.join(', ')}})'); | 1013 'jsonDecoder.decodeUnion($jsonPath, $json, ${literalString(type.field)
}, {${decoders.join(', ')}})'); |
998 } else { | 1014 } else { |
999 throw new Exception("Can't convert $type from JSON"); | 1015 throw new Exception("Can't convert $type from JSON"); |
1000 } | 1016 } |
1001 } | 1017 } |
1002 | 1018 |
1003 /** | 1019 /** |
1004 * True if the constructor argument for the given field should be optional. | 1020 * True if the constructor argument for the given field should be optional. |
1005 */ | 1021 */ |
1006 bool isOptionalConstructorArg(String className, TypeObjectField field) { | 1022 bool isOptionalConstructorArg(String className, TypeObjectField field) { |
1007 if (field.optional) { | 1023 if (field.optional) { |
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1073 dartType(type), (String value) => '$value.toJson()'); | 1089 dartType(type), (String value) => '$value.toJson()'); |
1074 } else { | 1090 } else { |
1075 throw new Exception("Can't convert $resolvedType from JSON"); | 1091 throw new Exception("Can't convert $resolvedType from JSON"); |
1076 } | 1092 } |
1077 } | 1093 } |
1078 | 1094 |
1079 @override | 1095 @override |
1080 visitApi() { | 1096 visitApi() { |
1081 outputHeader(); | 1097 outputHeader(); |
1082 writeln(); | 1098 writeln(); |
1083 writeln('part of protocol;'); | 1099 writeln('part of analysis_server.plugin.protocol.protocol;'); |
| 1100 writeln(); |
1084 emitClasses(); | 1101 emitClasses(); |
1085 } | 1102 } |
1086 } | 1103 } |
1087 | 1104 |
1088 /** | 1105 /** |
1089 * Container for code that can be used to translate a data type from JSON. | 1106 * Container for code that can be used to translate a data type from JSON. |
1090 */ | 1107 */ |
1091 abstract class FromJsonCode { | 1108 abstract class FromJsonCode { |
1092 /** | 1109 /** |
1093 * Get the translation code in the form of a closure. | 1110 * Get the translation code in the form of a closure. |
(...skipping 129 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1223 | 1240 |
1224 @override | 1241 @override |
1225 String get asClosure => '($type value) => ${callback('value')}'; | 1242 String get asClosure => '($type value) => ${callback('value')}'; |
1226 | 1243 |
1227 @override | 1244 @override |
1228 bool get isIdentity => false; | 1245 bool get isIdentity => false; |
1229 | 1246 |
1230 @override | 1247 @override |
1231 String asSnippet(String value) => callback(value); | 1248 String asSnippet(String value) => callback(value); |
1232 } | 1249 } |
OLD | NEW |