From 5c6e3ef1f8d9129bd7577c6df28a26e85603b771 Mon Sep 17 00:00:00 2001
From: David Malcolm <dmalcolm@redhat.com>
Date: Mon, 22 May 2017 16:47:11 -0400
Subject: [PATCH 29/31] FIXME: json.c cleanups

---
 gcc/json.c | 397 ++++++++++++++++++++++++++++++++++++++++++++++++++++---------
 gcc/json.h |  44 +++++--
 gcc/lsp.c  |   2 +-
 3 files changed, 379 insertions(+), 64 deletions(-)

diff --git a/gcc/json.c b/gcc/json.c
index 5cd06d5..c9b3d97 100644
--- a/gcc/json.c
+++ b/gcc/json.c
@@ -26,7 +26,9 @@ along with GCC; see the file COPYING3.  If not see
 
 using namespace json;
 
-/* Implemenation.  */
+/* class json::value.  */
+
+/* FIXME.  */
 
 char *
 value::to_str () const
@@ -36,6 +38,8 @@ value::to_str () const
   return xstrdup (pp_formatted_text (&pp));
 }
 
+/* FIXME.  */
+
 void
 value::dump (FILE *outf) const
 {
@@ -45,6 +49,8 @@ value::dump (FILE *outf) const
   pp_flush (&pp);
 }
 
+/* FIXME.  */
+
 const object *
 value::as_object () const
 {
@@ -53,6 +59,8 @@ value::as_object () const
   return static_cast <const object *> (this);
 }
 
+/* FIXME.  */
+
 const array *
 value::as_array () const
 {
@@ -61,6 +69,8 @@ value::as_array () const
   return static_cast <const array *> (this);
 }
 
+/* FIXME.  */
+
 const number *
 value::as_number () const
 {
@@ -69,6 +79,8 @@ value::as_number () const
   return static_cast <const number *> (this);
 }
 
+/* FIXME.  */
+
 const string *
 value::as_string () const
 {
@@ -77,7 +89,12 @@ value::as_string () const
   return static_cast <const string *> (this);
 }
 
-/* FIXME.  */
+/* Attempt to get lookup the value of a key/value pair from this value
+   as if it is an object.
+
+   On success, return true and write the value to OUT_VALUE.
+   On failure, return false and write an error message to OUT_ERR
+   (which must be freed by the caller).  */
 
 bool
 value::get_value_by_key (const char *name, const value *&out_value,
@@ -99,7 +116,8 @@ value::get_value_by_key (const char *name, const value *&out_value,
   return true;
 }
 
-/* FIXME.  */
+/* As value::get_value_by_key, but the value must be a number;
+   if successful, write it as an int to OUT_VALUE.  */
 
 bool
 value::get_int_by_key (const char *name, int &out_value, char *&out_err) const
@@ -117,7 +135,8 @@ value::get_int_by_key (const char *name, int &out_value, char *&out_err) const
   return true;
 }
 
-/* FIXME.  */
+/* As value::get_value_by_key, but the value must be a string;
+   if successful, write it as const char * to OUT_VALUE.  */
 
 bool
 value::get_string_by_key (const char *name, const char *&out_value,
@@ -136,6 +155,10 @@ value::get_string_by_key (const char *name, const char *&out_value,
   return true;
 }
 
+/* class json::object, a subclass of json::value.  */
+
+/* json:object's dtor.  */
+
 object::~object ()
 {
   for (map_t::iterator it = m_map.begin (); it != m_map.end (); ++it)
@@ -145,6 +168,8 @@ object::~object ()
     }
 }
 
+/* Implementation of json::value::print for json::object.  */
+
 void
 object::print (pretty_printer *pp) const
 {
@@ -162,12 +187,23 @@ object::print (pretty_printer *pp) const
   pp_character (pp, '}');
 }
 
+/* Implementation of json::value::clone for json::object.  */
+
 value *
 object::clone () const
 {
-  gcc_unreachable (); // FIXME
+  object *other = new object ();
+  for (map_t::iterator it = m_map.begin (); it != m_map.end (); ++it)
+    {
+      const char *key = const_cast <char *>((*it).first);
+      value *value = (*it).second;
+      other->set (key, value->clone ());
+    }
+  return other;
 }
 
