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

Unified Diff: pkg/analysis_server/tool/spec/codegen_dart_protocol.dart

Issue 725143004: Format and sort analyzer and analysis_server packages. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 1 month 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 side-by-side diff with in-line comments
Download patch
Index: pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
diff --git a/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart b/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
index 7bacc2322fe7cbe25ece19528116eea6c5750dab..2fc8d73ebf31a74fc38a56080f83f28201d5f3db 100644
--- a/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
+++ b/pkg/analysis_server/tool/spec/codegen_dart_protocol.dart
@@ -6,6 +6,8 @@ library codegen.protocol;
import 'dart:convert';
+import 'package:html5lib/dom.dart' as dom;
+
import 'api.dart';
import 'codegen_dart.dart';
import 'codegen_tools.dart';
@@ -13,158 +15,6 @@ import 'from_html.dart';
import 'implied_types.dart';
import 'to_html.dart';
-import 'package:html5lib/dom.dart' as dom;
-
-/**
- * Container for code that can be used to translate a data type from JSON.
- */
-abstract class FromJsonCode {
- /**
- * True if the data type is already in JSON form, so the translation is the
- * identity function.
- */
- bool get isIdentity;
-
- /**
- * Get the translation code in the form of a closure.
- */
- String get asClosure;
-
- /**
- * Get the translation code in the form of a code snippet, where [jsonPath]
- * is the variable holding the JSON path, and [json] is the variable holding
- * the raw JSON.
- */
- String asSnippet(String jsonPath, String json);
-}
-
-/**
- * Representation of FromJsonCode for a function defined elsewhere.
- */
-class FromJsonFunction extends FromJsonCode {
- final String asClosure;
-
- FromJsonFunction(this.asClosure);
-
- @override
- bool get isIdentity => false;
-
- @override
- String asSnippet(String jsonPath, String json) =>
- '$asClosure($jsonPath, $json)';
-}
-
-typedef String FromJsonSnippetCallback(String jsonPath, String json);
-
-/**
- * Representation of FromJsonCode for a snippet of inline code.
- */
-class FromJsonSnippet extends FromJsonCode {
- /**
- * Callback that can be used to generate the code snippet, once the names
- * of the [jsonPath] and [json] variables are known.
- */
- final FromJsonSnippetCallback callback;
-
- FromJsonSnippet(this.callback);
-
- @override
- bool get isIdentity => false;
-
- @override
- String get asClosure =>
- '(String jsonPath, Object json) => ${callback('jsonPath', 'json')}';
-
- @override
- String asSnippet(String jsonPath, String json) => callback(jsonPath, json);
-}
-
-/**
- * Representation of FromJsonCode for the identity transformation.
- */
-class FromJsonIdentity extends FromJsonSnippet {
- FromJsonIdentity() : super((String jsonPath, String json) => json);
-
- @override
- bool get isIdentity => true;
-}
-
-/**
- * Container for code that can be used to translate a data type to JSON.
- */
-abstract class ToJsonCode {
- /**
- * True if the data type is already in JSON form, so the translation is the
- * identity function.
- */
- bool get isIdentity;
-
- /**
- * Get the translation code in the form of a closure.
- */
- String get asClosure;
-
- /**
- * Get the translation code in the form of a code snippet, where [value]
- * is the variable holding the object to be translated.
- */
- String asSnippet(String value);
-}
-
-/**
- * Representation of ToJsonCode for a function defined elsewhere.
- */
-class ToJsonFunction extends ToJsonCode {
- final String asClosure;
-
- ToJsonFunction(this.asClosure);
-
- @override
- bool get isIdentity => false;
-
- @override
- String asSnippet(String value) => '$asClosure($value)';
-}
-
-typedef String ToJsonSnippetCallback(String value);
-
-/**
- * Representation of ToJsonCode for a snippet of inline code.
- */
-class ToJsonSnippet extends ToJsonCode {
- /**
- * Callback that can be used to generate the code snippet, once the name
- * of the [value] variable is known.
- */
- final ToJsonSnippetCallback callback;
-
- /**
- * Dart type of the [value] variable.
- */
- final String type;
-
- ToJsonSnippet(this.type, this.callback);
-
- @override
- bool get isIdentity => false;
-
- @override
- String get asClosure => '($type value) => ${callback('value')}';
-
- @override
- String asSnippet(String value) => callback(value);
-}
-
-/**
- * Representation of FromJsonCode for the identity transformation.
- */
-class ToJsonIdentity extends ToJsonSnippet {
- ToJsonIdentity(String type) : super(type, (String value) => value);
-
- @override
- bool get isIdentity => true;
-}
-
/**
* Special flags that need to be inserted into the declaration of the Element
* class.
@@ -178,11 +28,28 @@ const Map<String, String> specialElementFlags = const {
'deprecated': '0x20'
};
+final GeneratedFile target =
+ new GeneratedFile('../../lib/src/generated_protocol.dart', () {
+ CodegenProtocolVisitor visitor = new CodegenProtocolVisitor(readApi());
+ return visitor.collectCode(visitor.visitApi);
+});
+
+/**
+ * Translate spec_input.html into protocol_matchers.dart.
+ */
+main() {
+ target.generate();
+}
+
/**
* Callback type used to represent arbitrary code generation.
*/
typedef void CodegenCallback();
+typedef String FromJsonSnippetCallback(String jsonPath, String json);
+
+typedef String ToJsonSnippetCallback(String value);
+
/**
* Visitor which produces Dart code representing the API.
*/
@@ -216,12 +83,30 @@ class CodegenProtocolVisitor extends DartCodegenVisitor with CodeGenerator {
toHtmlVisitor = new ToHtmlVisitor(api),
impliedTypes = computeImpliedTypes(api);
- @override
- visitApi() {
- outputHeader();
- writeln();
- writeln('part of protocol;');
- emitClasses();
+ /**
+ * Compute the code necessary to compare two objects for equality.
+ */
+ String compareEqualsCode(TypeDecl type, String thisVar, String otherVar) {
+ TypeDecl resolvedType = resolveTypeReferenceChain(type);
+ if (resolvedType is TypeReference ||
+ resolvedType is TypeEnum ||
+ resolvedType is TypeObject ||
+ resolvedType is TypeUnion) {
+ return '$thisVar == $otherVar';
+ } else if (resolvedType is TypeList) {
+ String itemTypeName = dartType(resolvedType.itemType);
+ String subComparison = compareEqualsCode(resolvedType.itemType, 'a', 'b');
+ String closure = '($itemTypeName a, $itemTypeName b) => $subComparison';
+ return '_listEqual($thisVar, $otherVar, $closure)';
+ } else if (resolvedType is TypeMap) {
+ String valueTypeName = dartType(resolvedType.valueType);
+ String subComparison =
+ compareEqualsCode(resolvedType.valueType, 'a', 'b');
+ String closure = '($valueTypeName a, $valueTypeName b) => $subComparison';
+ return '_mapEqual($thisVar, $otherVar, $closure)';
+ }
+ throw new Exception(
+ "Don't know how to compare for equality: $resolvedType");
}
/**
@@ -244,60 +129,233 @@ class CodegenProtocolVisitor extends DartCodegenVisitor with CodeGenerator {
}
/**
- * Emit a class representing an data structure that doesn't exist in the
- * protocol because it is empty (e.g. the "params" object for a request that
- * doesn't have any parameters).
- */
- void emitEmptyObjectClass(String className, ImpliedType impliedType) {
- docComment(toHtmlVisitor.collectHtml(() {
- toHtmlVisitor.p(() {
- toHtmlVisitor.write(impliedType.humanReadableName);
- });
- }));
- writeln('class $className {');
- indent(() {
- if (emitToRequestMember(impliedType)) {
- writeln();
- }
- if (emitToResponseMember(impliedType)) {
- writeln();
- }
- if (emitToNotificationMember(impliedType)) {
- writeln();
- }
- emitObjectEqualsMember(null, className);
- writeln();
- emitObjectHashCode(null, className);
- });
- writeln('}');
- }
-
- /**
- * Emit the class to encapsulate an object type.
+ * Emit a convenience constructor for decoding a piece of protocol, if
+ * appropriate. Return true if a constructor was emitted.
*/
- void emitObjectClass(String className, TypeObject type,
- ImpliedType impliedType) {
- docComment(toHtmlVisitor.collectHtml(() {
- toHtmlVisitor.p(() {
- toHtmlVisitor.write(impliedType.humanReadableName);
- });
- if (impliedType.type != null) {
- toHtmlVisitor.showType(null, impliedType.type);
- }
- }));
- write('class $className');
- if (impliedType.kind == 'refactoringFeedback') {
- write(' extends RefactoringFeedback');
- }
- if (impliedType.kind == 'refactoringOptions') {
- write(' extends RefactoringOptions');
- }
- writeln(' implements HasToJson {');
- indent(() {
- if (emitSpecialStaticMembers(className)) {
- writeln();
- }
- for (TypeObjectField field in type.fields) {
+ bool emitConvenienceConstructor(String className, ImpliedType impliedType) {
+ // The type of object from which this piece of protocol should be decoded.
+ String inputType;
+ // The name of the input object.
+ String inputName;
+ // The field within the input object to decode.
+ String fieldName;
+ // Constructor call to create the JsonDecoder object.
+ String makeDecoder;
+ // Name of the constructor to create.
+ String constructorName;
+ // Extra arguments for the constructor.
+ List<String> extraArgs = <String>[];
+ switch (impliedType.kind) {
+ case 'requestParams':
+ inputType = 'Request';
+ inputName = 'request';
+ fieldName = '_params';
+ makeDecoder = 'new RequestDecoder(request)';
+ constructorName = 'fromRequest';
+ break;
+ case 'requestResult':
+ inputType = 'Response';
+ inputName = 'response';
+ fieldName = '_result';
+ makeDecoder =
+ 'new ResponseDecoder(REQUEST_ID_REFACTORING_KINDS.remove(response.id))';
+ constructorName = 'fromResponse';
+ break;
+ case 'notificationParams':
+ inputType = 'Notification';
+ inputName = 'notification';
+ fieldName = '_params';
+ makeDecoder = 'new ResponseDecoder(null)';
+ constructorName = 'fromNotification';
+ break;
+ case 'refactoringOptions':
+ inputType = 'EditGetRefactoringParams';
+ inputName = 'refactoringParams';
+ fieldName = 'options';
+ makeDecoder = 'new RequestDecoder(request)';
+ constructorName = 'fromRefactoringParams';
+ extraArgs.add('Request request');
+ break;
+ default:
+ return false;
+ }
+ List<String> args = ['$inputType $inputName'];
+ args.addAll(extraArgs);
+ writeln('factory $className.$constructorName(${args.join(', ')}) {');
+ indent(() {
+ String fieldNameString =
+ literalString(fieldName.replaceFirst(new RegExp('^_'), ''));
+ if (className == 'EditGetRefactoringParams') {
+ writeln('var params = new $className.fromJson(');
+ writeln(' $makeDecoder, $fieldNameString, $inputName.$fieldName);');
+ writeln('REQUEST_ID_REFACTORING_KINDS[request.id] = params.kind;');
+ writeln('return params;');
+ } else {
+ writeln('return new $className.fromJson(');
+ writeln(' $makeDecoder, $fieldNameString, $inputName.$fieldName);');
+ }
+ });
+ writeln('}');
+ return true;
+ }
+
+ /**
+ * Emit a class representing an data structure that doesn't exist in the
+ * protocol because it is empty (e.g. the "params" object for a request that
+ * doesn't have any parameters).
+ */
+ void emitEmptyObjectClass(String className, ImpliedType impliedType) {
+ docComment(toHtmlVisitor.collectHtml(() {
+ toHtmlVisitor.p(() {
+ toHtmlVisitor.write(impliedType.humanReadableName);
+ });
+ }));
+ writeln('class $className {');
+ indent(() {
+ if (emitToRequestMember(impliedType)) {
+ writeln();
+ }
+ if (emitToResponseMember(impliedType)) {
+ writeln();
+ }
+ if (emitToNotificationMember(impliedType)) {
+ writeln();
+ }
+ emitObjectEqualsMember(null, className);
+ writeln();
+ emitObjectHashCode(null, className);
+ });
+ writeln('}');
+ }
+
+ /**
+ * Emit a class to encapsulate an enum.
+ */
+ void emitEnumClass(String className, TypeEnum type, ImpliedType impliedType) {
+ docComment(toHtmlVisitor.collectHtml(() {
+ toHtmlVisitor.p(() {
+ toHtmlVisitor.write(impliedType.humanReadableName);
+ });
+ if (impliedType.type != null) {
+ toHtmlVisitor.showType(null, impliedType.type);
+ }
+ }));
+ writeln('class $className implements Enum {');
+ indent(() {
+ if (emitSpecialStaticMembers(className)) {
+ writeln();
+ }
+ for (TypeEnumValue value in type.values) {
+ docComment(toHtmlVisitor.collectHtml(() {
+ toHtmlVisitor.translateHtml(value.html);
+ }));
+ String valueString = literalString(value.value);
+ writeln(
+ 'static const ${value.value} = const $className._($valueString);');
+ writeln();
+ }
+ writeln('final String name;');
+ writeln();
+ writeln('const $className._(this.name);');
+ writeln();
+ emitEnumClassConstructor(className, type);
+ writeln();
+ emitEnumFromJsonConstructor(className, type, impliedType);
+ writeln();
+ if (emitSpecialConstructors(className)) {
+ writeln();
+ }
+ if (emitSpecialGetters(className)) {
+ writeln();
+ }
+ if (emitSpecialMethods(className)) {
+ writeln();
+ }
+ writeln('@override');
+ writeln('String toString() => "$className.\$name";');
+ writeln();
+ writeln('String toJson() => name;');
+ });
+ writeln('}');
+ }
+
+ /**
+ * Emit the constructor for an enum class.
+ */
+ void emitEnumClassConstructor(String className, TypeEnum type) {
+ writeln('factory $className(String name) {');
+ indent(() {
+ writeln('switch (name) {');
+ indent(() {
+ for (TypeEnumValue value in type.values) {
+ String valueString = literalString(value.value);
+ writeln('case $valueString:');
+ indent(() {
+ writeln('return ${value.value};');
+ });
+ }
+ });
+ writeln('}');
+ writeln(r"throw new Exception('Illegal enum value: $name');");
+ });
+ writeln('}');
+ }
+
+ /**
+ * Emit the method for decoding an enum from JSON.
+ */
+ void emitEnumFromJsonConstructor(String className, TypeEnum type,
+ ImpliedType impliedType) {
+ writeln(
+ 'factory $className.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {');
+ indent(() {
+ writeln('if (json is String) {');
+ indent(() {
+ writeln('try {');
+ indent(() {
+ writeln('return new $className(json);');
+ });
+ writeln('} catch(_) {');
+ indent(() {
+ writeln('// Fall through');
+ });
+ writeln('}');
+ });
+ writeln('}');
+ String humanReadableNameString =
+ literalString(impliedType.humanReadableName);
+ writeln(
+ 'throw jsonDecoder.mismatch(jsonPath, $humanReadableNameString);');
+ });
+ writeln('}');
+ }
+
+ /**
+ * Emit the class to encapsulate an object type.
+ */
+ void emitObjectClass(String className, TypeObject type,
+ ImpliedType impliedType) {
+ docComment(toHtmlVisitor.collectHtml(() {
+ toHtmlVisitor.p(() {
+ toHtmlVisitor.write(impliedType.humanReadableName);
+ });
+ if (impliedType.type != null) {
+ toHtmlVisitor.showType(null, impliedType.type);
+ }
+ }));
+ write('class $className');
+ if (impliedType.kind == 'refactoringFeedback') {
+ write(' extends RefactoringFeedback');
+ }
+ if (impliedType.kind == 'refactoringOptions') {
+ write(' extends RefactoringOptions');
+ }
+ writeln(' implements HasToJson {');
+ indent(() {
+ if (emitSpecialStaticMembers(className)) {
+ writeln();
+ }
+ for (TypeObjectField field in type.fields) {
if (field.value != null) {
continue;
}
@@ -345,46 +403,208 @@ class CodegenProtocolVisitor extends DartCodegenVisitor with CodeGenerator {
}
/**
- * If the class named [className] requires special static members, emit them
- * and return true.
+ * Emit the constructor for an object class.
*/
- bool emitSpecialStaticMembers(String className) {
- switch (className) {
- case 'Element':
- List<String> makeFlagsArgs = <String>[];
- List<String> makeFlagsStatements = <String>[];
- specialElementFlags.forEach((String name, String value) {
- String flag = 'FLAG_${name.toUpperCase()}';
- String camelName = camelJoin(['is', name]);
- writeln('static const int $flag = $value;');
- makeFlagsArgs.add('$camelName: false');
- makeFlagsStatements.add('if ($camelName) flags |= $flag;');
- });
- writeln();
- writeln('static int makeFlags({${makeFlagsArgs.join(', ')}}) {');
- indent(() {
- writeln('int flags = 0;');
- for (String statement in makeFlagsStatements) {
- writeln(statement);
- }
- writeln('return flags;');
- });
- writeln('}');
- return true;
- case 'SourceEdit':
- docComment(
- [
- new dom.Text(
- 'Get the result of applying a set of ' +
- '[edits] to the given [code]. Edits are applied in the order ' +
- 'they appear in [edits].')]);
+ void emitObjectConstructor(TypeObject type, String className) {
+ List<String> args = <String>[];
+ List<String> optionalArgs = <String>[];
+ List<CodegenCallback> extraInitCode = <CodegenCallback>[];
+ for (TypeObjectField field in type.fields) {
+ if (field.value != null) {
+ continue;
+ }
+ String arg = 'this.${field.name}';
+ if (isOptionalConstructorArg(className, field)) {
+ optionalArgs.add(arg);
+ if (!field.optional) {
+ // Optional constructor arg, but non-optional field. If no arg is
+ // given, the constructor should populate with the empty list.
+ TypeDecl fieldType = field.type;
+ if (fieldType is TypeList) {
+ extraInitCode.add(() {
+ writeln('if (${field.name} == null) {');
+ indent(() {
+ writeln('${field.name} = <${dartType(fieldType.itemType)}>[];');
+ });
+ writeln('}');
+ });
+ } else {
+ throw new Exception(
+ "Don't know how to create default field value.");
+ }
+ }
+ } else {
+ args.add(arg);
+ }
+ }
+ if (optionalArgs.isNotEmpty) {
+ args.add('{${optionalArgs.join(', ')}}');
+ }
+ write('$className(${args.join(', ')})');
+ if (extraInitCode.isEmpty) {
+ writeln(';');
+ } else {
+ writeln(' {');
+ indent(() {
+ for (CodegenCallback callback in extraInitCode) {
+ callback();
+ }
+ });
+ writeln('}');
+ }
+ }
+
+ /**
+ * Emit the operator== code for an object class.
+ */
+ void emitObjectEqualsMember(TypeObject type, String className) {
+ writeln('@override');
+ writeln('bool operator==(other) {');
+ indent(() {
+ writeln('if (other is $className) {');
+ indent(() {
+ var comparisons = <String>[];
+ if (type != null) {
+ for (TypeObjectField field in type.fields) {
+ if (field.value != null) {
+ continue;
+ }
+ comparisons.add(
+ compareEqualsCode(field.type, field.name, 'other.${field.name}'));
+ }
+ }
+ if (comparisons.isEmpty) {
+ writeln('return true;');
+ } else {
+ String concatenated = comparisons.join(' &&\n ');
+ writeln('return $concatenated;');
+ }
+ });
+ writeln('}');
+ writeln('return false;');
+ });
+ writeln('}');
+ }
+
+ /**
+ * Emit the method for decoding an object from JSON.
+ */
+ void emitObjectFromJsonConstructor(String className, TypeObject type,
+ ImpliedType impliedType) {
+ String humanReadableNameString =
+ literalString(impliedType.humanReadableName);
+ if (className == 'RefactoringFeedback') {
+ writeln(
+ 'factory RefactoringFeedback.fromJson(JsonDecoder jsonDecoder, '
+ 'String jsonPath, Object json, Map responseJson) {');
+ indent(() {
writeln(
- 'static String applySequence(String code, Iterable<SourceEdit> edits) =>');
- writeln(' _applySequence(code, edits);');
- return true;
- default:
- return false;
+ 'return _refactoringFeedbackFromJson(jsonDecoder, jsonPath, '
+ 'json, responseJson);');
+ });
+ writeln('}');
+ return;
+ }
+ if (className == 'RefactoringOptions') {
+ writeln(
+ 'factory RefactoringOptions.fromJson(JsonDecoder jsonDecoder, '
+ 'String jsonPath, Object json, RefactoringKind kind) {');
+ indent(() {
+ writeln(
+ 'return _refactoringOptionsFromJson(jsonDecoder, jsonPath, ' 'json, kind);');
+ });
+ writeln('}');
+ return;
}
+ writeln(
+ 'factory $className.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {');
+ indent(() {
+ writeln('if (json == null) {');
+ indent(() {
+ writeln('json = {};');
+ });
+ writeln('}');
+ writeln('if (json is Map) {');
+ indent(() {
+ List<String> args = <String>[];
+ List<String> optionalArgs = <String>[];
+ for (TypeObjectField field in type.fields) {
+ String fieldNameString = literalString(field.name);
+ String fieldAccessor = 'json[$fieldNameString]';
+ String jsonPath = 'jsonPath + ${literalString('.${field.name}')}';
+ if (field.value != null) {
+ String valueString = literalString(field.value);
+ writeln('if ($fieldAccessor != $valueString) {');
+ indent(() {
+ writeln(
+ 'throw jsonDecoder.mismatch(jsonPath, "equal " + $valueString);');
+ });
+ writeln('}');
+ continue;
+ }
+ if (isOptionalConstructorArg(className, field)) {
+ optionalArgs.add('${field.name}: ${field.name}');
+ } else {
+ args.add(field.name);
+ }
+ TypeDecl fieldType = field.type;
+ String fieldDartType = dartType(fieldType);
+ writeln('$fieldDartType ${field.name};');
+ writeln('if (json.containsKey($fieldNameString)) {');
+ indent(() {
+ String fromJson =
+ fromJsonCode(fieldType).asSnippet(jsonPath, fieldAccessor);
+ writeln('${field.name} = $fromJson;');
+ });
+ write('}');
+ if (!field.optional) {
+ writeln(' else {');
+ indent(() {
+ writeln(
+ "throw jsonDecoder.missingKey(jsonPath, $fieldNameString);");
+ });
+ writeln('}');
+ } else {
+ writeln();
+ }
+ }
+ args.addAll(optionalArgs);
+ writeln('return new $className(${args.join(', ')});');
+ });
+ writeln('} else {');
+ indent(() {
+ writeln(
+ 'throw jsonDecoder.mismatch(jsonPath, $humanReadableNameString);');
+ });
+ writeln('}');
+ });
+ writeln('}');
+ }
+
+ /**
+ * Emit the hashCode getter for an object class.
+ */
+ void emitObjectHashCode(TypeObject type, String className) {
+ writeln('@override');
+ writeln('int get hashCode {');
+ indent(() {
+ if (type == null) {
+ writeln('return ${className.hashCode};');
+ } else {
+ writeln('int hash = 0;');
+ for (TypeObjectField field in type.fields) {
+ String valueToCombine;
+ if (field.value != null) {
+ valueToCombine = field.value.hashCode.toString();
+ } else {
+ valueToCombine = '${field.name}.hashCode';
+ }
+ writeln('hash = _JenkinsSmiHash.combine(hash, $valueToCombine);');
+ }
+ writeln('return _JenkinsSmiHash.finish(hash);');
+ }
+ });
+ writeln('}');
}
/**
@@ -500,69 +720,46 @@ class CodegenProtocolVisitor extends DartCodegenVisitor with CodeGenerator {
}
/**
- * Emit the constructor for an object class.
+ * If the class named [className] requires special static members, emit them
+ * and return true.
*/
- void emitObjectConstructor(TypeObject type, String className) {
- List<String> args = <String>[];
- List<String> optionalArgs = <String>[];
- List<CodegenCallback> extraInitCode = <CodegenCallback>[];
- for (TypeObjectField field in type.fields) {
- if (field.value != null) {
- continue;
- }
- String arg = 'this.${field.name}';
- if (isOptionalConstructorArg(className, field)) {
- optionalArgs.add(arg);
- if (!field.optional) {
- // Optional constructor arg, but non-optional field. If no arg is
- // given, the constructor should populate with the empty list.
- TypeDecl fieldType = field.type;
- if (fieldType is TypeList) {
- extraInitCode.add(() {
- writeln('if (${field.name} == null) {');
- indent(() {
- writeln('${field.name} = <${dartType(fieldType.itemType)}>[];');
- });
- writeln('}');
- });
- } else {
- throw new Exception(
- "Don't know how to create default field value.");
+ bool emitSpecialStaticMembers(String className) {
+ switch (className) {
+ case 'Element':
+ List<String> makeFlagsArgs = <String>[];
+ List<String> makeFlagsStatements = <String>[];
+ specialElementFlags.forEach((String name, String value) {
+ String flag = 'FLAG_${name.toUpperCase()}';
+ String camelName = camelJoin(['is', name]);
+ writeln('static const int $flag = $value;');
+ makeFlagsArgs.add('$camelName: false');
+ makeFlagsStatements.add('if ($camelName) flags |= $flag;');
+ });
+ writeln();
+ writeln('static int makeFlags({${makeFlagsArgs.join(', ')}}) {');
+ indent(() {
+ writeln('int flags = 0;');
+ for (String statement in makeFlagsStatements) {
+ writeln(statement);
}
- }
- } else {
- args.add(arg);
- }
- }
- if (optionalArgs.isNotEmpty) {
- args.add('{${optionalArgs.join(', ')}}');
- }
- write('$className(${args.join(', ')})');
- if (extraInitCode.isEmpty) {
- writeln(';');
- } else {
- writeln(' {');
- indent(() {
- for (CodegenCallback callback in extraInitCode) {
- callback();
- }
- });
- writeln('}');
- }
- }
-
- /**
- * True if the constructor argument for the given field should be optional.
- */
- bool isOptionalConstructorArg(String className, TypeObjectField field) {
- if (field.optional) {
- return true;
- }
- List<String> forceOptional = _optionalConstructorArguments[className];
- if (forceOptional != null && forceOptional.contains(field.name)) {
- return true;
+ writeln('return flags;');
+ });
+ writeln('}');
+ return true;
+ case 'SourceEdit':
+ docComment(
+ [
+ new dom.Text(
+ 'Get the result of applying a set of ' +
+ '[edits] to the given [code]. Edits are applied in the order ' +
+ 'they appear in [edits].')]);
+ writeln(
+ 'static String applySequence(String code, Iterable<SourceEdit> edits) =>');
+ writeln(' _applySequence(code, edits);');
+ return true;
+ default:
+ return false;
}
- return false;
}
/**
@@ -596,6 +793,25 @@ class CodegenProtocolVisitor extends DartCodegenVisitor with CodeGenerator {
}
/**
+ * Emit the toNotification() code for a class, if appropriate. Returns true
+ * if code was emitted.
+ */
+ bool emitToNotificationMember(ImpliedType impliedType) {
+ if (impliedType.kind == 'notificationParams') {
+ writeln('Notification toNotification() {');
+ indent(() {
+ String eventString =
+ literalString((impliedType.apiNode as Notification).longEvent);
+ String jsonPart = impliedType.type != null ? 'toJson()' : 'null';
+ writeln('return new Notification($eventString, $jsonPart);');
+ });
+ writeln('}');
+ return true;
+ }
+ return false;
+ }
+
+ /**
* Emit the toRequest() code for a class, if appropriate. Returns true if
* code was emitted.
*/
@@ -632,157 +848,128 @@ class CodegenProtocolVisitor extends DartCodegenVisitor with CodeGenerator {
}
/**
- * Emit the toNotification() code for a class, if appropriate. Returns true
- * if code was emitted.
+ * Compute the code necessary to translate [type] from JSON.
*/
- bool emitToNotificationMember(ImpliedType impliedType) {
- if (impliedType.kind == 'notificationParams') {
- writeln('Notification toNotification() {');
- indent(() {
- String eventString =
- literalString((impliedType.apiNode as Notification).longEvent);
- String jsonPart = impliedType.type != null ? 'toJson()' : 'null';
- writeln('return new Notification($eventString, $jsonPart);');
- });
- writeln('}');
- return true;
+ FromJsonCode fromJsonCode(TypeDecl type) {
+ if (type is TypeReference) {
+ TypeDefinition referencedDefinition = api.types[type.typeName];
+ if (referencedDefinition != null) {
+ TypeDecl referencedType = referencedDefinition.type;
+ if (referencedType is TypeObject || referencedType is TypeEnum) {
+ return new FromJsonSnippet((String jsonPath, String json) {
+ String typeName = dartType(type);
+ if (typeName == 'RefactoringFeedback') {
+ return
+ 'new $typeName.fromJson(jsonDecoder, $jsonPath, $json, json)';
+ } else if (typeName == 'RefactoringOptions') {
+ return
+ 'new $typeName.fromJson(jsonDecoder, $jsonPath, $json, kind)';
+ } else {
+ return 'new $typeName.fromJson(jsonDecoder, $jsonPath, $json)';
+ }
+ });
+ } else {
+ return fromJsonCode(referencedType);
+ }
+ } else {
+ switch (type.typeName) {
+ case 'String':
+ return new FromJsonFunction('jsonDecoder._decodeString');
+ case 'bool':
+ return new FromJsonFunction('jsonDecoder._decodeBool');
+ case 'int':
+ case 'long':
+ return new FromJsonFunction('jsonDecoder._decodeInt');
+ case 'object':
+ return new FromJsonIdentity();
+ default:
+ throw new Exception('Unexpected type name ${type.typeName}');
+ }
+ }
+ } else if (type is TypeMap) {
+ FromJsonCode keyCode;
+ if (dartType(type.keyType) != 'String') {
+ keyCode = fromJsonCode(type.keyType);
+ } else {
+ keyCode = new FromJsonIdentity();
+ }
+ FromJsonCode valueCode = fromJsonCode(type.valueType);
+ if (keyCode.isIdentity && valueCode.isIdentity) {
+ return new FromJsonFunction('jsonDecoder._decodeMap');
+ } else {
+ return new FromJsonSnippet((String jsonPath, String json) {
+ StringBuffer result = new StringBuffer();
+ result.write('jsonDecoder._decodeMap($jsonPath, $json');
+ if (!keyCode.isIdentity) {
+ result.write(', keyDecoder: ${keyCode.asClosure}');
+ }
+ if (!valueCode.isIdentity) {
+ result.write(', valueDecoder: ${valueCode.asClosure}');
+ }
+ result.write(')');
+ return result.toString();
+ });
+ }
+ } else if (type is TypeList) {
+ FromJsonCode itemCode = fromJsonCode(type.itemType);
+ if (itemCode.isIdentity) {
+ return new FromJsonFunction('jsonDecoder._decodeList');
+ } else {
+ return new FromJsonSnippet(
+ (String jsonPath, String json) =>
+ 'jsonDecoder._decodeList($jsonPath, $json, ${itemCode.asClosure})');
+ }
+ } else if (type is TypeUnion) {
+ List<String> decoders = <String>[];
+ for (TypeDecl choice in type.choices) {
+ TypeDecl resolvedChoice = resolveTypeReferenceChain(choice);
+ if (resolvedChoice is TypeObject) {
+ TypeObjectField field = resolvedChoice.getField(type.field);
+ if (field == null) {
+ throw new Exception(
+ 'Each choice in the union needs a field named ${type.field}');
+ }
+ if (field.value == null) {
+ throw new Exception(
+ 'Each choice in the union needs a constant value for the field ${type.field}');
+ }
+ String closure = fromJsonCode(choice).asClosure;
+ decoders.add('${literalString(field.value)}: $closure');
+ } else {
+ throw new Exception('Union types must be unions of objects.');
+ }
+ }
+ return new FromJsonSnippet(
+ (String jsonPath, String json) =>
+ 'jsonDecoder._decodeUnion($jsonPath, $json, ${literalString(type.field)}, {${decoders.join(', ')}})');
+ } else {
+ throw new Exception("Can't convert $type from JSON");
}
- return false;
}
/**
- * Emit the operator== code for an object class.
+ * True if the constructor argument for the given field should be optional.
*/
- void emitObjectEqualsMember(TypeObject type, String className) {
- writeln('@override');
- writeln('bool operator==(other) {');
- indent(() {
- writeln('if (other is $className) {');
- indent(() {
- var comparisons = <String>[];
- if (type != null) {
- for (TypeObjectField field in type.fields) {
- if (field.value != null) {
- continue;
- }
- comparisons.add(
- compareEqualsCode(field.type, field.name, 'other.${field.name}'));
- }
- }
- if (comparisons.isEmpty) {
- writeln('return true;');
- } else {
- String concatenated = comparisons.join(' &&\n ');
- writeln('return $concatenated;');
- }
- });
- writeln('}');
- writeln('return false;');
- });
- writeln('}');
+ bool isOptionalConstructorArg(String className, TypeObjectField field) {
+ if (field.optional) {
+ return true;
+ }
+ List<String> forceOptional = _optionalConstructorArguments[className];
+ if (forceOptional != null && forceOptional.contains(field.name)) {
+ return true;
+ }
+ return false;
}
/**
- * Emit the hashCode getter for an object class.
+ * Create a string literal that evaluates to [s].
*/
- void emitObjectHashCode(TypeObject type, String className) {
- writeln('@override');
- writeln('int get hashCode {');
- indent(() {
- if (type == null) {
- writeln('return ${className.hashCode};');
- } else {
- writeln('int hash = 0;');
- for (TypeObjectField field in type.fields) {
- String valueToCombine;
- if (field.value != null) {
- valueToCombine = field.value.hashCode.toString();
- } else {
- valueToCombine = '${field.name}.hashCode';
- }
- writeln('hash = _JenkinsSmiHash.combine(hash, $valueToCombine);');
- }
- writeln('return _JenkinsSmiHash.finish(hash);');
- }
- });
- writeln('}');
+ String literalString(String s) {
+ return JSON.encode(s);
}
/**
- * Emit a class to encapsulate an enum.
- */
- void emitEnumClass(String className, TypeEnum type, ImpliedType impliedType) {
- docComment(toHtmlVisitor.collectHtml(() {
- toHtmlVisitor.p(() {
- toHtmlVisitor.write(impliedType.humanReadableName);
- });
- if (impliedType.type != null) {
- toHtmlVisitor.showType(null, impliedType.type);
- }
- }));
- writeln('class $className implements Enum {');
- indent(() {
- if (emitSpecialStaticMembers(className)) {
- writeln();
- }
- for (TypeEnumValue value in type.values) {
- docComment(toHtmlVisitor.collectHtml(() {
- toHtmlVisitor.translateHtml(value.html);
- }));
- String valueString = literalString(value.value);
- writeln(
- 'static const ${value.value} = const $className._($valueString);');
- writeln();
- }
- writeln('final String name;');
- writeln();
- writeln('const $className._(this.name);');
- writeln();
- emitEnumClassConstructor(className, type);
- writeln();
- emitEnumFromJsonConstructor(className, type, impliedType);
- writeln();
- if (emitSpecialConstructors(className)) {
- writeln();
- }
- if (emitSpecialGetters(className)) {
- writeln();
- }
- if (emitSpecialMethods(className)) {
- writeln();
- }
- writeln('@override');
- writeln('String toString() => "$className.\$name";');
- writeln();
- writeln('String toJson() => name;');
- });
- writeln('}');
- }
-
- /**
- * Emit the constructor for an enum class.
- */
- void emitEnumClassConstructor(String className, TypeEnum type) {
- writeln('factory $className(String name) {');
- indent(() {
- writeln('switch (name) {');
- indent(() {
- for (TypeEnumValue value in type.values) {
- String valueString = literalString(value.value);
- writeln('case $valueString:');
- indent(() {
- writeln('return ${value.value};');
- });
- }
- });
- writeln('}');
- writeln(r"throw new Exception('Illegal enum value: $name');");
- });
- writeln('}');
- }
-
- /**
- * Compute the code necessary to convert [type] to JSON.
+ * Compute the code necessary to convert [type] to JSON.
*/
ToJsonCode toJsonCode(TypeDecl type) {
TypeDecl resolvedType = resolveTypeReferenceChain(type);
@@ -839,344 +1026,157 @@ class CodegenProtocolVisitor extends DartCodegenVisitor with CodeGenerator {
}
}
+ @override
+ visitApi() {
+ outputHeader();
+ writeln();
+ writeln('part of protocol;');
+ emitClasses();
+ }
+}
+
+/**
+ * Container for code that can be used to translate a data type from JSON.
+ */
+abstract class FromJsonCode {
/**
- * Compute the code necessary to compare two objects for equality.
+ * Get the translation code in the form of a closure.
*/
- String compareEqualsCode(TypeDecl type, String thisVar, String otherVar) {
- TypeDecl resolvedType = resolveTypeReferenceChain(type);
- if (resolvedType is TypeReference ||
- resolvedType is TypeEnum ||
- resolvedType is TypeObject ||
- resolvedType is TypeUnion) {
- return '$thisVar == $otherVar';
- } else if (resolvedType is TypeList) {
- String itemTypeName = dartType(resolvedType.itemType);
- String subComparison = compareEqualsCode(resolvedType.itemType, 'a', 'b');
- String closure = '($itemTypeName a, $itemTypeName b) => $subComparison';
- return '_listEqual($thisVar, $otherVar, $closure)';
- } else if (resolvedType is TypeMap) {
- String valueTypeName = dartType(resolvedType.valueType);
- String subComparison =
- compareEqualsCode(resolvedType.valueType, 'a', 'b');
- String closure = '($valueTypeName a, $valueTypeName b) => $subComparison';
- return '_mapEqual($thisVar, $otherVar, $closure)';
- }
- throw new Exception(
- "Don't know how to compare for equality: $resolvedType");
- }
+ String get asClosure;
/**
- * Emit the method for decoding an object from JSON.
+ * True if the data type is already in JSON form, so the translation is the
+ * identity function.
*/
- void emitObjectFromJsonConstructor(String className, TypeObject type,
- ImpliedType impliedType) {
- String humanReadableNameString =
- literalString(impliedType.humanReadableName);
- if (className == 'RefactoringFeedback') {
- writeln(
- 'factory RefactoringFeedback.fromJson(JsonDecoder jsonDecoder, '
- 'String jsonPath, Object json, Map responseJson) {');
- indent(() {
- writeln(
- 'return _refactoringFeedbackFromJson(jsonDecoder, jsonPath, '
- 'json, responseJson);');
- });
- writeln('}');
- return;
- }
- if (className == 'RefactoringOptions') {
- writeln(
- 'factory RefactoringOptions.fromJson(JsonDecoder jsonDecoder, '
- 'String jsonPath, Object json, RefactoringKind kind) {');
- indent(() {
- writeln(
- 'return _refactoringOptionsFromJson(jsonDecoder, jsonPath, ' 'json, kind);');
- });
- writeln('}');
- return;
- }
- writeln(
- 'factory $className.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {');
- indent(() {
- writeln('if (json == null) {');
- indent(() {
- writeln('json = {};');
- });
- writeln('}');
- writeln('if (json is Map) {');
- indent(() {
- List<String> args = <String>[];
- List<String> optionalArgs = <String>[];
- for (TypeObjectField field in type.fields) {
- String fieldNameString = literalString(field.name);
- String fieldAccessor = 'json[$fieldNameString]';
- String jsonPath = 'jsonPath + ${literalString('.${field.name}')}';
- if (field.value != null) {
- String valueString = literalString(field.value);
- writeln('if ($fieldAccessor != $valueString) {');
- indent(() {
- writeln(
- 'throw jsonDecoder.mismatch(jsonPath, "equal " + $valueString);');
- });
- writeln('}');
- continue;
- }
- if (isOptionalConstructorArg(className, field)) {
- optionalArgs.add('${field.name}: ${field.name}');
- } else {
- args.add(field.name);
- }
- TypeDecl fieldType = field.type;
- String fieldDartType = dartType(fieldType);
- writeln('$fieldDartType ${field.name};');
- writeln('if (json.containsKey($fieldNameString)) {');
- indent(() {
- String fromJson =
- fromJsonCode(fieldType).asSnippet(jsonPath, fieldAccessor);
- writeln('${field.name} = $fromJson;');
- });
- write('}');
- if (!field.optional) {
- writeln(' else {');
- indent(() {
- writeln(
- "throw jsonDecoder.missingKey(jsonPath, $fieldNameString);");
- });
- writeln('}');
- } else {
- writeln();
- }
- }
- args.addAll(optionalArgs);
- writeln('return new $className(${args.join(', ')});');
- });
- writeln('} else {');
- indent(() {
- writeln(
- 'throw jsonDecoder.mismatch(jsonPath, $humanReadableNameString);');
- });
- writeln('}');
- });
- writeln('}');
- }
+ bool get isIdentity;
/**
- * Emit the method for decoding an enum from JSON.
+ * Get the translation code in the form of a code snippet, where [jsonPath]
+ * is the variable holding the JSON path, and [json] is the variable holding
+ * the raw JSON.
*/
- void emitEnumFromJsonConstructor(String className, TypeEnum type,
- ImpliedType impliedType) {
- writeln(
- 'factory $className.fromJson(JsonDecoder jsonDecoder, String jsonPath, Object json) {');
- indent(() {
- writeln('if (json is String) {');
- indent(() {
- writeln('try {');
- indent(() {
- writeln('return new $className(json);');
- });
- writeln('} catch(_) {');
- indent(() {
- writeln('// Fall through');
- });
- writeln('}');
- });
- writeln('}');
- String humanReadableNameString =
- literalString(impliedType.humanReadableName);
- writeln(
- 'throw jsonDecoder.mismatch(jsonPath, $humanReadableNameString);');
- });
- writeln('}');
- }
+ String asSnippet(String jsonPath, String json);
+}
+/**
+ * Representation of FromJsonCode for a function defined elsewhere.
+ */
+class FromJsonFunction extends FromJsonCode {
+ final String asClosure;
+
+ FromJsonFunction(this.asClosure);
+
+ @override
+ bool get isIdentity => false;
+
+ @override
+ String asSnippet(String jsonPath, String json) =>
+ '$asClosure($jsonPath, $json)';
+}
+
+/**
+ * Representation of FromJsonCode for the identity transformation.
+ */
+class FromJsonIdentity extends FromJsonSnippet {
+ FromJsonIdentity() : super((String jsonPath, String json) => json);
+
+ @override
+ bool get isIdentity => true;
+}
+
+/**
+ * Representation of FromJsonCode for a snippet of inline code.
+ */
+class FromJsonSnippet extends FromJsonCode {
/**
- * Compute the code necessary to translate [type] from JSON.
+ * Callback that can be used to generate the code snippet, once the names
+ * of the [jsonPath] and [json] variables are known.
*/
- FromJsonCode fromJsonCode(TypeDecl type) {
- if (type is TypeReference) {
- TypeDefinition referencedDefinition = api.types[type.typeName];
- if (referencedDefinition != null) {
- TypeDecl referencedType = referencedDefinition.type;
- if (referencedType is TypeObject || referencedType is TypeEnum) {
- return new FromJsonSnippet((String jsonPath, String json) {
- String typeName = dartType(type);
- if (typeName == 'RefactoringFeedback') {
- return
- 'new $typeName.fromJson(jsonDecoder, $jsonPath, $json, json)';
- } else if (typeName == 'RefactoringOptions') {
- return
- 'new $typeName.fromJson(jsonDecoder, $jsonPath, $json, kind)';
- } else {
- return 'new $typeName.fromJson(jsonDecoder, $jsonPath, $json)';
- }
- });
- } else {
- return fromJsonCode(referencedType);
- }
- } else {
- switch (type.typeName) {
- case 'String':
- return new FromJsonFunction('jsonDecoder._decodeString');
- case 'bool':
- return new FromJsonFunction('jsonDecoder._decodeBool');
- case 'int':
- case 'long':
- return new FromJsonFunction('jsonDecoder._decodeInt');
- case 'object':
- return new FromJsonIdentity();
- default:
- throw new Exception('Unexpected type name ${type.typeName}');
- }
- }
- } else if (type is TypeMap) {
- FromJsonCode keyCode;
- if (dartType(type.keyType) != 'String') {
- keyCode = fromJsonCode(type.keyType);
- } else {
- keyCode = new FromJsonIdentity();
- }
- FromJsonCode valueCode = fromJsonCode(type.valueType);
- if (keyCode.isIdentity && valueCode.isIdentity) {
- return new FromJsonFunction('jsonDecoder._decodeMap');
- } else {
- return new FromJsonSnippet((String jsonPath, String json) {
- StringBuffer result = new StringBuffer();
- result.write('jsonDecoder._decodeMap($jsonPath, $json');
- if (!keyCode.isIdentity) {
- result.write(', keyDecoder: ${keyCode.asClosure}');
- }
- if (!valueCode.isIdentity) {
- result.write(', valueDecoder: ${valueCode.asClosure}');
- }
- result.write(')');
- return result.toString();
- });
- }
- } else if (type is TypeList) {
- FromJsonCode itemCode = fromJsonCode(type.itemType);
- if (itemCode.isIdentity) {
- return new FromJsonFunction('jsonDecoder._decodeList');
- } else {
- return new FromJsonSnippet(
- (String jsonPath, String json) =>
- 'jsonDecoder._decodeList($jsonPath, $json, ${itemCode.asClosure})');
- }
- } else if (type is TypeUnion) {
- List<String> decoders = <String>[];
- for (TypeDecl choice in type.choices) {
- TypeDecl resolvedChoice = resolveTypeReferenceChain(choice);
- if (resolvedChoice is TypeObject) {
- TypeObjectField field = resolvedChoice.getField(type.field);
- if (field == null) {
- throw new Exception(
- 'Each choice in the union needs a field named ${type.field}');
- }
- if (field.value == null) {
- throw new Exception(
- 'Each choice in the union needs a constant value for the field ${type.field}');
- }
- String closure = fromJsonCode(choice).asClosure;
- decoders.add('${literalString(field.value)}: $closure');
- } else {
- throw new Exception('Union types must be unions of objects.');
- }
- }
- return new FromJsonSnippet(
- (String jsonPath, String json) =>
- 'jsonDecoder._decodeUnion($jsonPath, $json, ${literalString(type.field)}, {${decoders.join(', ')}})');
- } else {
- throw new Exception("Can't convert $type from JSON");
- }
- }
+ final FromJsonSnippetCallback callback;
+
+ FromJsonSnippet(this.callback);
+
+ @override
+ String get asClosure =>
+ '(String jsonPath, Object json) => ${callback('jsonPath', 'json')}';
+ @override
+ bool get isIdentity => false;
+
+ @override
+ String asSnippet(String jsonPath, String json) => callback(jsonPath, json);
+}
+
+/**
+ * Container for code that can be used to translate a data type to JSON.
+ */
+abstract class ToJsonCode {
/**
- * Emit a convenience constructor for decoding a piece of protocol, if
- * appropriate. Return true if a constructor was emitted.
+ * Get the translation code in the form of a closure.
*/
- bool emitConvenienceConstructor(String className, ImpliedType impliedType) {
- // The type of object from which this piece of protocol should be decoded.
- String inputType;
- // The name of the input object.
- String inputName;
- // The field within the input object to decode.
- String fieldName;
- // Constructor call to create the JsonDecoder object.
- String makeDecoder;
- // Name of the constructor to create.
- String constructorName;
- // Extra arguments for the constructor.
- List<String> extraArgs = <String>[];
- switch (impliedType.kind) {
- case 'requestParams':
- inputType = 'Request';
- inputName = 'request';
- fieldName = '_params';
- makeDecoder = 'new RequestDecoder(request)';
- constructorName = 'fromRequest';
- break;
- case 'requestResult':
- inputType = 'Response';
- inputName = 'response';
- fieldName = '_result';
- makeDecoder =
- 'new ResponseDecoder(REQUEST_ID_REFACTORING_KINDS.remove(response.id))';
- constructorName = 'fromResponse';
- break;
- case 'notificationParams':
- inputType = 'Notification';
- inputName = 'notification';
- fieldName = '_params';
- makeDecoder = 'new ResponseDecoder(null)';
- constructorName = 'fromNotification';
- break;
- case 'refactoringOptions':
- inputType = 'EditGetRefactoringParams';
- inputName = 'refactoringParams';
- fieldName = 'options';
- makeDecoder = 'new RequestDecoder(request)';
- constructorName = 'fromRefactoringParams';
- extraArgs.add('Request request');
- break;
- default:
- return false;
- }
- List<String> args = ['$inputType $inputName'];
- args.addAll(extraArgs);
- writeln('factory $className.$constructorName(${args.join(', ')}) {');
- indent(() {
- String fieldNameString =
- literalString(fieldName.replaceFirst(new RegExp('^_'), ''));
- if (className == 'EditGetRefactoringParams') {
- writeln('var params = new $className.fromJson(');
- writeln(' $makeDecoder, $fieldNameString, $inputName.$fieldName);');
- writeln('REQUEST_ID_REFACTORING_KINDS[request.id] = params.kind;');
- writeln('return params;');
- } else {
- writeln('return new $className.fromJson(');
- writeln(' $makeDecoder, $fieldNameString, $inputName.$fieldName);');
- }
- });
- writeln('}');
- return true;
- }
+ String get asClosure;
/**
- * Create a string literal that evaluates to [s].
+ * True if the data type is already in JSON form, so the translation is the
+ * identity function.
*/
- String literalString(String s) {
- return JSON.encode(s);
- }
+ bool get isIdentity;
+
+ /**
+ * Get the translation code in the form of a code snippet, where [value]
+ * is the variable holding the object to be translated.
+ */
+ String asSnippet(String value);
}
-final GeneratedFile target =
- new GeneratedFile('../../lib/src/generated_protocol.dart', () {
- CodegenProtocolVisitor visitor = new CodegenProtocolVisitor(readApi());
- return visitor.collectCode(visitor.visitApi);
-});
+/**
+ * Representation of ToJsonCode for a function defined elsewhere.
+ */
+class ToJsonFunction extends ToJsonCode {
+ final String asClosure;
+
+ ToJsonFunction(this.asClosure);
+
+ @override
+ bool get isIdentity => false;
+
+ @override
+ String asSnippet(String value) => '$asClosure($value)';
+}
/**
- * Translate spec_input.html into protocol_matchers.dart.
+ * Representation of FromJsonCode for the identity transformation.
*/
-main() {
- target.generate();
+class ToJsonIdentity extends ToJsonSnippet {
+ ToJsonIdentity(String type) : super(type, (String value) => value);
+
+ @override
+ bool get isIdentity => true;
+}
+
+/**
+ * Representation of ToJsonCode for a snippet of inline code.
+ */
+class ToJsonSnippet extends ToJsonCode {
+ /**
+ * Callback that can be used to generate the code snippet, once the name
+ * of the [value] variable is known.
+ */
+ final ToJsonSnippetCallback callback;
+
+ /**
+ * Dart type of the [value] variable.
+ */
+ final String type;
+
+ ToJsonSnippet(this.type, this.callback);
+
+ @override
+ String get asClosure => '($type value) => ${callback('value')}';
+
+ @override
+ bool get isIdentity => false;
+
+ @override
+ String asSnippet(String value) => callback(value);
}
« no previous file with comments | « pkg/analysis_server/tool/spec/codegen_dart.dart ('k') | pkg/analysis_server/tool/spec/codegen_inttest_methods.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698