protected void append_json_sequence_repr(StringBuffer buf, PySequence sequence)
     throws JSONEncodeError {
   int num_items = sequence.__len__();
   buf.append('[');
   for (int ix = 0; ix < num_items; ix++) {
     buf.append(json_repr(sequence.__getitem__(ix)));
     if (ix < num_items - 1) buf.append(',');
   }
   buf.append(']');
 }
 protected void append_json_map_repr(StringBuffer buf, PyObject map, PyList keys)
     throws JSONEncodeError {
   int num_keys = keys.__len__();
   buf.append('{');
   for (int ix = 0; ix < num_keys; ix++) {
     PyObject k = keys.__getitem__(ix);
     if (!(k instanceof PyString))
       throw new JSONEncodeError(
           ((PyType) k.fastGetClass()).fastGetName()
               + " objects are not permitted as JSON object keys.");
     append_json_string_repr(buf, ((PyString) k).toString());
     buf.append(':');
     buf.append(json_repr(map.__finditem__(k)));
     if (ix < num_keys - 1) buf.append(',');
   }
   buf.append('}');
 }
 public void append_json_repr(StringBuffer buf, PyObject py_obj) throws JSONEncodeError {
   if (py_obj instanceof PyString) append_json_string_repr(buf, ((PyString) py_obj).toString());
   // Must test for PyBoolean before PyInteger because former is a subclass of latter.
   else if (py_obj instanceof PyBoolean)
     buf.append(((PyBoolean) py_obj).getBooleanValue() ? "true" : "false");
   else if (py_obj instanceof PyInteger)
     buf.append(Integer.toString(((PyInteger) py_obj).getValue()));
   else if (py_obj instanceof PyLong) {
     String repr = ((PyLong) py_obj).__repr__().toString();
     buf.append(repr.substring(0, repr.length() - 1));
   } else if (py_obj instanceof PyFloat)
     buf.append(Double.toString(((PyFloat) py_obj).getValue()));
   else if (py_obj instanceof PyStringMap) append_json_string_map_repr(buf, (PyStringMap) py_obj);
   else if (py_obj instanceof PyDictionary)
     append_json_dictionary_repr(buf, (PyDictionary) py_obj);
   else if (py_obj instanceof PySequence) append_json_sequence_repr(buf, (PySequence) py_obj);
   else if (py_obj instanceof PyNone) buf.append("null");
   else if (py_obj.__findattr__("__json__") != null
       && py_obj.__findattr__("__json__").isCallable())
     buf.append(((PyMethod) py_obj.__findattr__("__json__")).__call__().toString());
   else
     throw new JSONEncodeError(
         "Python '"
             + ((PyType) py_obj.fastGetClass()).fastGetName()
             + "' object '"
             + py_obj.__repr__()
             + "' is not encodable in JSON");
 }
  protected void append_json_string_repr(StringBuffer buf, String str) {
    int size = str.length();
    StringBuffer v = new StringBuffer(str.length());
    char quote = '"';

    buf.append(quote);
    for (int i = 0; size-- > 0; ) {
      int ch = str.charAt(i++);
      /* Escape quotes */
      if (ch == quote || ch == '\\') {
        buf.append('\\');
        buf.append((char) ch);
      } else if (ch == '\n') buf.append("\\n");
      else if (ch == '\t') buf.append("\\t");
      else if (ch == '\b') buf.append("\\b");
      else if (ch == '\f') buf.append("\\f");
      else if (ch == '\r') buf.append("\\r");
      else if (ch < ' '
          || (ch >= 127 && emit_ascii)
          || (ch >= Character.MIN_SURROGATE && ch <= Character.MAX_SURROGATE)) {
        /* Map control and non ascii characters to '\\uxxxx' */
        buf.append("\\u");
        buf.append(hexdigit[(ch >> 12) & 0xf]);
        buf.append(hexdigit[(ch >> 8) & 0xf]);
        buf.append(hexdigit[(ch >> 4) & 0xf]);
        buf.append(hexdigit[ch & 15]);
      }
      /* Copy everything else as-is */
      else buf.append((char) ch);
    }
    buf.append(quote);
  }
 public String json_repr(PyObject py_obj) throws JSONEncodeError {
   StringBuffer buf = new StringBuffer();
   append_json_repr(buf, py_obj);
   return buf.toString();
 }