+/* Get the json::value * for KEY, or NULL if the key is not present.  */
+
 value *
 object::get (const char *key) const
 {
@@ -177,7 +213,8 @@ object::get (const char *key) const
   return NULL;
 }
 
-/* Takes ownership of KEY and VALUE.  */
+/* Set the json::value * for KEY, taking ownership of VALUE
+   (and taking a copy of KEY).  */
 
 void
 object::set (const char *key, value *v)
@@ -185,6 +222,10 @@ object::set (const char *key, value *v)
   m_map.put (xstrdup (key), v);
 }
 
+/* class json::array, a subclass of json::value.  */
+
+/* json::array's dtor.  */
+
 array::~array ()
 {
   unsigned i;
@@ -193,6 +234,8 @@ array::~array ()
     delete v;
 }
 
+/* Implementation of json::value::print for json::array.  */
+
 void
 array::print (pretty_printer *pp) const
 {
@@ -208,6 +251,8 @@ array::print (pretty_printer *pp) const
   pp_character (pp, ']');
 }
 
+/* Implementation of json::value::clone for json::array.  */
+
 value *
 array::clone () const
 {
@@ -219,18 +264,26 @@ array::clone () const
   return other;
 }
 
+/* class json::number, a subclass of json::value.  */
+
+/* Implementation of json::value::print for json::number.  */
+
 void
 number::print (pretty_printer *pp) const
 {
   pp_printf (pp, "%i", (int)m_value); // FIXME
 }
 
+/* Implementation of json::value::clone for json::number.  */
+
 value *
 number::clone () const
 {
   return new number (m_value);
 }
 
+/* class json::string, a subclass of json::value.  */
+
 void
 string::print (pretty_printer *pp) const
 {
@@ -256,30 +309,56 @@ string::print (pretty_printer *pp) const
   pp_character (pp, '"');
 }
 
+/* Implementation of json::value::clone for json::string.  */
+
 value *
 string::clone () const
 {
   return new string (m_utf8);
 }
 
+/* class json::literal, a subclass of json::value.  */
+
+/* Implementation of json::value::print for json::literal.  */
+
 void
 literal::print (pretty_printer *pp) const
 {
-  pp_string (pp, "FIXME"); // FIXME
+  switch (m_kind)
+    {
+    case JSON_TRUE:
+      pp_string (pp, "true");
+      break;
+    case JSON_FALSE:
+      pp_string (pp, "false");
+      break;
+    case JSON_NULL:
+      pp_string (pp, "null");
+      break;
+    default:
+      gcc_unreachable ();
+    }
 }
 
+/* Implementation of json::value::clone for json::literal.  */
+
 value *
 literal::clone () const
 {
-  gcc_unreachable (); // FIXME
+  return new literal (m_kind);
 }
 
