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