Index: pkg/analysis_server/lib/src/protocol2.dart |
diff --git a/pkg/analysis_server/lib/src/protocol2.dart b/pkg/analysis_server/lib/src/protocol2.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..755f8fa399a22fae364a4d524b0f3267dba0aab4 |
--- /dev/null |
+++ b/pkg/analysis_server/lib/src/protocol2.dart |
@@ -0,0 +1,232 @@ |
+// 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. |
+ |
+library protocol2; |
+ |
+import 'dart:convert'; |
+ |
+import 'protocol.dart'; |
+ |
+part 'generated_protocol.dart'; |
+ |
+/** |
+ * Translate the input [map], applying [keyCallback] to all its keys, and |
+ * [valueCallback] to all its values. |
+ */ |
+_mapMap(Map map, {dynamic keyCallback(key), dynamic valueCallback(value)}) { |
+ Map result = {}; |
+ map.forEach((key, value) { |
+ if (keyCallback != null) { |
+ key = keyCallback(key); |
+ } |
+ if (valueCallback != null) { |
+ value = valueCallback(value); |
+ } |
+ result[key] = value; |
+ }); |
+ return result; |
+} |
+ |
+/** |
+ * Jenkins hash function, optimized for small integers. Borrowed from |
+ * sdk/lib/math/jenkins_smi_hash.dart. |
+ * |
+ * TODO(paulberry): Move to somewhere that can be shared with other code. |
+ */ |
+class _JenkinsSmiHash { |
+ static int combine(int hash, int value) { |
+ hash = 0x1fffffff & (hash + value); |
+ hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10)); |
+ return hash ^ (hash >> 6); |
+ } |
+ |
+ static int finish(int hash) { |
+ hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3)); |
+ hash = hash ^ (hash >> 11); |
+ return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); |
+ } |
+ |
+ static int hash2(a, b) => finish(combine(combine(0, a), b)); |
+ |
+ static int hash4(a, b, c, d) => |
+ finish(combine(combine(combine(combine(0, a), b), c), d)); |
+} |
+ |
+ |
+/** |
+ * Type of callbacks used to decode parts of JSON objects. [jsonPath] is a |
+ * string describing the part of the JSON object being decoded, and [value] is |
+ * the part to decode. |
+ */ |
+typedef Object JsonDecoderCallback(String jsonPath, Object value); |
+ |
+/** |
+ * Base class for decoding JSON objects. The derived class must implement |
+ * error reporting logic. |
+ */ |
+abstract class JsonDecoderBase { |
+ /** |
+ * Create an exception to throw if the JSON object at [jsonPath] is missing |
+ * the key [key]. |
+ */ |
+ dynamic missingKey(String jsonPath, String key); |
+ |
+ /** |
+ * Create an exception to throw if the JSON object at [jsonPath] fails to |
+ * match the API definition of [expected]. |
+ */ |
+ dynamic mismatch(String jsonPath, String expected); |
+ |
+ /** |
+ * Decode a JSON object that is expected to be a Map. [keyDecoder] is used |
+ * to decode the keys, and [valueDecoder] is used to decode the values. |
+ */ |
+ Map _decodeMap(String jsonPath, Object json, {JsonDecoderCallback keyDecoder, |
+ JsonDecoderCallback valueDecoder}) { |
+ if (json == null) { |
+ return {}; |
+ } else if (json is Map) { |
+ Map result = {}; |
+ json.forEach((String key, value) { |
+ Object decodedKey; |
+ if (keyDecoder != null) { |
+ decodedKey = keyDecoder('$jsonPath.key', key); |
+ } else { |
+ decodedKey = key; |
+ } |
+ if (valueDecoder != null) { |
+ value = valueDecoder('$jsonPath[${JSON.encode(key)}]', value); |
+ } |
+ result[decodedKey] = value; |
+ }); |
+ return result; |
+ } else { |
+ throw mismatch(jsonPath, 'Map'); |
+ } |
+ } |
+ |
+ /** |
+ * Decode a JSON object that is expected to be a List. [decoder] is used to |
+ * decode the items in the list. |
+ */ |
+ List _decodeList(String jsonPath, Object json, [JsonDecoderCallback decoder]) { |
+ if (json == null) { |
+ return []; |
+ } else if (json is List) { |
+ List result = []; |
+ for (int i = 0; i < json.length; i++) { |
+ result.add(decoder('$jsonPath[$i]', json[i])); |
+ } |
+ return result; |
+ } else { |
+ throw mismatch(jsonPath, 'List'); |
+ } |
+ } |
+ |
+ /** |
+ * Decode a JSON object that is expected to be a string. |
+ */ |
+ String _decodeString(String jsonPath, Object json) { |
+ if (json is String) { |
+ return json; |
+ } else { |
+ throw mismatch(jsonPath, 'String'); |
+ } |
+ } |
+ |
+ /** |
+ * Decode a JSON object that is expected to be a boolean. The strings "true" |
+ * and "false" are also accepted. |
+ */ |
+ bool _decodeBool(String jsonPath, Object json) { |
danrubel
2014/08/17 17:10:21
Do you want to sort the class memebers via cmd-1 -
Paul Berry
2014/08/18 21:58:03
Done.
|
+ if (json is bool) { |
+ return json; |
+ } else if (json == 'true') { |
+ return true; |
+ } else if (json == 'false') { |
+ return false; |
+ } |
+ throw mismatch(jsonPath, 'bool'); |
+ } |
+ |
+ /** |
+ * Decode a JSON object that is expected to be an integer. A string |
+ * representation of an integer is also accepted. |
+ */ |
+ int _decodeInt(String jsonPath, Object json) { |
+ if (json is int) { |
+ return json; |
+ } else if (json is String) { |
+ return int.parse(json, onError: (String value) { |
+ throw mismatch(jsonPath, 'int'); |
+ }); |
+ } |
+ throw mismatch(jsonPath, 'int'); |
+ } |
+ |
+ /** |
+ * Decode a JSON object that is expected to be one of several choices, |
+ * where the choices are disambiguated by the contents of the field [field]. |
+ * [decoders] is a map from each possible string in the field to the decoder |
+ * that should be used to decode the JSON object. |
+ */ |
+ Object _decodeUnion(String jsonPath, Map json, String field, |
+ Map<String, JsonDecoderCallback> decoders) { |
+ if (json is Map) { |
+ if (!json.containsKey(field)) { |
+ throw missingKey(jsonPath, field); |
+ } |
+ var disambiguatorPath = '$jsonPath[${JSON.encode(field)}]'; |
+ String disambiguator = _decodeString(disambiguatorPath, |
+ json[field]); |
+ if (!decoders.containsKey(disambiguator)) { |
+ throw mismatch(disambiguatorPath, 'One of: ${decoders.keys.toList()}'); |
+ } |
+ return decoders[disambiguator](jsonPath, json); |
+ } else { |
+ throw mismatch(jsonPath, 'Map'); |
+ } |
+ } |
+} |
+ |
+/** |
+ * JsonDecoder for decoding requests. Errors are reporting by throwing a |
+ * [RequestFailure]. |
+ */ |
+class RequestDecoder extends JsonDecoder { |
+ /** |
+ * The request being deserialized. |
+ */ |
+ final Request _request; |
+ |
+ RequestDecoder(this._request); |
+ |
+ @override |
+ dynamic mismatch(String jsonPath, String expected) { |
+ return new RequestFailure(new Response.invalidParameter(_request, jsonPath, |
+ 'be $expected')); |
+ } |
+ |
+ @override |
+ dynamic missingKey(String jsonPath, String key) { |
+ return new RequestFailure(new Response.invalidParameter(_request, jsonPath, |
+ 'contain key ${JSON.encode(key)}')); |
+ } |
+} |
+ |
+/** |
+ * JsonDecoder for decoding responses from the server. This is intended to be |
+ * used only for testing. Errors are reported using bare [Exception] objects. |
+ */ |
+class ResponseDecoder extends JsonDecoder { |
+ @override |
+ dynamic mismatch(String jsonPath, String expected) { |
+ return new Exception('Expected $expected at $jsonPath'); |
+ } |
+ |
+ @override |
+ dynamic missingKey(String jsonPath, String key) { |
+ return new Exception('Missing key $key at $jsonPath'); |
+ } |
+} |