-/* Parsing decls.  */
+/* Declarations relating to parsing JSON, all within an
+   anonymous namespace.  */
+
+namespace {
 
-namespace json {
+/* FIXME.  */
 
 typedef unsigned unichar;
 
+/* FIXME.  */
+
 enum token_id
 {
   TOK_ERROR,
@@ -303,6 +382,8 @@ enum token_id
   TOK_NUMBER
 };
 
+/* FIXME.  */
+
 static const char *token_id_name[] = {
   "error",
   "EOF",
@@ -319,11 +400,12 @@ static const char *token_id_name[] = {
   "number"
 };
 
+/* FIXME.  */
+
 struct token
 {
   enum token_id id;
   int index;
-  int length;
   union
   {
     char *string;
@@ -331,11 +413,13 @@ struct token
   } u;
 };
 
+/* A class for lexing JSON.  */
+
 class lexer
 {
  public:
   lexer ();
-  void add_utf8 (size_t sz, const char *utf8_buf);
+  void add_utf8 (size_t length, const char *utf8_buf);
 
   const token *peek ();
   void consume ();
@@ -347,6 +431,7 @@ class lexer
   void lex_token (token *out);
   void lex_string (token *out);
   void lex_number (token *out, unichar first_char);
+  bool rest_of_literal_p (const char *suffix) const;
 
  private:
   auto_vec<unichar> m_buffer;
@@ -357,11 +442,13 @@ class lexer
   int m_num_next_tokens;
 };
 
+/* A class for parsing JSON.  */
+
 class parser
 {
  public:
   parser (char **err_out);
-  void add_utf8 (size_t sz, const char *utf8_buf);
+  void add_utf8 (size_t length, const char *utf8_buf);
   value *parse_value ();
   object *parse_object ();
   array *parse_array ();
@@ -377,17 +464,19 @@ class parser
   char **m_err_out;
 };
 
-} // namespace json
+} // anonymous namespace for parsing implementation
 
 /* Parser implementation.  */
 
-using namespace json;
+/* FIXME.  */
 
 lexer::lexer ()
 : m_buffer (), m_next_char_idx (0), m_num_next_tokens (0)
 {
 }
 
+/* FIXME.  */
+
 const token *
 lexer::peek ()
 {
@@ -399,6 +488,8 @@ lexer::peek ()
   return &m_next_tokens[0];
 }
 
+/* FIXME.  */
+
 void
 lexer::consume ()
 {
@@ -423,14 +514,18 @@ lexer::consume ()
 	   sizeof (token) * m_num_next_tokens);
 }
 
+/* FIXME.  */
+
 void
-lexer::add_utf8 (size_t sz, const char *utf8_buf)
+lexer::add_utf8 (size_t length, const char *utf8_buf)
 {
   // FIXME: this assumes Latin-1.
-  for (size_t i = 0; i < sz; i++)
+  for (size_t i = 0; i < length; i++)
     m_buffer.safe_push (utf8_buf[i]);
 }
 
+/* FIXME.  */
+
 bool
 lexer::get_char (unichar &out)
 {
@@ -441,12 +536,16 @@ lexer::get_char (unichar &out)
   return true;
 }
 
+/* FIXME.  */
+
 void
 lexer::unget_char ()
 {
   --m_next_char_idx;
 }
 
+/* FIXME.  */
+
 void
 lexer::dump_token (FILE *outf, const token *tok)
 {
@@ -510,6 +609,8 @@ lexer::dump_token (FILE *outf, const token *tok)
     }
 }
 
+/* FIXME.  */
+
 void
 lexer::lex_token (token *out)
 {
@@ -521,7 +622,6 @@ lexer::lex_token (token *out)
       if (!get_char (next_char))
 	{
 	  out->id = TOK_EOF;
-	  out->length = 1;
 	  return;
 	}
       if (next_char != ' ' && next_char != '\t')
@@ -532,32 +632,26 @@ lexer::lex_token (token *out)
     {
     case '[':
       out->id = TOK_OPEN_SQUARE;
-      out->length = 1;
       break;
 
     case '{':
       out->id = TOK_OPEN_CURLY;
-      out->length = 1;
       break;
 
     case ']':
       out->id = TOK_CLOSE_SQUARE;
-      out->length = 1;
       break;
 
     case '}':
       out->id = TOK_CLOSE_CURLY;
-      out->length = 1;
       break;
 
     case ':':
       out->id = TOK_COLON;
-      out->length = 1;
       break;
 
     case ',':
       out->id = TOK_COMMA;
-      out->length = 1;
       break;
 
     case '"':
@@ -578,14 +672,45 @@ lexer::lex_token (token *out)
       lex_number (out, next_char);
       break;
 
+    case 't':
+      /* Handle literal "true".  */
+      if (rest_of_literal_p ("rue"))
+	{
+	  out->id = TOK_TRUE;
+	  break;
+	}
+      else
+	goto err;
+
+    case 'f':
+      /* Handle literal "false".  */
+      if (rest_of_literal_p ("alse"))
+	{
+	  out->id = TOK_FALSE;
+	  break;
+	}
+      else
+	goto err;
+
+    case 'n':
+      /* Handle literal "null".  */
+      if (rest_of_literal_p ("ull"))
+	{
+	  out->id = TOK_NULL;
+	  break;
+	}
+      else
+	goto err;
+
+    err:
     default:
-      //error ();
       out->id = TOK_ERROR;
-      out->length = 1;
       break;
     }
 }
 
