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

Side by Side Diff: pkg/analysis_server/tool/spec/codegen_dart_protocol.dart

Issue 479043002: Code generate Dart classes representing the analysis server API. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Remove accidental comment change Created 6 years, 4 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 | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library codegen.protocol;
6
7 import 'dart:convert';
8
9 import 'api.dart';
10 import 'codegen_tools.dart';
11 import 'from_html.dart';
12 import 'implied_types.dart';
13 import 'to_html.dart';
14
15 /**
16 * Container for code that can be used to translate a data type from JSON.
17 */
18 abstract class FromJsonCode {
19 /**
20 * True if the data type is already in JSON form, so the translation is the
21 * identity function.
22 */
23 bool get isIdentity;
24
25 /**
26 * Get the translation code in the form of a closure.
27 */
28 String get asClosure;
29
30 /**
31 * Get the translation code in the form of a code snippet, where [jsonPath]
32 * is the variable holding the JSON path, and [json] is the variable holding
33 * the raw JSON.
34 */
35 String asSnippet(String jsonPath, String json);
36 }
37
38 /**
39 * Representation of FromJsonCode for a function defined elsewhere.
40 */
41 class FromJsonFunction extends FromJsonCode {
42 final String asClosure;
43
44 FromJsonFunction(this.asClosure);
45
46 @override
47 bool get isIdentity => false;
48
49 @override
50 String asSnippet(String jsonPath, String json) =>
51 '$asClosure($jsonPath, $json)';
52 }
53
54 typedef String FromJsonSnippetCallback(String jsonPath, String json);
55
56 /**
57 * Representation of FromJsonCode for a snippet of inline code.
58 */
59 class FromJsonSnippet extends FromJsonCode {
60 /**
61 * Callback that can be used to generate the code snippet, once the names
62 * of the [jsonPath] and [json] variables are known.
63 */
64 final FromJsonSnippetCallback callback;
65
66 FromJsonSnippet(this.callback);
67
68 @override
69 bool get isIdentity => false;
70
71 @override
72 String get asClosure =>
73 '(String jsonPath, Object json) => ${callback('jsonPath', 'json')}';
74
75 @override
76 String asSnippet(String jsonPath, String json) => callback(jsonPath, json);
77 }
78
79 /**
80 * Representation of FromJsonCode for the identity transformation.
81 */
82 class FromJsonIdentity extends FromJsonSnippet {
83 FromJsonIdentity() : super((String jsonPath, String json) => json);
84
85 @override
86 bool get isIdentity => true;
87 }
88
89 /**
90 * Container for code that can be used to translate a data type to JSON.
91 */
92 abstract class ToJsonCode {
93 /**
94 * True if the data type is already in JSON form, so the translation is the
95 * identity function.
96 */
97 bool get isIdentity;
98
99 /**
100 * Get the translation code in the form of a closure.
101 */
102 String get asClosure;
103
104 /**
105 * Get the translation code in the form of a code snippet, where [value]
106 * is the variable holding the object to be translated.
107 */
108 String asSnippet(String value);
109 }
110
111 /**
112 * Representation of ToJsonCode for a function defined elsewhere.
113 */
114 class ToJsonFunction extends ToJsonCode {
115 final String asClosure;
116
117 ToJsonFunction(this.asClosure);
118
119 @override
120 bool get isIdentity => false;
121
122 @override
123 String asSnippet(String value) => '$asClosure($value)';
124 }
125
126 typedef String ToJsonSnippetCallback(String value);
127
128 /**
129 * Representation of ToJsonCode for a snippet of inline code.
130 */
131 class ToJsonSnippet extends ToJsonCode {
132 /**
133 * Callback that can be used to generate the code snippet, once the name
134 * of the [value] variable is known.
135 */
136 final ToJsonSnippetCallback callback;
137
138 /**
139 * Dart type of the [value] variable.
140 */
141 final String type;
142
143 ToJsonSnippet(this.type, this.callback);
144
145 @override
146 bool get isIdentity => false;
147
148 @override
149 String get asClosure => '($type value) => ${callback('value')}';
150
151 @override
152 String asSnippet(String value) => callback(value);
153 }
154
155 /**
156 * Representation of FromJsonCode for the identity transformation.
157 */
158 class ToJsonIdentity extends ToJsonSnippet {
159 ToJsonIdentity(String type) : super(type, (String value) => value);
160
161 @override
162 bool get isIdentity => true;
163 }
164
165 /**
166 * Visitor which produces Dart code representing the API.
167 */
168 class CodegenProtocolVisitor extends HierarchicalApiVisitor with CodeGenerator {
169 /**
170 * Type references in the spec that are named something else in Dart.
171 */
172 static const Map<String, String> _typeRenames = const {
173 'object': 'Object',
174 };
175
176 /**
177 * Visitor used to produce doc comments.
178 */
179 final ToHtmlVisitor toHtmlVisitor;
180
181 /**
182 * Types implied by the API. This includes types explicitly named in the
183 * API as well as those implied by the definitions of requests, responses,
184 * notifications, etc.
185 */
186 final Map<String, ImpliedType> impliedTypes;
187
188 CodegenProtocolVisitor(Api api)
189 : super(api),
190 toHtmlVisitor = new ToHtmlVisitor(api),
191 impliedTypes = computeImpliedTypes(api);
192
193 @override
194 visitApi() {
195 outputHeader();
196 writeln();
197 writeln('part of protocol2;');
198 emitClasses();
199 }
200
201 /**
202 * Translate each type implied by the API to a class.
203 */
204 void emitClasses() {
205 for (ImpliedType impliedType in impliedTypes.values) {
206 TypeDecl type = impliedType.type;
207 if (type != null) {
208 String dartTypeName = capitalize(impliedType.camelName);
209 if (type is TypeObject) {
210 writeln();
211 emitObjectClass(dartTypeName, type, impliedType);
212 } else if (type is TypeEnum) {
213 writeln();
214 emitEnumClass(dartTypeName, type, impliedType);
215 }
216 }
217 }
218 }
219
220 /**
221 * Emit the class to encapsulate an object type.
222 */
223 void emitObjectClass(String className, TypeObject type, ImpliedType
224 impliedType) {
225 docComment(toHtmlVisitor.collectHtml(() {
226 toHtmlVisitor.p(() {
227 toHtmlVisitor.write(impliedType.humanReadableName);
228 });
229 if (impliedType.type != null) {
230 toHtmlVisitor.showType(null, impliedType.type);
231 }
232 }));
233 writeln('class $className {');
234 indent(() {
235 for (TypeObjectField field in type.fields) {
236 if (field.value != null) {
237 continue;
238 }
239 docComment(toHtmlVisitor.collectHtml(() {
240 toHtmlVisitor.translateHtml(field.html);
241 }));
242 writeln('final ${dartType(field.type)} ${field.name};');
243 writeln();
244 }
245 emitObjectConstructor(type, className);
246 writeln();
247 emitObjectFromJsonConstructor(className, type, impliedType);
248 writeln();
249 if (emitConvenienceConstructor(className, impliedType)) {
250 writeln();
251 }
252 emitToJsonMember(type);
253 writeln();
254 writeln('@override');
255 writeln('String toString() => JSON.encode(toJson());');
256 writeln();
257 emitObjectEqualsMember(type, className);
258 writeln();
259 emitObjectHashCode(type);
260 });
261 writeln('}');
262 }
263
264 /**
265 * Emit the constructor for an object class.
266 */
267 void emitObjectConstructor(TypeObject type, String className) {
268 List<String> args = <String>[];
269 List<String> optionalArgs = <String>[];
270 for (TypeObjectField field in type.fields) {
271 if (field.value != null) {
272 continue;
273 }
274 String arg = 'this.${field.name}';
275 if (field.optional) {
276 optionalArgs.add(arg);
277 } else {
278 args.add(arg);
279 }
280 }
281 if (optionalArgs.isNotEmpty) {
282 args.add('{${optionalArgs.join(', ')}}');
283 }
284 writeln('$className(${args.join(', ')});');
285 }
286
287 /**
288 * Emit the toJson() code for an object class.
289 */
290 void emitToJsonMember(TypeObject type) {
291 writeln('Map<String, dynamic> toJson() {');
292 indent(() {
293 writeln('Map<String, dynamic> result = {};');
294 for (TypeObjectField field in type.fields) {
295 String fieldNameString = literalString(field.name);
296 if (field.value != null) {
297 writeln('result[$fieldNameString] = ${literalString(field.value)};');
298 continue;
299 }
300 String fieldToJson = toJsonCode(field.type).asSnippet(field.name);
301 String populateField = 'result[$fieldNameString] = $fieldToJson;';
302 if (field.optional) {
303 writeln('if (${field.name} != null) {');
304 indent(() {
305 writeln(populateField);
306 });
307 writeln('}');
308 } else {
309 writeln(populateField);
310 }
311 }
312 writeln('return result;');
313 });
314 writeln('}');
315 }
316
317 /**
318 * Emit the operator== code for an object class.
319 */
320 void emitObjectEqualsMember(TypeObject type, String className) {
321 writeln('@override');
322 writeln('bool operator==(other) {');
323 indent(() {
324 writeln('if (other is $className) {');
325 indent(() {
326 var comparisons = <String>[];
327 for (TypeObjectField field in type.fields) {
328 if (field.value != null) {
329 continue;
330 }
331 comparisons.add(compareEqualsCode(field.type, field.name,
332 'other.${field.name}'));
333 }
334 if (comparisons.isEmpty) {
335 writeln('return true;');
336 } else {
337 String concatenated = comparisons.join(' &&\n ');
338 writeln('return $concatenated;');
339 }
340 });
341 writeln('}');
342 writeln('return false;');
343 });
344 writeln('}');
345 }
346
347 /**
348 * Emit the hashCode getter for an object class.
349 */
350 void emitObjectHashCode(TypeObject type) {
351 writeln('@override');
352 writeln('int get hashCode {');
353 indent(() {
354 writeln('int hash = 0;');
355 for (TypeObjectField field in type.fields) {
356 String valueToCombine;
357 if (field.value != null) {
358 valueToCombine = field.value.hashCode.toString();
359 } else {
360 valueToCombine = '${field.name}.hashCode';
361 }
362 writeln('hash = _JenkinsSmiHash.combine(hash, $valueToCombine);');
363 }
364 writeln('return _JenkinsSmiHash.finish(hash);');
365 });
366 writeln('}');
367 }
368
369 /**
370 * Emit a class to encapsulate an enum.
371 */
372 void emitEnumClass(String className, TypeEnum type, ImpliedType impliedType) {
373 docComment(toHtmlVisitor.collectHtml(() {
374 toHtmlVisitor.p(() {
375 toHtmlVisitor.write(impliedType.humanReadableName);
376 });
377 if (impliedType.type != null) {
378 toHtmlVisitor.showType(null, impliedType.type);
379 }
380 }));
381 writeln('class $className {');
382 indent(() {
383 for (TypeEnumValue value in type.values) {
384 docComment(toHtmlVisitor.collectHtml(() {
385 toHtmlVisitor.translateHtml(value.html);
386 }));
387 String valueString = literalString(value.value);
388 writeln(
389 'static const ${value.value} = const $className._($valueString);');
390 writeln();
391 }
392 writeln('final String name;');
393 writeln();
394 writeln('const $className._(this.name);');
395 writeln();
396 emitEnumClassConstructor(className, type);
397 writeln();
398 emitEnumFromJsonConstructor(className, type, impliedType);
399 writeln();
400 writeln('@override');
401 writeln('String toString() => "$className.\$name";');
402 writeln();
403 writeln('String toJson() => name;');
404 });
405 writeln('}');
406 }
407
408 /**
409 * Emit the constructor for an enum class.
410 */
411 void emitEnumClassConstructor(String className, TypeEnum type) {
412 writeln('factory $className(String name) {');
413 indent(() {
414 writeln('switch (name) {');
415 indent(() {
416 for (TypeEnumValue value in type.values) {
417 String valueString = literalString(value.value);
418 writeln('case $valueString:');
419 indent(() {
420 writeln('return ${value.value};');
421 });
422 }
423 });
424 writeln('}');
425 writeln(r"throw new Exception('Illegal enum value: $name');");
426 });
427 writeln('}');
428 }
429
430 /**
431 * Compute the code necessary to convert [type] to JSON.
432 */
433 ToJsonCode toJsonCode(TypeDecl type) {
434 TypeDecl resolvedType = resolveTypeReferenceChain(type);
435 if (resolvedType is TypeReference) {
436 return new ToJsonIdentity(dartType(type));
437 } else if (resolvedType is TypeList) {
438 ToJsonCode itemCode = toJsonCode(resolvedType.itemType);
439 if (itemCode.isIdentity) {
440 return new ToJsonIdentity(dartType(type));
441 } else {
442 return new ToJsonSnippet(dartType(type), (String value) =>
443 '$value.map(${itemCode.asClosure})');
444 }
445 } else if (resolvedType is TypeMap) {
446 ToJsonCode keyCode;
447 if (dartType(resolvedType.keyType) != 'String') {
448 keyCode = toJsonCode(resolvedType.keyType);
449 } else {
450 keyCode = new ToJsonIdentity(dartType(resolvedType.keyType));
451 }
452 ToJsonCode valueCode = toJsonCode(resolvedType.valueType);
453 if (keyCode.isIdentity && valueCode.isIdentity) {
454 return new ToJsonIdentity(dartType(resolvedType));
455 } else {
456 return new ToJsonSnippet(dartType(type), (String value) {
457 StringBuffer result = new StringBuffer();
458 result.write('_mapMap($value');
459 if (!keyCode.isIdentity) {
460 result.write(', keyCallback: ${keyCode.asClosure}');
461 }
462 if (!valueCode.isIdentity) {
463 result.write(', valueCallback: ${valueCode.asClosure}');
464 }
465 result.write(')');
466 return result.toString();
467 });
468 }
469 } else if (resolvedType is TypeUnion) {
470 for (TypeDecl choice in resolvedType.choices) {
471 if (resolveTypeReferenceChain(choice) is! TypeObject) {
472 throw new Exception('Union types must be unions of objects');
473 }
474 }
475 return new ToJsonSnippet(dartType(type), (String value) =>
476 '$value.toJson()');
477 } else if (resolvedType is TypeObject || resolvedType is TypeEnum) {
478 return new ToJsonSnippet(dartType(type), (String value) =>
479 '$value.toJson()');
480 } else {
481 throw new Exception("Can't convert $resolvedType from JSON");
482 }
483 }
484
485 /**
486 * Compute the code necessary to compare two objects for equality.
487 */
488 String compareEqualsCode(TypeDecl type, String thisVar, String otherVar) {
489 TypeDecl resolvedType = resolveTypeReferenceChain(type);
490 if (resolvedType is TypeReference || resolvedType is TypeEnum ||
491 resolvedType is TypeObject || resolvedType is TypeUnion) {
492 return '$thisVar == $otherVar';
493 } else if (resolvedType is TypeList) {
494 String itemTypeName = dartType(resolvedType.itemType);
495 String subComparison = compareEqualsCode(resolvedType.itemType, 'a', 'b');
496 String closure = '($itemTypeName a, $itemTypeName b) => $subComparison';
497 return '_listEqual($thisVar, $otherVar, $closure)';
498 } else if (resolvedType is TypeMap) {
499 String valueTypeName = dartType(resolvedType.valueType);
500 String subComparison = compareEqualsCode(resolvedType.valueType, 'a', 'b'
501 );
502 String closure = '($valueTypeName a, $valueTypeName b) => $subComparison';
503 return '_mapEqual($thisVar, $otherVar, $closure)';
504 }
505 throw new Exception("Don't know how to compare for equality: $resolvedType"
506 );
507 }
508
509 /**
510 * Emit the method for decoding an object from JSON.
511 */
512 void emitObjectFromJsonConstructor(String className, TypeObject
513 type, ImpliedType impliedType) {
514 String humanReadableNameString = literalString(impliedType.humanReadableName
515 );
516 writeln(
517 'factory $className.fromJson(JsonDecoder jsonDecoder, String jsonPath, O bject json) {'
518 );
519 indent(() {
520 writeln('if (json is Map) {');
521 indent(() {
522 List<String> args = <String>[];
523 List<String> optionalArgs = <String>[];
524 for (TypeObjectField field in type.fields) {
525 String fieldNameString = literalString(field.name);
526 String fieldAccessor = 'json[$fieldNameString]';
527 String jsonPath = 'jsonPath + ${literalString('.${field.name}')}';
528 if (field.value != null) {
529 String valueString = literalString(field.value);
530 writeln('if ($fieldAccessor != $valueString) {');
531 indent(() {
532 writeln(
533 'throw jsonDecoder.mismatch(jsonPath, "equal " + $valueString) ;');
534 });
535 writeln('}');
536 continue;
537 }
538 if (field.optional) {
539 optionalArgs.add('${field.name}: ${field.name}');
540 } else {
541 args.add(field.name);
542 }
543 String fieldDartType = dartType(field.type);
544 writeln('$fieldDartType ${field.name};');
545 writeln('if (json.containsKey($fieldNameString)) {');
546 indent(() {
547 String toJson = fromJsonCode(field.type).asSnippet(jsonPath,
548 fieldAccessor);
549 writeln('${field.name} = $toJson;');
550 });
551 write('}');
552 if (!field.optional) {
553 writeln(' else {');
554 indent(() {
555 writeln(
556 "throw jsonDecoder.missingKey(jsonPath, $fieldNameString);");
557 });
558 writeln('}');
559 } else {
560 writeln();
561 }
562 }
563 args.addAll(optionalArgs);
564 writeln('return new $className(${args.join(', ')});');
565 });
566 writeln('} else {');
567 indent(() {
568 writeln(
569 'throw jsonDecoder.mismatch(jsonPath, $humanReadableNameString);');
570 });
571 writeln('}');
572 });
573 writeln('}');
574 }
575
576 /**
577 * Emit the method for decoding an enum from JSON.
578 */
579 void emitEnumFromJsonConstructor(String className, TypeEnum type, ImpliedType
580 impliedType) {
581 writeln(
582 'factory $className.fromJson(JsonDecoder jsonDecoder, String jsonPath, O bject json) {'
583 );
584 indent(() {
585 writeln('if (json is String) {');
586 indent(() {
587 writeln('try {');
588 indent(() {
589 writeln('return new $className(json);');
590 });
591 writeln('} catch(_) {');
592 indent(() {
593 writeln('// Fall through');
594 });
595 writeln('}');
596 });
597 writeln('}');
598 String humanReadableNameString = literalString(
599 impliedType.humanReadableName);
600 writeln('throw jsonDecoder.mismatch(jsonPath, $humanReadableNameString);'
601 );
602 });
603 writeln('}');
604 }
605
606 /**
607 * Compute the code necessary to translate [type] from JSON.
608 */
609 FromJsonCode fromJsonCode(TypeDecl type) {
610 if (type is TypeReference) {
611 TypeDefinition referencedDefinition = api.types[type.typeName];
612 if (referencedDefinition != null) {
613 TypeDecl referencedType = referencedDefinition.type;
614 if (referencedType is TypeObject || referencedType is TypeEnum) {
615 return new FromJsonSnippet((String jsonPath, String json) =>
616 'new ${dartType(type)}.fromJson(jsonDecoder, $jsonPath, $json)');
617 } else {
618 return fromJsonCode(referencedType);
619 }
620 } else {
621 switch (type.typeName) {
622 case 'String':
623 return new FromJsonFunction('jsonDecoder._decodeString');
624 case 'bool':
625 return new FromJsonFunction('jsonDecoder._decodeBool');
626 case 'int':
627 return new FromJsonFunction('jsonDecoder._decodeInt');
628 case 'object':
629 return new FromJsonIdentity();
630 default:
631 throw new Exception('Unexpected type name ${type.typeName}');
632 }
633 }
634 } else if (type is TypeMap) {
635 FromJsonCode keyCode;
636 if (dartType(type.keyType) != 'String') {
637 keyCode = fromJsonCode(type.keyType);
638 } else {
639 keyCode = new FromJsonIdentity();
640 }
641 FromJsonCode valueCode = fromJsonCode(type.valueType);
642 if (keyCode.isIdentity && valueCode.isIdentity) {
643 return new FromJsonFunction('jsonDecoder._decodeMap');
644 } else {
645 return new FromJsonSnippet((String jsonPath, String json) {
646 StringBuffer result = new StringBuffer();
647 result.write('jsonDecoder._decodeMap($jsonPath, $json');
648 if (!keyCode.isIdentity) {
649 result.write(', keyDecoder: ${keyCode.asClosure}');
650 }
651 if (!valueCode.isIdentity) {
652 result.write(', valueDecoder: ${valueCode.asClosure}');
653 }
654 result.write(')');
655 return result.toString();
656 });
657 }
658 } else if (type is TypeList) {
659 FromJsonCode itemCode = fromJsonCode(type.itemType);
660 if (itemCode.isIdentity) {
661 return new FromJsonFunction('jsonDecoder._decodeList');
662 } else {
663 return new FromJsonSnippet((String jsonPath, String json) =>
664 'jsonDecoder._decodeList($jsonPath, $json, ${itemCode.asClosure})');
665 }
666 } else if (type is TypeUnion) {
667 List<String> decoders = <String>[];
668 for (TypeDecl choice in type.choices) {
669 TypeDecl resolvedChoice = resolveTypeReferenceChain(choice);
670 if (resolvedChoice is TypeObject) {
671 TypeObjectField field = resolvedChoice.getField(type.field);
672 if (field == null) {
673 throw new Exception(
674 'Each choice in the union needs a field named ${type.field}');
675 }
676 if (field.value == null) {
677 throw new Exception(
678 'Each choice in the union needs a constant value for the field $ {type.field}');
679 }
680 String closure = fromJsonCode(choice).asClosure;
681 decoders.add('${literalString(field.value)}: $closure');
682 } else {
683 throw new Exception('Union types must be unions of objects.');
684 }
685 }
686 return new FromJsonSnippet((String jsonPath, String json) =>
687 'jsonDecoder._decodeUnion($jsonPath, $json, ${literalString(type.field )}, {${decoders.join(', ')}})'
688 );
689 } else {
690 throw new Exception("Can't convert $type from JSON");
691 }
692 }
693
694 /**
695 * Emit a convenience constructor for decoding a piece of protocol, if
696 * appropriate. Return true if a constructor was emitted.
697 */
698 bool emitConvenienceConstructor(String className, ImpliedType impliedType) {
699 // The type of object from which this piece of protocol should be decoded.
700 String inputType;
701 // The name of the input object.
702 String inputName;
703 // The field within the input object to decode.
704 String fieldName;
705 // Constructor call to create the JsonDecoder object.
706 String makeDecoder;
707 // Name of the constructor to create.
708 String constructorName;
709 // Extra arguments for the constructor.
710 List<String> extraArgs = <String>[];
711 switch (impliedType.kind) {
712 case 'requestParams':
713 inputType = 'Request';
714 inputName = 'request';
715 fieldName = 'params';
716 makeDecoder = 'new RequestDecoder(request)';
717 constructorName = 'fromRequest';
718 break;
719 case 'requestResult':
720 inputType = 'Response';
721 inputName = 'response';
722 fieldName = 'result';
723 makeDecoder = 'new ResponseDecoder()';
724 constructorName = 'fromResponse';
725 break;
726 case 'notificationParams':
727 inputType = 'Notification';
728 inputName = 'notification';
729 fieldName = 'params';
730 makeDecoder = 'new ResponseDecoder()';
731 constructorName = 'fromNotification';
732 break;
733 case 'refactoringFeedback':
734 inputType = 'EditGetRefactoringResult';
735 inputName = 'refactoringResult';
736 fieldName = 'feedback';
737 makeDecoder = 'new ResponseDecoder()';
738 constructorName = 'fromRefactoringResult';
739 break;
740 case 'refactoringOptions':
741 inputType = 'EditGetRefactoringParams';
742 inputName = 'refactoringParams';
743 fieldName = 'options';
744 makeDecoder = 'new RequestDecoder(request)';
745 constructorName = 'fromRefactoringParams';
746 extraArgs.add('Request request');
747 break;
748 default:
749 return false;
750 }
751 List<String> args = ['$inputType $inputName'];
752 args.addAll(extraArgs);
753 writeln('factory $className.$constructorName(${args.join(', ')}) {');
754 indent(() {
755 String fieldNameString = literalString(fieldName);
756 writeln('return new $className.fromJson(');
757 writeln(' $makeDecoder, $fieldNameString, $inputName.$fieldName);');
758 });
759 writeln('}');
760 return true;
761 }
762
763 /**
764 * Create a string literal that evaluates to [s].
765 */
766 String literalString(String s) {
767 return JSON.encode(s);
768 }
769
770 /**
771 * Convert the given [TypeDecl] to a Dart type.
772 */
773 String dartType(TypeDecl type) {
774 if (type is TypeReference) {
775 String typeName = type.typeName;
776 TypeDefinition referencedDefinition = api.types[typeName];
777 if (_typeRenames.containsKey(typeName)) {
778 return _typeRenames[typeName];
779 }
780 if (referencedDefinition == null) {
781 return typeName;
782 }
783 TypeDecl referencedType = referencedDefinition.type;
784 if (referencedType is TypeObject || referencedType is TypeEnum) {
785 return typeName;
786 }
787 return dartType(referencedType);
788 } else if (type is TypeList) {
789 return 'List<${dartType(type.itemType)}>';
790 } else if (type is TypeMap) {
791 return 'Map<${dartType(type.keyType)}, ${dartType(type.valueType)}>';
792 } else if (type is TypeUnion) {
793 return 'dynamic';
794 } else {
795 throw new Exception("Can't convert to a dart type");
796 }
797 }
798 }
799
800 final GeneratedFile target = new GeneratedFile(
801 '../../lib/src/generated_protocol.dart', () {
802 CodegenProtocolVisitor visitor = new CodegenProtocolVisitor(readApi());
803 return visitor.collectCode(visitor.visitApi);
804 });
805
806 /**
807 * Translate spec_input.html into protocol_matchers.dart.
808 */
809 main() {
810 target.generate();
811 }
OLDNEW
« no previous file with comments | « pkg/analysis_server/tool/spec/api.dart ('k') | pkg/analysis_server/tool/spec/codegen_matchers.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698