private static void WriteQuery(JsonWriter writer, Spec.Query query)
 {
     writer.BeginArray();
     writer.WriteNumber((int)query.type);
     if (query.type == Spec.Query.QueryType.START)
     {
         WriteTerm(writer, query.query);
         writer.BeginObject();
         foreach (var opt in query.global_optargs)
         {
             writer.WriteMember(opt.key);
             WriteTerm(writer, opt.val);
         }
         writer.EndObject();
     }
     writer.EndArray();
 }
        private static void WriteTerm(JsonWriter writer, Spec.Term term)
        {
            if (term.type == Term.TermType.DATUM)
            {
                WriteDatum(writer, term.datum);
                return;
            }

            writer.BeginArray();
            writer.WriteNumber((int)term.type);
            if (term.args.Count > 0 || term.optargs.Count > 0)
            {
                writer.BeginArray();
                foreach (var arg in term.args)
                {
                    WriteTerm(writer, arg);
                }
                writer.EndArray();
                writer.BeginObject();
                foreach (var opt in term.optargs)
                {
                    writer.WriteMember(opt.key);
                    WriteTerm(writer, opt.val);
                }
                writer.EndObject();
            }
            writer.EndArray();
        }
 private static void WriteDatum(JsonWriter writer, Spec.Datum datum)
 {
     switch (datum.type)
     {
         case Spec.Datum.DatumType.R_BOOL:
             writer.WriteBoolean(datum.r_bool);
             break;
         case Spec.Datum.DatumType.R_JSON:
             throw new NotSupportedException();
         case Spec.Datum.DatumType.R_NULL:
             writer.WriteNull();
             break;
         case Spec.Datum.DatumType.R_NUM:
             writer.WriteNumber(datum.r_num);
             break;
         case Spec.Datum.DatumType.R_STR:
             writer.WriteString(datum.r_str);
             break;
         case Spec.Datum.DatumType.R_ARRAY:
             {
                 var newterm = new Term() { type = Term.TermType.MAKE_ARRAY };
                 newterm.args.AddRange(datum.r_array.Select(ap => new Term()
                 {
                     type = Term.TermType.DATUM,
                     datum = ap,
                 }));
                 WriteTerm(writer, newterm);
             }
             break;
         case Spec.Datum.DatumType.R_OBJECT:
             {
                 var newterm = new Term() { type = Term.TermType.MAKE_OBJ };
                 newterm.optargs.AddRange(datum.r_object.Select(ap => new Term.AssocPair()
                 {
                     key = ap.key,
                     val = new Term()
                     {
                         type = Term.TermType.DATUM,
                         datum = ap.val
                     }
                 }));
                 WriteTerm(writer, newterm);
             }
             break;
     }
 }