+/* FIXME.  */
+
 void
 lexer::lex_string (token *out)
 {
@@ -610,7 +735,6 @@ lexer::lex_string (token *out)
 	    if (!get_char (next_char))
 	      {
 		out->id = TOK_ERROR;
-		out->length = 1;
 		return;
 	      }
 	    switch (next_char)
@@ -624,7 +748,6 @@ lexer::lex_string (token *out)
 
 	      default:
 		out->id = TOK_ERROR;
-		out->length = 1;
 		return;
 	      }
 	  }
@@ -645,10 +768,10 @@ lexer::lex_string (token *out)
   out->u.string[content.length ()] = '\0';
 
   // FIXME: leaks?  have a json_context do the allocation
-
-  //out->length = out->m_next_char_idx;
 }
 
+/* FIXME.  */
+
 void
 lexer::lex_number (token *out, unichar first_char)
 {
@@ -687,6 +810,27 @@ lexer::lex_number (token *out, unichar first_char)
   out->u.number = value;
 }
 
+/* Determine if the next characters to be lexed match SUFFIX.  */
+
+bool
+lexer::rest_of_literal_p (const char *suffix) const
+{
+  int suffix_idx = 0;
+  int buf_idx = m_next_char_idx;
+  while (1)
+    {
+      if (suffix[suffix_idx] == '\0')
+	return true;
+      /* FIXME: this assumes ASCII.  */
+      if (m_buffer[buf_idx] != (unichar)suffix[suffix_idx])
+	return false;
+      buf_idx++;
+      suffix_idx++;
+    }
+}
+
+/* FIXME.  */
+
 parser::parser (char **err_out)
 : m_lexer (), m_err_out (err_out)
 {
@@ -695,37 +839,71 @@ parser::parser (char **err_out)
   *err_out = NULL;
 }
 
+/* FIXME.  */
+
 void
-parser::add_utf8 (size_t sz, const char *utf8_buf)
+parser::add_utf8 (size_t length, const char *utf8_buf)
 {
-  m_lexer.add_utf8 (sz, utf8_buf);
+  m_lexer.add_utf8 (length, utf8_buf);
 }
 
+/* FIXME.  */
+
 value *
 parser::parse_value ()
 {
   const token *tok = m_lexer.peek ();
-  if (tok->id == TOK_OPEN_CURLY)
-    return parse_object ();
-  else if (tok->id == TOK_STRING)
-    {
-      string *result = new string (tok->u.string);
-      m_lexer.consume ();
-      return result;
-    }
-  else if (tok->id == TOK_OPEN_SQUARE)
-    return parse_array ();
-  else if (tok->id == TOK_NUMBER)
+  switch (tok->id)
     {
-      number *result = new number (tok->u.number);
-      m_lexer.consume ();
-      return result;
-    }
+    case TOK_OPEN_CURLY:
+      return parse_object ();
+
+    case TOK_STRING:
+      {
+	string *result = new string (tok->u.string);
+	m_lexer.consume ();
+	return result;
+      }
+
+    case TOK_OPEN_SQUARE:
+      return parse_array ();
 
-  error_at (tok->index, "unexpected token: %s", token_id_name[tok->id]);
-  return NULL; // FIXME
+    case TOK_NUMBER:
+      {
+	number *result = new number (tok->u.number);
+	m_lexer.consume ();
+	return result;
+      }
+
+    case TOK_TRUE:
+      {
+	literal *result = new literal (JSON_TRUE);
+	m_lexer.consume ();
+	return result;
+      }
+
+    case TOK_FALSE:
+      {
+	literal *result = new literal (JSON_FALSE);
+	m_lexer.consume ();
+	return result;
+      }
+
+    case TOK_NULL:
+      {
+	literal *result = new literal (JSON_NULL);
+	m_lexer.consume ();
+	return result;
+      }
+
+    default:
+      error_at (tok->index, "unexpected token: %s", token_id_name[tok->id]);
+      return NULL;
+    }
 }
 
