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

Unified Diff: pkg/analysis_server/spec/codegen_matchers.dart

Issue 443873006: Add analysis server API specification and related tools. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: 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 side-by-side diff with in-line comments
Download patch
Index: pkg/analysis_server/spec/codegen_matchers.dart
diff --git a/pkg/analysis_server/spec/codegen_matchers.dart b/pkg/analysis_server/spec/codegen_matchers.dart
new file mode 100644
index 0000000000000000000000000000000000000000..ed3665db50b67471b8be5b800b1345a45a87f3a4
--- /dev/null
+++ b/pkg/analysis_server/spec/codegen_matchers.dart
@@ -0,0 +1,195 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * Code generation for the file "matchers.dart".
+ */
+library CodegenMatchers;
scheglov 2014/08/06 18:20:39 AFAIK library names should be all lower case with
Paul Berry 2014/08/06 18:32:43 Done.
+
+import 'dart:convert';
+import 'dart:io';
+
+import 'api.dart';
+import 'codegen_tools.dart';
+import 'from_html.dart';
+import 'to_html.dart';
+
+class CodegenMatchersVisitor extends HierarchicalApiVisitor with CodeGenerator {
+ /**
+ * Visitor used to produce doc comments.
+ */
+ final ToHtmlVisitor toHtmlVisitor;
+
+ /**
+ * Short human-readable string describing the context of the matcher being
+ * created.
+ */
+ String context;
+
+ CodegenMatchersVisitor(Api api)
+ : super(api),
+ toHtmlVisitor = new ToHtmlVisitor(api);
+
+ /**
+ * Create a matcher for the part of the API called [name], optionally
+ * clarified by [nameSuffix]. The matcher should verify that its input
+ * matches the given [type].
+ */
+ void makeMatcher(String name, String nameSuffix, TypeDecl type) {
+ context = name;
+ List<String> nameParts = ['is'];
+ nameParts.addAll(name.split('.'));
+ if (nameSuffix != null) {
+ context += ' $nameSuffix';
+ nameParts.add(nameSuffix);
+ }
+ docComment(toHtmlVisitor.collectHtml(() {
+ toHtmlVisitor.p(() {
+ toHtmlVisitor.write(context);
+ });
+ if (type != null) {
+ toHtmlVisitor.showType(null, type);
+ }
+ }), false);
+ write('final Matcher ${camelJoin(nameParts)} = ');
+ if (type == null) {
+ write('isNull');
+ } else {
+ visitTypeDecl(type);
+ }
+ writeln(';');
+ writeln();
+ }
+
+ @override
+ visitApi() {
+ outputHeader();
+ writeln('/**');
+ writeln(' * Matchers for data types defined in the analysis server API');
+ writeln(' */');
+ writeln('library test.integration.protocol.matchers;');
+ writeln();
+ writeln("import 'package:unittest/unittest.dart';");
+ writeln();
+ writeln("import 'integration_tests.dart';");
+ writeln();
+ writeln();
+ super.visitApi();
+ }
+
+ @override
+ visitNotification(Notification notification) {
+ makeMatcher(notification.longEvent, 'params', notification.params);
+ }
+
+ @override
+ visitRequest(Request request) {
+ makeMatcher(request.longMethod, 'params', request.params);
+ makeMatcher(request.longMethod, 'result', request.result);
+ }
+
+ @override
+ visitRefactoring(Refactoring refactoring) {
+ String camelKind = camelJoin(refactoring.kind.toLowerCase().split('_'));
+ makeMatcher(camelKind, 'feedback', refactoring.feedback);
+ makeMatcher(camelKind, 'options', refactoring.options);
+ }
+
+ @override
+ visitTypeDefinition(TypeDefinition typeDefinition) {
+ makeMatcher(typeDefinition.name, null, typeDefinition.type);
+ }
+
+ @override
+ visitTypeEnum(TypeEnum typeEnum) {
+ writeln('isIn([');
+ indent(() {
+ bool commaNeeded = false;
+ for (TypeEnumValue value in typeEnum.values) {
+ if (commaNeeded) {
+ writeln(',');
+ }
+ write('${JSON.encode(value.value)}');
+ commaNeeded = true;
+ }
+ writeln();
+ });
+ write('])');
+ }
+
+ @override
+ visitTypeList(TypeList typeList) {
+ write('isListOf(');
+ visitTypeDecl(typeList.itemType);
+ write(')');
+ }
+
+ @override
+ visitTypeMap(TypeMap typeMap) {
+ write('isMapOf(');
+ visitTypeDecl(typeMap.keyType);
+ write(', ');
+ visitTypeDecl(typeMap.valueType);
+ write(')');
+ }
+
+ @override
+ void visitTypeObject(TypeObject typeObject) {
+ writeln('new MatchesJsonObject(');
+ indent(() {
+ write('${JSON.encode(context)}, ');
+ Iterable<TypeObjectField> requiredFields = typeObject.fields.where(
+ (TypeObjectField field) => !field.optional);
+ outputObjectFields(requiredFields);
+ List<TypeObjectField> optionalFields = typeObject.fields.where(
+ (TypeObjectField field) => field.optional).toList();
+ if (optionalFields.isNotEmpty) {
+ write(', optionalFields: ');
+ outputObjectFields(optionalFields);
+ }
+ });
+ write(')');
+ }
+
+ /**
+ * Generate a map describing the given set of fields, for use as the
+ * 'requiredFields' or 'optionalFields' argument to the [MatchesJsonObject]
+ * constructor.
+ */
+ void outputObjectFields(Iterable<TypeObjectField> fields) {
+ if (fields.isEmpty) {
+ write('null');
+ return;
+ }
+ writeln('{');
+ indent(() {
+ bool commaNeeded = false;
+ for (TypeObjectField field in fields) {
+ if (commaNeeded) {
+ writeln(',');
+ }
+ write('${JSON.encode(field.name)}: ');
+ visitTypeDecl(field.type);
+ commaNeeded = true;
+ }
+ writeln();
+ });
+ write('}');
+ }
+
+ @override
+ void visitTypeReference(TypeReference typeReference) {
+ write(camelJoin(['is', typeReference.typeName]));
+ }
+}
+
+/**
+ * Translate spec_input.html into protocol_matchers.dart.
+ */
+main() {
+ CodegenMatchersVisitor visitor = new CodegenMatchersVisitor(readApi());
+ String code = visitor.collectCode(visitor.visitApi);
+ File outputFile = new File('../test/integration/protocol_matchers.dart');
+ outputFile.writeAsStringSync(code);
+}

Powered by Google App Engine
This is Rietveld 408576698