| 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 'api.dart'; | 9 import 'api.dart'; |
| 10 import 'codegen_tools.dart'; | 10 import 'codegen_tools.dart'; |
| (...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 219 | 219 |
| 220 CodegenProtocolVisitor(Api api) | 220 CodegenProtocolVisitor(Api api) |
| 221 : super(api), | 221 : super(api), |
| 222 toHtmlVisitor = new ToHtmlVisitor(api), | 222 toHtmlVisitor = new ToHtmlVisitor(api), |
| 223 impliedTypes = computeImpliedTypes(api); | 223 impliedTypes = computeImpliedTypes(api); |
| 224 | 224 |
| 225 @override | 225 @override |
| 226 visitApi() { | 226 visitApi() { |
| 227 outputHeader(); | 227 outputHeader(); |
| 228 writeln(); | 228 writeln(); |
| 229 writeln('part of protocol2;'); | 229 writeln('part of protocol;'); |
| 230 emitClasses(); | 230 emitClasses(); |
| 231 } | 231 } |
| 232 | 232 |
| 233 /** | 233 /** |
| 234 * Translate each type implied by the API to a class. | 234 * Translate each type implied by the API to a class. |
| 235 */ | 235 */ |
| 236 void emitClasses() { | 236 void emitClasses() { |
| 237 for (ImpliedType impliedType in impliedTypes.values) { | 237 for (ImpliedType impliedType in impliedTypes.values) { |
| 238 TypeDecl type = impliedType.type; | 238 TypeDecl type = impliedType.type; |
| 239 if (type != null) { | 239 String dartTypeName = capitalize(impliedType.camelName); |
| 240 String dartTypeName = capitalize(impliedType.camelName); | 240 if (type == null) { |
| 241 if (type is TypeObject) { | 241 emitEmptyObjectClass(dartTypeName, impliedType); |
| 242 writeln(); | 242 } else if (type is TypeObject || type == null) { |
| 243 emitObjectClass(dartTypeName, type, impliedType); | 243 writeln(); |
| 244 } else if (type is TypeEnum) { | 244 emitObjectClass(dartTypeName, type, impliedType); |
| 245 writeln(); | 245 } else if (type is TypeEnum) { |
| 246 emitEnumClass(dartTypeName, type, impliedType); | 246 writeln(); |
| 247 } | 247 emitEnumClass(dartTypeName, type, impliedType); |
| 248 } | 248 } |
| 249 } | 249 } |
| 250 } | 250 } |
| 251 | 251 |
| 252 /** | 252 /** |
| 253 * Emit a class representing an data structure that doesn't exist in the |
| 254 * protocol because it is empty (e.g. the "params" object for a request that |
| 255 * doesn't have any parameters). |
| 256 */ |
| 257 void emitEmptyObjectClass(String className, ImpliedType impliedType) { |
| 258 docComment(toHtmlVisitor.collectHtml(() { |
| 259 toHtmlVisitor.p(() { |
| 260 toHtmlVisitor.write(impliedType.humanReadableName); |
| 261 }); |
| 262 })); |
| 263 writeln('class $className {'); |
| 264 indent(() { |
| 265 if (emitToRequestMember(impliedType)) { |
| 266 writeln(); |
| 267 } |
| 268 if (emitToResponseMember(impliedType)) { |
| 269 writeln(); |
| 270 } |
| 271 if (emitToNotificationMember(impliedType)) { |
| 272 writeln(); |
| 273 } |
| 274 emitObjectEqualsMember(null, className); |
| 275 writeln(); |
| 276 emitObjectHashCode(null, className); |
| 277 }); |
| 278 writeln('}'); |
| 279 } |
| 280 |
| 281 /** |
| 253 * Emit the class to encapsulate an object type. | 282 * Emit the class to encapsulate an object type. |
| 254 */ | 283 */ |
| 255 void emitObjectClass(String className, TypeObject type, | 284 void emitObjectClass(String className, TypeObject type, |
| 256 ImpliedType impliedType) { | 285 ImpliedType impliedType) { |
| 257 docComment(toHtmlVisitor.collectHtml(() { | 286 docComment(toHtmlVisitor.collectHtml(() { |
| 258 toHtmlVisitor.p(() { | 287 toHtmlVisitor.p(() { |
| 259 toHtmlVisitor.write(impliedType.humanReadableName); | 288 toHtmlVisitor.write(impliedType.humanReadableName); |
| 260 }); | 289 }); |
| 261 if (impliedType.type != null) { | 290 if (impliedType.type != null) { |
| 262 toHtmlVisitor.showType(null, impliedType.type); | 291 toHtmlVisitor.showType(null, impliedType.type); |
| 263 } | 292 } |
| 264 })); | 293 })); |
| 265 writeln('class $className implements HasToJson {'); | 294 writeln('class $className {'); |
| 266 indent(() { | 295 indent(() { |
| 267 if (emitSpecialStaticMembers(className)) { | 296 if (emitSpecialStaticMembers(className)) { |
| 268 writeln(); | 297 writeln(); |
| 269 } | 298 } |
| 270 for (TypeObjectField field in type.fields) { | 299 for (TypeObjectField field in type.fields) { |
| 271 if (field.value != null) { | 300 if (field.value != null) { |
| 272 continue; | 301 continue; |
| 273 } | 302 } |
| 274 docComment(toHtmlVisitor.collectHtml(() { | 303 docComment(toHtmlVisitor.collectHtml(() { |
| 275 toHtmlVisitor.translateHtml(field.html); | 304 toHtmlVisitor.translateHtml(field.html); |
| (...skipping 26 matching lines...) Expand all Loading... |
| 302 writeln(); | 331 writeln(); |
| 303 } | 332 } |
| 304 if (emitSpecialMethods(className)) { | 333 if (emitSpecialMethods(className)) { |
| 305 writeln(); | 334 writeln(); |
| 306 } | 335 } |
| 307 writeln('@override'); | 336 writeln('@override'); |
| 308 writeln('String toString() => JSON.encode(toJson());'); | 337 writeln('String toString() => JSON.encode(toJson());'); |
| 309 writeln(); | 338 writeln(); |
| 310 emitObjectEqualsMember(type, className); | 339 emitObjectEqualsMember(type, className); |
| 311 writeln(); | 340 writeln(); |
| 312 emitObjectHashCode(type); | 341 emitObjectHashCode(type, className); |
| 313 }); | 342 }); |
| 314 writeln('}'); | 343 writeln('}'); |
| 315 } | 344 } |
| 316 | 345 |
| 317 /** | 346 /** |
| 318 * If the class named [className] requires special static members, emit them | 347 * If the class named [className] requires special static members, emit them |
| 319 * and return true. | 348 * and return true. |
| 320 */ | 349 */ |
| 321 bool emitSpecialStaticMembers(String className) { | 350 bool emitSpecialStaticMembers(String className) { |
| 322 switch (className) { | 351 switch (className) { |
| (...skipping 338 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 661 /** | 690 /** |
| 662 * Emit the toRequest() code for a class, if appropriate. Returns true if | 691 * Emit the toRequest() code for a class, if appropriate. Returns true if |
| 663 * code was emitted. | 692 * code was emitted. |
| 664 */ | 693 */ |
| 665 bool emitToRequestMember(ImpliedType impliedType) { | 694 bool emitToRequestMember(ImpliedType impliedType) { |
| 666 if (impliedType.kind == 'requestParams') { | 695 if (impliedType.kind == 'requestParams') { |
| 667 writeln('Request toRequest(String id) {'); | 696 writeln('Request toRequest(String id) {'); |
| 668 indent(() { | 697 indent(() { |
| 669 String methodString = | 698 String methodString = |
| 670 literalString((impliedType.apiNode as Request).longMethod); | 699 literalString((impliedType.apiNode as Request).longMethod); |
| 671 writeln('return new Request(id, $methodString, toJson());'); | 700 String jsonPart = impliedType.type != null ? 'toJson()' : 'null'; |
| 701 writeln('return new Request(id, $methodString, $jsonPart);'); |
| 672 }); | 702 }); |
| 673 writeln('}'); | 703 writeln('}'); |
| 674 return true; | 704 return true; |
| 675 } | 705 } |
| 676 return false; | 706 return false; |
| 677 } | 707 } |
| 678 | 708 |
| 679 /** | 709 /** |
| 680 * Emit the toResponse() code for a class, if appropriate. Returns true if | 710 * Emit the toResponse() code for a class, if appropriate. Returns true if |
| 681 * code was emitted. | 711 * code was emitted. |
| 682 */ | 712 */ |
| 683 bool emitToResponseMember(ImpliedType impliedType) { | 713 bool emitToResponseMember(ImpliedType impliedType) { |
| 684 if (impliedType.kind == 'requestResult') { | 714 if (impliedType.kind == 'requestResult') { |
| 685 writeln('Response toResponse(String id) {'); | 715 writeln('Response toResponse(String id) {'); |
| 686 indent(() { | 716 indent(() { |
| 687 writeln('return new Response(id, result: toJson());'); | 717 String jsonPart = impliedType.type != null ? 'toJson()' : 'null'; |
| 718 writeln('return new Response(id, result: $jsonPart);'); |
| 688 }); | 719 }); |
| 689 writeln('}'); | 720 writeln('}'); |
| 690 return true; | 721 return true; |
| 691 } | 722 } |
| 692 return false; | 723 return false; |
| 693 } | 724 } |
| 694 | 725 |
| 695 /** | 726 /** |
| 696 * Emit the toNotification() code for a class, if appropriate. Returns true | 727 * Emit the toNotification() code for a class, if appropriate. Returns true |
| 697 * if code was emitted. | 728 * if code was emitted. |
| 698 */ | 729 */ |
| 699 bool emitToNotificationMember(ImpliedType impliedType) { | 730 bool emitToNotificationMember(ImpliedType impliedType) { |
| 700 if (impliedType.kind == 'notificationParams') { | 731 if (impliedType.kind == 'notificationParams') { |
| 701 writeln('Notification toNotification() {'); | 732 writeln('Notification toNotification() {'); |
| 702 indent(() { | 733 indent(() { |
| 703 String eventString = | 734 String eventString = |
| 704 literalString((impliedType.apiNode as Notification).longEvent); | 735 literalString((impliedType.apiNode as Notification).longEvent); |
| 705 writeln('return new Notification($eventString, toJson());'); | 736 String jsonPart = impliedType.type != null ? 'toJson()' : 'null'; |
| 737 writeln('return new Notification($eventString, $jsonPart);'); |
| 706 }); | 738 }); |
| 707 writeln('}'); | 739 writeln('}'); |
| 708 return true; | 740 return true; |
| 709 } | 741 } |
| 710 return false; | 742 return false; |
| 711 } | 743 } |
| 712 | 744 |
| 713 /** | 745 /** |
| 714 * Emit the operator== code for an object class. | 746 * Emit the operator== code for an object class. |
| 715 */ | 747 */ |
| 716 void emitObjectEqualsMember(TypeObject type, String className) { | 748 void emitObjectEqualsMember(TypeObject type, String className) { |
| 717 writeln('@override'); | 749 writeln('@override'); |
| 718 writeln('bool operator==(other) {'); | 750 writeln('bool operator==(other) {'); |
| 719 indent(() { | 751 indent(() { |
| 720 writeln('if (other is $className) {'); | 752 writeln('if (other is $className) {'); |
| 721 indent(() { | 753 indent(() { |
| 722 var comparisons = <String>[]; | 754 var comparisons = <String>[]; |
| 723 for (TypeObjectField field in type.fields) { | 755 if (type != null) { |
| 724 if (field.value != null) { | 756 for (TypeObjectField field in type.fields) { |
| 725 continue; | 757 if (field.value != null) { |
| 758 continue; |
| 759 } |
| 760 comparisons.add( |
| 761 compareEqualsCode(field.type, field.name, 'other.${field.name}')
); |
| 726 } | 762 } |
| 727 comparisons.add( | |
| 728 compareEqualsCode(field.type, field.name, 'other.${field.name}')); | |
| 729 } | 763 } |
| 730 if (comparisons.isEmpty) { | 764 if (comparisons.isEmpty) { |
| 731 writeln('return true;'); | 765 writeln('return true;'); |
| 732 } else { | 766 } else { |
| 733 String concatenated = comparisons.join(' &&\n '); | 767 String concatenated = comparisons.join(' &&\n '); |
| 734 writeln('return $concatenated;'); | 768 writeln('return $concatenated;'); |
| 735 } | 769 } |
| 736 }); | 770 }); |
| 737 writeln('}'); | 771 writeln('}'); |
| 738 writeln('return false;'); | 772 writeln('return false;'); |
| 739 }); | 773 }); |
| 740 writeln('}'); | 774 writeln('}'); |
| 741 } | 775 } |
| 742 | 776 |
| 743 /** | 777 /** |
| 744 * Emit the hashCode getter for an object class. | 778 * Emit the hashCode getter for an object class. |
| 745 */ | 779 */ |
| 746 void emitObjectHashCode(TypeObject type) { | 780 void emitObjectHashCode(TypeObject type, String className) { |
| 747 writeln('@override'); | 781 writeln('@override'); |
| 748 writeln('int get hashCode {'); | 782 writeln('int get hashCode {'); |
| 749 indent(() { | 783 indent(() { |
| 750 writeln('int hash = 0;'); | 784 if (type == null) { |
| 751 for (TypeObjectField field in type.fields) { | 785 writeln('return ${className.hashCode};'); |
| 752 String valueToCombine; | 786 } else { |
| 753 if (field.value != null) { | 787 writeln('int hash = 0;'); |
| 754 valueToCombine = field.value.hashCode.toString(); | 788 for (TypeObjectField field in type.fields) { |
| 755 } else { | 789 String valueToCombine; |
| 756 valueToCombine = '${field.name}.hashCode'; | 790 if (field.value != null) { |
| 791 valueToCombine = field.value.hashCode.toString(); |
| 792 } else { |
| 793 valueToCombine = '${field.name}.hashCode'; |
| 794 } |
| 795 writeln('hash = _JenkinsSmiHash.combine(hash, $valueToCombine);'); |
| 757 } | 796 } |
| 758 writeln('hash = _JenkinsSmiHash.combine(hash, $valueToCombine);'); | 797 writeln('return _JenkinsSmiHash.finish(hash);'); |
| 759 } | 798 } |
| 760 writeln('return _JenkinsSmiHash.finish(hash);'); | |
| 761 }); | 799 }); |
| 762 writeln('}'); | 800 writeln('}'); |
| 763 } | 801 } |
| 764 | 802 |
| 765 /** | 803 /** |
| 766 * Emit a class to encapsulate an enum. | 804 * Emit a class to encapsulate an enum. |
| 767 */ | 805 */ |
| 768 void emitEnumClass(String className, TypeEnum type, ImpliedType impliedType) { | 806 void emitEnumClass(String className, TypeEnum type, ImpliedType impliedType) { |
| 769 docComment(toHtmlVisitor.collectHtml(() { | 807 docComment(toHtmlVisitor.collectHtml(() { |
| 770 toHtmlVisitor.p(() { | 808 toHtmlVisitor.p(() { |
| (...skipping 359 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1130 // Constructor call to create the JsonDecoder object. | 1168 // Constructor call to create the JsonDecoder object. |
| 1131 String makeDecoder; | 1169 String makeDecoder; |
| 1132 // Name of the constructor to create. | 1170 // Name of the constructor to create. |
| 1133 String constructorName; | 1171 String constructorName; |
| 1134 // Extra arguments for the constructor. | 1172 // Extra arguments for the constructor. |
| 1135 List<String> extraArgs = <String>[]; | 1173 List<String> extraArgs = <String>[]; |
| 1136 switch (impliedType.kind) { | 1174 switch (impliedType.kind) { |
| 1137 case 'requestParams': | 1175 case 'requestParams': |
| 1138 inputType = 'Request'; | 1176 inputType = 'Request'; |
| 1139 inputName = 'request'; | 1177 inputName = 'request'; |
| 1140 fieldName = 'params'; | 1178 fieldName = '_params'; |
| 1141 makeDecoder = 'new RequestDecoder(request)'; | 1179 makeDecoder = 'new RequestDecoder(request)'; |
| 1142 constructorName = 'fromRequest'; | 1180 constructorName = 'fromRequest'; |
| 1143 break; | 1181 break; |
| 1144 case 'requestResult': | 1182 case 'requestResult': |
| 1145 inputType = 'Response'; | 1183 inputType = 'Response'; |
| 1146 inputName = 'response'; | 1184 inputName = 'response'; |
| 1147 fieldName = 'result'; | 1185 fieldName = '_result'; |
| 1148 makeDecoder = 'new ResponseDecoder()'; | 1186 makeDecoder = 'new ResponseDecoder()'; |
| 1149 constructorName = 'fromResponse'; | 1187 constructorName = 'fromResponse'; |
| 1150 break; | 1188 break; |
| 1151 case 'notificationParams': | 1189 case 'notificationParams': |
| 1152 inputType = 'Notification'; | 1190 inputType = 'Notification'; |
| 1153 inputName = 'notification'; | 1191 inputName = 'notification'; |
| 1154 fieldName = 'params'; | 1192 fieldName = '_params'; |
| 1155 makeDecoder = 'new ResponseDecoder()'; | 1193 makeDecoder = 'new ResponseDecoder()'; |
| 1156 constructorName = 'fromNotification'; | 1194 constructorName = 'fromNotification'; |
| 1157 break; | 1195 break; |
| 1158 case 'refactoringFeedback': | 1196 case 'refactoringFeedback': |
| 1159 inputType = 'EditGetRefactoringResult'; | 1197 inputType = 'EditGetRefactoringResult'; |
| 1160 inputName = 'refactoringResult'; | 1198 inputName = 'refactoringResult'; |
| 1161 fieldName = 'feedback'; | 1199 fieldName = 'feedback'; |
| 1162 makeDecoder = 'new ResponseDecoder()'; | 1200 makeDecoder = 'new ResponseDecoder()'; |
| 1163 constructorName = 'fromRefactoringResult'; | 1201 constructorName = 'fromRefactoringResult'; |
| 1164 break; | 1202 break; |
| 1165 case 'refactoringOptions': | 1203 case 'refactoringOptions': |
| 1166 inputType = 'EditGetRefactoringParams'; | 1204 inputType = 'EditGetRefactoringParams'; |
| 1167 inputName = 'refactoringParams'; | 1205 inputName = 'refactoringParams'; |
| 1168 fieldName = 'options'; | 1206 fieldName = 'options'; |
| 1169 makeDecoder = 'new RequestDecoder(request)'; | 1207 makeDecoder = 'new RequestDecoder(request)'; |
| 1170 constructorName = 'fromRefactoringParams'; | 1208 constructorName = 'fromRefactoringParams'; |
| 1171 extraArgs.add('Request request'); | 1209 extraArgs.add('Request request'); |
| 1172 break; | 1210 break; |
| 1173 default: | 1211 default: |
| 1174 return false; | 1212 return false; |
| 1175 } | 1213 } |
| 1176 List<String> args = ['$inputType $inputName']; | 1214 List<String> args = ['$inputType $inputName']; |
| 1177 args.addAll(extraArgs); | 1215 args.addAll(extraArgs); |
| 1178 writeln('factory $className.$constructorName(${args.join(', ')}) {'); | 1216 writeln('factory $className.$constructorName(${args.join(', ')}) {'); |
| 1179 indent(() { | 1217 indent(() { |
| 1180 String fieldNameString = literalString(fieldName); | 1218 String fieldNameString = |
| 1219 literalString(fieldName.replaceFirst(new RegExp('^_'), '')); |
| 1181 writeln('return new $className.fromJson('); | 1220 writeln('return new $className.fromJson('); |
| 1182 writeln(' $makeDecoder, $fieldNameString, $inputName.$fieldName);'); | 1221 writeln(' $makeDecoder, $fieldNameString, $inputName.$fieldName);'); |
| 1183 }); | 1222 }); |
| 1184 writeln('}'); | 1223 writeln('}'); |
| 1185 return true; | 1224 return true; |
| 1186 } | 1225 } |
| 1187 | 1226 |
| 1188 /** | 1227 /** |
| 1189 * Create a string literal that evaluates to [s]. | 1228 * Create a string literal that evaluates to [s]. |
| 1190 */ | 1229 */ |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1227 CodegenProtocolVisitor visitor = new CodegenProtocolVisitor(readApi()); | 1266 CodegenProtocolVisitor visitor = new CodegenProtocolVisitor(readApi()); |
| 1228 return visitor.collectCode(visitor.visitApi); | 1267 return visitor.collectCode(visitor.visitApi); |
| 1229 }); | 1268 }); |
| 1230 | 1269 |
| 1231 /** | 1270 /** |
| 1232 * Translate spec_input.html into protocol_matchers.dart. | 1271 * Translate spec_input.html into protocol_matchers.dart. |
| 1233 */ | 1272 */ |
| 1234 main() { | 1273 main() { |
| 1235 target.generate(); | 1274 target.generate(); |
| 1236 } | 1275 } |
| OLD | NEW |