+/* FIXME.  */
+
 object *
 parser::parse_object ()
 {
@@ -755,6 +933,11 @@ parser::parse_object ()
       require (TOK_COLON);
 
       value *v = parse_value ();
+      if (!v)
+	{
+	  free (key);
+	  return result;
+	}
       result->set (key, v);
       free (key);
 
@@ -773,6 +956,8 @@ parser::parse_object ()
   return result;
 }
 
+/* FIXME.  */
+
 array *
 parser::parse_array ()
 {
@@ -790,6 +975,9 @@ parser::parse_array ()
   while (!seen_error_p ())
     {
       value *v = parse_value ();
+      if (!v)
+	return result;
+
       result->append (v);
 
       tok = m_lexer.peek ();
@@ -808,6 +996,8 @@ parser::parse_array ()
   return result;
 }
 
+/* FIXME.  */
+
 void
 parser::require (enum token_id tok_id)
 {
@@ -818,6 +1008,8 @@ parser::require (enum token_id tok_id)
   m_lexer.consume ();
 }
 
+/* FIXME.  */
+
 void
 parser::error_at (int index, const char *fmt, ...)
 {
@@ -830,23 +1022,29 @@ parser::error_at (int index, const char *fmt, ...)
 				    index, formatted);
   free (formatted);
 
-  fprintf (stderr, "%s\n", msg_with_index);
+  if (0)
+    fprintf (stderr, "%s\n", msg_with_index);
   if (*m_err_out == NULL)
     *m_err_out = msg_with_index;
   else
     free (msg_with_index);
 }
 
+/* Attempt to parse the UTF-8 encoded buffer at UTF8_BUF
+   of the given LENGTH.
+   If successful, return a non-NULL json::value *.
+   if there was a problem, return NULL and write an error
+   message to err_out, which must be freed by the caller.  */
 
 value *
