1 /*******************************************************************************
2 
3         Copyright: Copyright (C) 2008 Aaron Craelius & Kris Bell
4                    All rights reserved
5 
6         License:   BSD style: $(LICENSE)
7 
8         version:   July 2008: Initial release
9 
10         Authors:   Aaron, Kris
11 
12 *******************************************************************************/
13 
14 module tango.text.json.Json;
15 
16 private import tango.core.Vararg;
17 
18 private import tango.io.model.IConduit;
19 
20 private import tango.text.json.JsonEscape;
21 
22 private import tango.text.json.JsonParser;
23 
24 private import Float = tango.text.convert.Float;
25 
26 private import Utf = tango.text.convert.Utf;
27 
28 /*******************************************************************************
29 
30         Parse json text into a set of inter-related structures. Typical 
31         usage is as follows:
32         ---
33         auto json = new Json!(char);
34         json.parse (`{"t": true, "n":null, "array":["world", [4, 5]]}`);    
35         ---   
36 
37         Converting back to text format employs a delegate. This one emits 
38         document content to the console:
39         ---
40         json.print ((char[] s) {Stdout(s);}); 
41         ---
42 
43         Constructing json within your code leverages a handful of factories 
44         within a document instance. This example creates a document from an 
45         array of values:
46         ---
47         auto json = new Json!(char);
48 
49         // [true, false, null, "text"]
50         with (json)
51               value = array (true, false, null, "text");
52         ---
53 
54         Setting the document to contain a simple object instead:
55         ---
56         // {"a" : 10}
57         with (json)
58               value = object (pair("a", value(10)));
59         ---
60 
61         Objects may be constructed with multiple attribute pairs like so:
62         ---
63         // {"a" : 10, "b" : true}
64         with (json)
65               value = object (pair("a", value(10)), pair("b", value(true)));
66         ---
67 
68         Substitute arrays, or other objects as values where appropriate:
69         ---
70         // {"a" : [10, true, {"b" : null}]}
71         with (json)
72               value = object (pair("a", array(10, true, object(pair("b")))));
73         ---
74 
75         TODO: document how to extract content
76 
77         Big thanks to dhasenan for suggesting the construction notation. We
78         can't make effective use of operator-overloading, due to the use of
79         struct pointers, so this syntax turned out to be the next best thing.
80 
81 *******************************************************************************/
82 
83 class Json(T) : JsonParser!(T)
84 {
85                      /// use these types for external references
86         public alias JsonValue*  Value;
87         public alias NameValue*  Attribute;
88         public alias JsonObject* Composite;
89 
90                     /// enumerates the seven acceptable JSON value types
91         public enum Type {Null, String, RawString, Number, Object, Array, True, False};
92 
93         private Value root;
94 
95         /***********************************************************************
96         
97                 Construct a json instance, with a default value of null
98 
99         ***********************************************************************/
100         
101         this ()
102         {
103                 arrays.length = 16;
104                 parse (null);
105         }
106 
107         /***********************************************************************
108         
109                 Parse the given text and return a resultant Value type. Also
110                 sets the document value. 
111 
112         ***********************************************************************/
113         
114         final Value parse (const(T)[] json)
115         {
116                 nesting = 0;
117                 attrib.reset();
118                 values.reset();
119                 objects.reset();
120                 foreach (ref p; arrays)
121                          p.index = 0;
122 
123                 root = createValue();
124                 if (super.reset (json))
125                 {
126                     if (curType is Token.BeginObject)
127                         root.set (parseObject());
128                     else
129                        if (curType is Token.BeginArray)
130                            root.set (parseArray());
131                        else
132                           exception ("invalid json document");
133                 }
134                 return root;
135         }
136 
137         /***********************************************************************
138         
139                 Return a text representation of this document
140 
141         ***********************************************************************/
142 
143         final T[] toString (const(T)[] space, int decimals=2)
144         {
145                 return root.print (space, decimals);
146         }
147         
148         final override
149         immutable(char)[] toString()
150         {
151                 return Utf.toString(toString(null)).idup;
152         }
153 
154         /***********************************************************************
155         
156                 Returns the root value of this document
157 
158         ***********************************************************************/
159         
160         final Value value ()
161         {
162                 return root;
163         }
164 
165         /***********************************************************************
166         
167                 Set the root value of this document
168 
169         ***********************************************************************/
170         
171         final Value value (Value v)
172         {
173                 return root = v;
174         }
175 
176         /***********************************************************************
177         
178                 Create a text value
179 
180         ***********************************************************************/
181         
182         final Value value (const(T)[] v)
183         {
184                 return createValue().set (v);
185         }
186 
187         /***********************************************************************
188         
189                 Create a boolean value
190 
191         ***********************************************************************/
192         
193         final Value value (bool v)
194         {
195                 return createValue().set (v);
196         }
197 
198         /***********************************************************************
199         
200                 Create a numeric value
201 
202         ***********************************************************************/
203         
204         final Value value (double v)
205         {
206                 return createValue().set (v);
207         }
208 
209          /***********************************************************************
210          
211                  Create a single Value from an array of Values
212 
213          ***********************************************************************/
214 
215          final Value value (Value[] vals)
216          {
217                  return createValue().set (vals);
218          }
219 
220         /***********************************************************************
221         
222                 Create an array of values
223 
224         ***********************************************************************/
225 
226         final Value array (...)
227         {
228                 return createValue().set (this, _arguments, _argptr);
229         }
230 
231         /***********************************************************************
232         
233                 Create an attribute/value pair, where value defaults to 
234                 null
235 
236         ***********************************************************************/
237         
238         Attribute pair (const(T)[] name, Value value = null)
239         {
240                 if (value is null)
241                     value = createValue();
242                 return createAttribute().set (name, value);
243         }
244 
245         /***********************************************************************
246         
247                 Create a composite from zero or more pairs, and return as 
248                 a value
249 
250         ***********************************************************************/
251         
252         final Value object (Attribute set[]...)
253         {
254                 return createValue().set (createObject().add (set));
255         }
256 
257         /***********************************************************************
258         
259                 Internal factory to create values
260 
261         ***********************************************************************/
262         
263         private Value createValue ()
264         {
265                 return values.allocate().reset();
266         }
267 
268         /***********************************************************************
269         
270                 Internal factory to create composites
271 
272         ***********************************************************************/
273         
274         private Composite createObject ()
275         {
276                 return objects.allocate().reset();
277         }
278 
279         /***********************************************************************
280         
281                 Internal factory to create attributes
282 
283         ***********************************************************************/
284        
285         private Attribute createAttribute ()
286         {
287                 return attrib.allocate();
288         }
289 
290         /***********************************************************************
291         
292                 Throw a generic exception
293 
294         ***********************************************************************/
295         
296         private void exception (immutable(char)[] msg)
297         {
298                 throw new Exception (msg);
299         }
300 
301         /***********************************************************************
302         
303                 Parse an instance of a value
304 
305         ***********************************************************************/
306         
307         private Value parseValue ()
308         {
309                 auto v = values.allocate();
310 
311                 switch (super.curType)
312                        {
313                        case Token.True:
314                             v.set (Type.True);
315                             break;
316 
317                        case Token.False:
318                             v.set (Type.False);
319                             break;
320 
321                        case Token.Null:
322                             v.set (Type.Null);
323                             break;
324 
325                        case Token.BeginObject:
326                             v.set (parseObject());
327                             break;
328 
329                        case Token.BeginArray:
330                             v.set (parseArray());
331                             break;
332 
333                        case Token.String:
334                             v.set (super.value, true);
335                             break;
336 
337                        case Token.Number:
338                             v.set (Float.parse (super.value));
339                             break;
340 
341                        default:
342                             v.set (Type.Null);
343                             break;
344                        }
345 
346                 return v;
347         }
348 
349         /***********************************************************************
350         
351                 Parse an object declaration
352 
353         ***********************************************************************/
354         
355         private Composite parseObject ()
356         {
357                 auto o = objects.allocate().reset();
358 
359                 while (super.next) 
360                       {
361                       if (super.curType is Token.EndObject)
362                           return o;
363 
364                       if (super.curType != Token.Name)
365                           super.expected ("an attribute-name", super.str.ptr);
366                         
367                       auto name = super.value;
368                         
369                       if (! super.next)
370                             super.expected ("an attribute-value", super.str.ptr);
371                         
372                       o.append (attrib.allocate().set (name, parseValue()));
373                       }
374 
375                 return o;
376         }
377         
378         /***********************************************************************
379         
380                 Parse an array declaration
381 
382         ***********************************************************************/
383         
384         private Value[] parseArray ()
385         {
386                 if (nesting >= arrays.length)
387                     exception ("array nesting too deep within document");
388 
389                 auto array = &arrays[nesting++];
390                 auto start = array.index;
391 
392                 while (super.next && super.curType != Token.EndArray) 
393                       {
394                       if (array.index >= array.content.length)
395                           array.content.length = array.content.length + 300;
396 
397                       array.content [array.index++] = parseValue();
398                       }
399 
400                 if (super.curType != Token.EndArray)
401                     exception ("malformed array");
402 
403                 --nesting;
404                 return array.content [start .. array.index];
405         }
406 
407         /***********************************************************************
408         
409                 Represents an attribute/value pair. Aliased as Attribute
410 
411         ***********************************************************************/
412         
413         struct NameValue
414         {
415                 private Attribute       next;
416                 public  const(T)[]      name;
417                 public  Value           value;
418 
419                 /***************************************************************
420         
421                         Set a name and a value for this attribute
422 
423                         Returns itself, for use with Composite.add()
424 
425                 ***************************************************************/
426         
427                 Attribute set (const(T)[] key, Value val)
428                 {
429                         name = key;
430                         value = val;
431                         return &this;
432                 }
433         }
434 
435         /***********************************************************************
436 
437                 Represents a single json Object (a composite of named 
438                 attribute/value pairs).
439 
440                 This is aliased as Composite
441 
442         ***********************************************************************/
443         
444         struct JsonObject
445         {
446                 private Attribute head,
447                                   tail;
448                 
449                 /***************************************************************
450         
451                 ***************************************************************/
452         
453                 Composite reset ()
454                 {
455                         head = tail = null;
456                         return &this;
457                 }
458 
459                 /***************************************************************
460         
461                         Append an attribute/value pair
462 
463                 ***************************************************************/
464         
465                 Composite append (Attribute a)
466                 {
467                         if (tail)
468                             tail.next = a, tail = a;
469                         else
470                            head = tail = a;
471                         return &this;
472                 }
473 
474                 /***************************************************************
475         
476                         Add a set of attribute/value pairs
477 
478                 ***************************************************************/
479         
480                 Composite add (Attribute[] set...)
481                 {
482                         foreach (attr; set)
483                                  append (attr);
484                         return &this;
485                 }
486 
487                 /***************************************************************
488                         
489                         Construct and return a hashmap of Object attributes.
490                         This will be a fairly costly operation, so consider 
491                         alternatives where appropriate
492 
493                 ***************************************************************/
494         
495                 Value[T[]] hashmap ()
496                 {
497                         Value[T[]] members;
498 
499                         auto a = head;
500                         while (a)
501                               {
502                               members[a.name] = a.value;
503                               a = a.next;
504                               }
505 
506                         return members;
507                 }
508         
509                 /***************************************************************
510         
511                         Return a corresponding value for the given attribute 
512                         name. Does a linear lookup across the attribute set
513 
514                 ***************************************************************/
515         
516                 Value value (const(T)[] name)
517                 {
518                         auto a = head;
519                         while (a)
520                                if (name == a.name)
521                                    return a.value;
522                                else
523                                   a = a.next;
524 
525                         return null;
526                 }
527         
528                 /***************************************************************
529         
530                         Iterate over our attribute names and values
531 
532                 ***************************************************************/
533         
534                 @property Iterator attributes ()
535                 {
536                         Iterator i = {head};
537                         return i;
538                 }
539 
540                 /***************************************************************
541         
542                         Iterate over our attribute names. Note that we 
543                         use a Fruct to handle this, since foreach does
544                         not operate cleanly with pointers (it doesn't 
545                         automatically dereference them), whereas using 
546                         x.attributes() does. 
547                         
548                         We may also use this to do some name filtering
549 
550                 ***************************************************************/
551         
552                 static struct Iterator
553                 {
554                         private Attribute head;
555         
556                         int opApply (int delegate(ref const(T)[] key, ref Value val) dg)
557                         {
558                                 int res;
559         
560                                 auto a = head;
561                                 while (a)
562                                       {
563                                       if ((res = dg (a.name, a.value)) != 0) 
564                                            break;
565                                       a = a.next;
566                                       }
567                                return res;
568                         }
569                 }
570         }
571         
572         /***********************************************************************
573         
574                 Represents a json value that is one of the seven types 
575                 specified via the Json.Type enum 
576 
577         ***********************************************************************/
578         
579         struct JsonValue
580         {
581                 private union
582                 {
583                         Value[]         array;
584                         real            number;
585                         const(T)[]      string;
586                         Composite       object;
587                 }
588         
589                 public Type type;               /// the type of this node
590                 alias reset set;                /// alternate name for reset
591 
592                 /***************************************************************
593         
594                         return true if this node is of the given type
595 
596                 ***************************************************************/
597         
598                 bool equals (Type t)
599                 {
600                         return type is t;
601                 }
602                 
603                 /***************************************************************
604         
605                         Return true if this value represent True
606 
607                 ***************************************************************/
608         
609                 bool toBool ()
610                 {
611                         return (type is Type.True);
612                 }
613 
614                 /***************************************************************
615                         
616                         Return the string content. Returns null if this
617                         value is not a string.
618 
619                         Uses dst for escape conversion where possible.
620 
621                 ***************************************************************/
622 
623                 const(T)[] toString (T[] dst)
624                 {
625                         if (type is Type.RawString)
626                             return string;
627 
628                         if (type is Type.String)
629                             return unescape (string, dst);
630 
631                         return null;
632                 }
633                 
634                 immutable(char)[] toString()
635                 {
636                         return Utf.toString(toString(cast(T[])null)).idup;
637                 }
638                 
639                 /***************************************************************
640         
641                         Emit the string content to the given delegate, with
642                         escape conversion as required.
643 
644                         Returns false if this is not a String value
645                       
646                 ***************************************************************/
647         
648                 bool toString (scope void delegate(const(T)[]) dg)
649                 {
650                         if (type is Type.RawString)
651                             dg(string);
652                         else
653                            if (type is Type.String)
654                                unescape (string, dg);
655                            else
656                               return false;
657                         return true;
658                 }
659 
660                 /***************************************************************
661         
662                         Return the content as a Composite/Object. Returns null
663                         if this value is not a Composite.
664 
665                 ***************************************************************/
666         
667                 Composite toObject ()
668                 {
669                         return type is Type.Object ? object : null;
670                 }
671                 
672                 /***************************************************************
673         
674                         Return the content as a double. Returns nan where
675                         the value is not numeric.
676 
677                 ***************************************************************/
678         
679                 real toNumber ()
680                 {
681                         return type is Type.Number ? number : real.nan;
682                 }
683                 
684                 /***************************************************************
685         
686                         Return the content as an array. Returns null where
687                         the value is not an array.
688 
689                 ***************************************************************/
690         
691                 Value[] toArray ()
692                 {
693                         return (type is Type.Array) ? array : null;
694                 }
695                 
696                 /***************************************************************
697         
698                         Set this value to represent a string. If 'escaped' 
699                         is set, the string is assumed to have pre-converted
700                         escaping of reserved characters (such as \t).
701 
702                 ***************************************************************/
703         
704                 Value set (const(T)[] str, bool escaped = false)
705                 {
706                         type = escaped ? Type.String : Type.RawString;
707                         string = str;
708                         return &this;
709                 }
710                 
711                 /***************************************************************
712         
713                         Set this value to represent an object.
714 
715                 ***************************************************************/
716         
717                 Value set (Composite obj)
718                 {
719                         type = Type.Object;
720                         object = obj;
721                         return &this;
722                 }
723                 
724                 /***************************************************************
725         
726                         Set this value to represent a number.
727 
728                 ***************************************************************/
729         
730                 Value set (real num)
731                 {
732                         type = Type.Number;
733                         number = num;
734                         return &this;
735                 }
736                 
737                 /***************************************************************
738         
739                         Set this value to represent a boolean.
740 
741                 ***************************************************************/
742         
743                 Value set (bool b)
744                 {
745                         type = b ? Type.True : Type.False;             
746                         return &this;
747                 }
748                 
749                 /***************************************************************
750         
751                         Set this value to represent an array of values.
752 
753                 ***************************************************************/
754         
755                 Value set (Value[] a)
756                 {
757                         type = Type.Array;
758                         array = a;
759                         return &this;
760                 }
761                 
762                 /***************************************************************
763         
764                         Set this value to represent null
765 
766                 ***************************************************************/
767         
768                 Value reset ()
769                 {
770                         type = Type.Null;
771                         return &this;
772                 }
773                 
774                 /***************************************************************
775         
776                         Return a text representation of this value
777 
778                 ***************************************************************/
779 
780                 T[] print (const(T)[] space=null, int decimals=2)
781                 {
782                         T[] tmp;
783                         void append (const(T)[] s) {tmp ~= s;}
784                         print (&append, space, decimals);
785                         return tmp;
786                 }
787 
788                 /***************************************************************
789         
790                         Emit a text representation of this value to the 
791                         given OutputStream
792 
793                 ***************************************************************/
794 
795                 Value print (OutputStream s, const(T)[] space=null, int decimals=2)
796                 {
797                         return print ((const(T)[] t){s.write(t);}, space, decimals);
798                 }
799 
800                 /***************************************************************
801                         
802                         Emit a text representation of this value to the
803                         provided delegate
804 
805                 ***************************************************************/
806                 
807                 Value print (void delegate(const(T)[]) append, const(T)[] space=null, int decimals=2)
808                 {
809                         auto indent = 0;
810         
811                         @property void newline ()
812                         {
813                                 if (space.length)
814                                    {
815                                    append ("\n");
816                                    for (auto i=0; i < indent; i++)
817                                         append (space);
818                                    }
819                         }
820         
821                         void printValue (Value val)
822                         {
823                                 void printObject (Composite obj)
824                                 {
825                                         if (obj is null) 
826                                             return;
827                                         
828                                         bool first = true;
829                                         append ("{");
830                                         indent++;
831         
832                                         foreach (k, v; obj.attributes)
833                                                 {
834                                                 if (!first)  
835                                                      append (",");
836                                                 newline;
837                                                 append (`"`), append(k), append(`":`);
838                                                 printValue (v);
839                                                 first = false;
840                                                 }
841                                         indent--;
842                                         newline;
843                                         append ("}");
844                                 }
845                                 
846                                 void printArray (Value[] arr)
847                                 {
848                                         bool first = true;
849                                         append ("[");
850                                         indent++;
851                                         foreach (v; arr)
852                                                 {
853                                                 if (!first) 
854                                                      append (", ");
855                                                 newline;
856                                                 printValue (v);
857                                                 first = false;
858                                                 }
859                                         indent--;
860                                         newline;
861                                         append ("]");
862                                 }
863         
864         
865                                 if (val is null) 
866                                     return;
867                                 
868                                 switch (val.type)
869                                        {
870                                        T[64] tmp = void;
871         
872                                        case Type.String:
873                                             append (`"`), append(val..string), append(`"`);
874                                             break;
875         
876                                        case Type.RawString:
877                                             append (`"`), escape(val..string, append), append(`"`);
878                                             break;
879         
880                                        case Type.Number:
881                                             append (Float.format (tmp, val.toNumber(), decimals));
882                                             break;
883         
884                                        case Type.Object:
885                                             auto obj = val.toObject();
886                                             debug assert(obj !is null);
887                                             printObject (val.toObject());
888                                             break;
889         
890                                        case Type.Array:
891                                             printArray (val.toArray());
892                                             break;
893         
894                                        case Type.True:
895                                             append ("true");
896                                             break;
897         
898                                        case Type.False:
899                                             append ("false");
900                                             break;
901         
902                                        default:
903                                        case Type.Null:
904                                             append ("null");
905                                             break;
906                                        }
907                         }
908                         
909                         printValue (&this);
910                         return &this;
911                 }
912 
913                 /***************************************************************
914         
915                         Set to a specified type
916 
917                 ***************************************************************/
918         
919                 private Value set (Type type)
920                 {
921                         this.type = type;
922                         return &this;
923                 }
924 
925                 /***************************************************************
926         
927                         Set a variety of values into an array type
928 
929                 ***************************************************************/
930         
931                 private Value set (Json host, TypeInfo[] info, va_list args)
932                 {
933                         Value[] list;
934 
935                         foreach (type; info)
936                                 {
937                                 Value v;
938                                 if (type is typeid(Value))
939                                     v = va_arg!(Value)(args);
940                                 else
941                                    {
942                                    v = host.createValue();
943                                    if (type is typeid(double))
944                                        v.set (va_arg!(double)(args));
945                                    else
946                                    if (type is typeid(int))
947                                        v.set (va_arg!(int)(args));
948                                    else
949                                    if (type is typeid(bool))
950                                        v.set (va_arg!(bool)(args));
951                                    else
952                                    if (type is typeid(long))
953                                        v.set (va_arg!(long)(args));
954                                    else
955                                    if (type is typeid(Composite))
956                                        v.set (va_arg!(Composite)(args));
957                                    else
958                                    if (type is typeid(T[]))
959                                        v.set (va_arg!(T[])(args));
960                                    else
961                                    if (type is typeid(void*))
962                                        va_arg!(void*)(args);
963                                    else
964                                       host.exception ("JsonValue.set :: unexpected type: "~type.toString());
965                                    }
966                                 list ~= v;
967                                 }
968                         /* For some reason DMD 2.054 doesn't like calling set here directly */
969                         return forwardref_buf (&this, list);
970                 }
971 
972                 private static Value forwardref_buf(Value v, Value[] list)
973                 {
974                     return v.set(list);
975                 }
976         }
977 
978         /***********************************************************************
979         
980                 Internal allocation mechanism
981 
982         ***********************************************************************/
983         
984         private struct Allocator(T)
985         {
986                 private T[]     list;
987                 private T[][]   lists;
988                 private int     index,
989                                 block;
990 
991                 void reset ()
992                 {
993                         // discard since prior lists are not initialized
994                         lists.length = 0;       
995                         block = -1;
996                         newlist;
997                 }
998 
999                 T* allocate ()
1000                 {
1001                         if (index >= list.length)
1002                             newlist;
1003         
1004                         auto p = &list [index++];
1005                         return p;
1006                 }
1007         
1008                 @property private void newlist ()
1009                 {
1010                         index = 0;
1011                         if (++block >= lists.length)
1012                            {
1013                            lists.length = lists.length + 1;
1014                            lists[$-1] = new T[256];
1015                            }
1016                         list = lists [block];
1017                 }
1018         }
1019 
1020         /***********************************************************************
1021             
1022                 Internal use for parsing array values
1023                     
1024         ***********************************************************************/
1025         
1026         private struct Array
1027         {
1028                 uint            index;
1029                 Value[]         content;
1030         }
1031 
1032         /***********************************************************************
1033         
1034                 Internal document representation
1035 
1036         ***********************************************************************/
1037         
1038         private alias Allocator!(NameValue)     Attrib;
1039         private alias Allocator!(JsonValue)     Values;
1040         private alias Allocator!(JsonObject)    Objects;
1041 
1042         private Attrib                          attrib;
1043         private Values                          values;
1044         private Array[]                         arrays;
1045         private Objects                         objects;
1046         private uint                            nesting;
1047 }
1048 
1049 
1050 
1051 /*******************************************************************************
1052 
1053 *******************************************************************************/
1054 
1055 debug (UnitTest)
1056 {
1057         unittest
1058         {
1059         with (new Json!(char))
1060              {
1061              root = object
1062                   (
1063                   pair ("edgar", value("friendly")),
1064                   pair ("count", value(11.5)),
1065                   pair ("array", value(array(1, 2)))
1066                   );
1067 
1068              auto value = toString();
1069              assert (value == `{"edgar":"friendly","count":11.5,"array":[1, 2]}`, value);
1070              }
1071         }
1072         
1073         unittest
1074         {
1075         // check with a separator of the tab character
1076         with (new Json!(char))
1077              {
1078              root = object
1079                   (
1080                   pair ("edgar", value("friendly")),
1081                   pair ("count", value(11.5)),
1082                   pair ("array", value(array(1, 2)))
1083                   );
1084 
1085              auto value = toString ("\t");
1086              assert (value == "{\n\t\"edgar\":\"friendly\",\n\t\"count\":11.5,\n\t\"array\":[\n\t\t1, \n\t\t2\n\t]\n}", value);
1087              }
1088         }
1089         
1090         unittest
1091         {
1092         // check with a separator of five spaces
1093         with (new Json!(dchar))
1094              {
1095              root = object
1096                   ( 
1097                   pair ("edgar", value("friendly")),
1098                   pair ("count", value(11.5)),
1099                   pair ("array", value(array(1, 2)))
1100                   );
1101 
1102              auto value = toString ("     ");
1103              assert (value == "{\n     \"edgar\":\"friendly\",\n     \"count\":11.5,\n     \"array\":[\n          1, \n          2\n     ]\n}");
1104              }
1105         }
1106 }
1107         
1108 /*******************************************************************************
1109 
1110 *******************************************************************************/
1111 
1112 debug (Json)
1113 {
1114         import tango.io.Stdout;
1115         import tango.io.device.File;
1116         import tango.time.StopWatch;
1117                 
1118         void main()
1119         {
1120                 void loop (JsonParser!(char) parser, char[] json, int n)
1121                 {
1122                         for (uint i = 0; i < n; ++i)
1123                             {
1124                             parser.reset (json);
1125                             while (parser.next) {}
1126                             }
1127                 }
1128         
1129                 void test (char[] filename, char[] txt)
1130                 {
1131                         uint n = (300 * 1024 * 1024) / txt.length;
1132                         auto parser = new JsonParser!(char);
1133                         
1134                         StopWatch watch;
1135                         watch.start;
1136                         loop (parser, txt, n);
1137                         auto t = watch.stop;
1138                         auto mb = (txt.length * n) / (1024 * 1024);
1139                         Stdout.formatln("{} {} iterations, {} seconds: {} MB/s", filename, n, t, mb/t);
1140                 }
1141         
1142                 void test1 (char[] filename, char[] txt)
1143                 {
1144                         uint n = (200 * 1024 * 1024) / txt.length;
1145                         auto parser = new Json!(char);
1146                         
1147                         StopWatch watch;
1148                         watch.start;
1149                         for (uint i = 0; i < n; ++i)
1150                              parser.parse (txt);
1151         
1152                         auto t = watch.stop;
1153                         auto mb = (txt.length * n) / (1024 * 1024);
1154                         Stdout.formatln("{} {} iterations, {} seconds: {} MB/s", filename, n, t, mb/t);
1155                 }
1156         
1157                 char[] load (char[] file)
1158                 {
1159                         return cast(char[]) File.get(file);
1160                 }
1161         
1162                 //test("test1.json", load("test1.json"));
1163                 //test("test2.json", load("test2.json"));
1164                 //test("test3.json", load("test3.json"));
1165                         
1166                 //test1("test1.json", load("test1.json"));
1167                 //test1("test2.json", load("test2.json"));
1168                 //test1("test3.json", load("test3.json"));
1169                 
1170                 auto p = new Json!(char);
1171                 auto v = p.parse (`{"t": true, "f":false, "n":null, "hi":["world", "big", 123, [4, 5, ["foo"]]]}`);       
1172                 Stdout.formatln ("{}", p.toString());
1173         
1174                 with (p)
1175                       value = object(pair("a", array(null, true, false, 30, object(pair("foo")))), pair("b", value(10)));
1176         
1177                 Stdout.formatln ("{}", p.toString());
1178 
1179                 p.parse ("[-1]");
1180                 Stdout.formatln ("{}", p.toString(null));
1181 
1182                 p.parse ("[11.23477]");
1183                 Stdout.formatln ("{}", p.toString(null, 4));
1184 
1185                 p.parse(`["foo"]`);
1186                 Stdout.formatln ("{}", p.toString());
1187 
1188                 p.parse(`{"foo": {"ff" : "ffff"}`);
1189                 Stdout.formatln ("{}", p.toString());
1190 
1191                 with (new Json!(char))
1192                      {
1193                      root = object(pair("array", array(null)));
1194                      Stdout.formatln ("{}", toString());
1195                      }
1196         }
1197 }
1198 
1199 
1200