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