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 }