-json::parse_utf8_string (size_t sz, const char *utf8_buf,
+json::parse_utf8_string (size_t length, const char *utf8_buf,
 			 char **err_out)
 {
   gcc_assert (err_out);
   gcc_assert (*err_out == NULL);
 
   parser p (err_out);
-  p.add_utf8 (sz, utf8_buf);
+  p.add_utf8 (length, utf8_buf);
   value *result = p.parse_value ();
   if (p.seen_error_p ())
     {
@@ -857,6 +1055,12 @@ json::parse_utf8_string (size_t sz, const char *utf8_buf,
   return result;
 }
 
+/* Attempt to parse the nil-terminated UTF-8 encoded buffer at
+   UTF8_BUF.
+   If successful, return a non-NULL json::value *.
+   if there was a problem, return NULL and write an error
+   message to err_out, which must be freed by the caller.  */
+
 value *
 json::parse_utf8_string (const char *utf8, char **err_out)
 {
@@ -880,6 +1084,8 @@ assert_to_str_eq (const char *expected_json, json::value *jv)
   free (json);
 }
 
+/* FIXME.  */
+
 static void
 test_parse_string ()
 {
@@ -900,23 +1106,34 @@ test_parse_string ()
   delete jv;
 }
 
+/* FIXME.  */
+
 static void
 test_parse_number ()
 {
+  json::value *jv, *clone;
+
   char *err = NULL;
-  json::value *jv = parse_utf8_string ("42", &err);
+  jv = parse_utf8_string ("42", &err);
   ASSERT_EQ (NULL, err);
   ASSERT_EQ (JSON_NUMBER, jv->get_kind ());
   ASSERT_EQ (42.0, ((json::number *)jv)->get ());
   assert_to_str_eq ("42", jv);
+  clone = jv->clone ();
+  ASSERT_EQ (JSON_NUMBER, clone->get_kind ());
+  delete clone;
   delete jv;
 }
 
+/* FIXME.  */
+
 static void
 test_parse_array ()
 {
+  json::value *jv, *clone;
+
   char *err = NULL;
-  json::value *jv = parse_utf8_string ("[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]", &err);
+  jv = parse_utf8_string ("[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]", &err);
   ASSERT_EQ (NULL, err);
   ASSERT_EQ (JSON_ARRAY, jv->get_kind ());
   json::array *arr = static_cast <json::array *> (jv);
@@ -928,9 +1145,25 @@ test_parse_array ()
       ASSERT_EQ (i, ((json::number *)element)->get ());
     }
   assert_to_str_eq ("[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]", jv);
+
+  clone = jv->clone ();
+  ASSERT_EQ (JSON_ARRAY, clone->get_kind ());
+  arr = static_cast <json::array *> (clone);
+  ASSERT_EQ (10, arr->get_length ());
+  for (int i = 0; i < 10; i++)
+    {
+      json::value *element = arr->get (i);
+      ASSERT_EQ (JSON_NUMBER, element->get_kind ());
+      ASSERT_EQ (i, ((json::number *)element)->get ());
+    }
+  assert_to_str_eq ("[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]", clone);
+  delete clone;
+
   delete jv;
 }
 
+/* FIXME.  */
+
 static void
 test_parse_object ()
 {
@@ -955,16 +1188,61 @@ test_parse_object ()
   ASSERT_EQ (2, baz_array->get_length ());
 
   // etc, verify numbers
-  // etc, true, false, null
 
   // TODO: error-handling
   // TODO: partial document
 
   /* We can't use assert_to_str_eq since ordering is not guaranteed.  */
 
+  json::value *clone = jv->clone ();
+  ASSERT_EQ (JSON_OBJECT, clone->get_kind ());
+  ASSERT_EQ (JSON_STRING, clone->as_object ()->get ("foo")->get_kind ());
+  delete clone;
+
   delete jv;
 }
 
+/* Verify that the literals "true", "false" and "null" are parsed,
+   dumped, and are clonable.  */
+
+static void
+test_parse_literals ()
+{
+  json::value *jv, *clone;
+  char *err = NULL;
+  jv = parse_utf8_string ("true", &err);
+  ASSERT_EQ (NULL, err);
+  ASSERT_TRUE (jv != NULL);
+  ASSERT_EQ (JSON_TRUE, jv->get_kind ());
+  assert_to_str_eq ("true", jv);
+  clone = jv->clone ();
+  ASSERT_EQ (JSON_TRUE, clone->get_kind ());
+  delete clone;
+  delete jv;
+
+  jv = parse_utf8_string ("false", &err);
+  ASSERT_EQ (NULL, err);
+  ASSERT_TRUE (jv != NULL);
+  ASSERT_EQ (JSON_FALSE, jv->get_kind ());
+  assert_to_str_eq ("false", jv);
+  clone = jv->clone ();
+  ASSERT_EQ (JSON_FALSE, clone->get_kind ());
+  delete clone;
+  delete jv;
+
+  jv = parse_utf8_string ("null", &err);
+  ASSERT_EQ (NULL, err);
+  ASSERT_TRUE (jv != NULL);
+  ASSERT_EQ (JSON_NULL, jv->get_kind ());
+  assert_to_str_eq ("null", jv);
+  clone = jv->clone ();
+  ASSERT_EQ (JSON_NULL, clone->get_kind ());
+  delete clone;
+  delete jv;
+}
+
+/* FIXME.  */
+
 static void
 test_parse_jsonrpc ()
 {
@@ -978,6 +1256,8 @@ test_parse_jsonrpc ()
   delete jv;
 }
 
+/* FIXME.  */
+
 static void
 test_parse_empty_object ()
 {
@@ -990,6 +1270,8 @@ test_parse_empty_object ()
   delete jv;
 }
 
+/* FIXME.  */
+
 static void
 test_error_empty_string ()
 {
@@ -1000,6 +1282,8 @@ test_error_empty_string ()
   free (err);
 }
 
+/* FIXME.  */
+
 static void
 test_error_missing_comma ()
 {
@@ -1023,6 +1307,7 @@ json_c_tests ()
   test_parse_number ();
   test_parse_array ();
   test_parse_object ();
+  test_parse_literals ();
   test_parse_jsonrpc ();
   test_parse_empty_object ();
   test_error_empty_string ();
@@ -1030,6 +1315,8 @@ json_c_tests ()
 
   /* FIXME: tests for roundtripping (noting that we don't preserve
      object key ordering).  */
+
+  /* FIXME: cloning.  */
 }
 
 } // namespace selftest
diff --git a/gcc/json.h b/gcc/json.h
index 7655d50..6e71beb 100644
--- a/gcc/json.h
+++ b/gcc/json.h
@@ -20,22 +20,45 @@ along with GCC; see the file COPYING3.  If not see
 #ifndef GCC_JSON_H
 #define GCC_JSON_H
 
+/* Implementation of JSON, a lightweight data-interchange format.
+
+   See http://www.json.org/
+   and http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf
+
+   Supports parsing text into a DOM-like tree of json::value *, dumping
+   json::value * to text.  */
+
 namespace json
 {
 
+/* Forward decls of json::value and its subclasses (using indentation
+   to denote inheritance.  */
+
 class value;
-  class string;
-  class number;
   class object;
   class array;
+  class number;
+  class string;
   class literal;
 
+/* An enum for discriminating the subclasses of json::value.  */
+
 enum kind
 {
+  /* class json::object.  */
   JSON_OBJECT,
+
+  /* class json::array.  */
   JSON_ARRAY,
+
+  /* class json::number.  */
   JSON_NUMBER,
+
+  /* class json::string.  */
   JSON_STRING,
+
+  /* class json::literal uses these three values to identify the
+     particular literal.  */
   JSON_TRUE,
   JSON_FALSE,
   JSON_NULL
@@ -49,18 +72,23 @@ class value
   virtual ~value () {}
   virtual enum kind get_kind () const = 0;
   virtual void print (pretty_printer *pp) const = 0;
+
+  /* Create a deep copy of the value, returning a value which must be
+     deleted by the caller.  */
   virtual value *clone () const = 0;
 
   char *to_str () const;
   void dump (FILE *) const;
 
+  /* Methods for dynamically casting a value to one of the subclasses,
+     returning NULL if the value is of the wrong kind.  */
   const object *as_object () const;
   const array *as_array () const;
   const number *as_number () const;
   const string *as_string () const;
 
-  /* Convenience accessors for attempting to get a value from
-     this value as if it is an object.
+  /* Convenience accessors for attempting to perform key/value lookups
+     on this value as if it were an json::object.
 
      On success, return true and write the value to OUT_VALUE.
      On failure, return false and write an error message to OUT_ERR
@@ -146,7 +174,8 @@ class string : public value
   char *m_utf8;
 };
 
-/* Subclass of value for the literals "true", "false", and "null".  */
+/* Subclass of value for the three JSON literals "true", "false",
+   and "null".  */
 
 class literal : public value
 {
@@ -161,13 +190,12 @@ class literal : public value
   enum kind m_kind;
 };
 
-/* Parsing decls.  */
+/* Declarations for parsing JSON to a json::value * tree.  */
 
-extern value *parse_utf8_string (size_t sz, const char *utf8_buf,
+extern value *parse_utf8_string (size_t length, const char *utf8_buf,
 				 char **err_out);
 extern value *parse_utf8_string (const char *utf8, char **err_out);
 
 } // namespace json
 
 #endif  /* GCC_JSON_H  */
-
diff --git a/gcc/lsp.c b/gcc/lsp.c
index 9663ccc..ed5d68e 100644
--- a/gcc/lsp.c
+++ b/gcc/lsp.c
@@ -247,7 +247,7 @@ static void
 test_simple ()
 {
   noop_server noop;
-  lsp::jsonrpc_server js (true, noop);
+  lsp::jsonrpc_server js (false, noop);
   const char *init_request
     = ("{\"jsonrpc\": \"2.0\", \"method\": \"initialize\","
        " \"params\": [42, 23], \"id\": 1}"); // FIXME
-- 
1.8.5.3

