--- /dev/null
+[
+ {
+ "_id": "60ca4f9c6d42737b7bed094a",
+ "index": 0,
+ "guid": "ce782a8f-c466-44fb-8bbc-9da2153de074",
+ "isActive": true,
+ "balance": "$1,984.80",
+ "picture": "http://placehold.it/32x32",
+ "age": 30,
+ "eyeColor": "green",
+ "name": "Mcguire Hodge",
+ "gender": "male",
+ "company": "SNIPS",
+ "email": "mcguirehodge@snips.com",
+ "phone": "+1 (834) 435-2386",
+ "address": "426 Wilson Street, Ahwahnee, Maine, 5085",
+ "about": "Tempor esse irure cupidatat qui eu sint elit. Voluptate nisi officia adipisicing sunt eu enim anim excepteur sunt eiusmod id magna. Sint aliqua eu minim consectetur ullamco laboris amet. Et reprehenderit est sit aute ex nulla eiusmod in occaecat. Aliqua quis dolore tempor aute consequat laborum non amet et culpa occaecat. Deserunt non aliqua consequat adipisicing.\r\n",
+ "registered": "2019-11-14T05:31:14 +06:00",
+ "latitude": -20.052331,
+ "longitude": 63.936704,
+ "tags": [
+ "laborum",
+ "minim",
+ "cupidatat",
+ "ad",
+ "adipisicing",
+ "exercitation",
+ "mollit"
+ ],
+ "friends": [
+ {
+ "id": 0,
+ "name": "Foster Huff"
+ },
+ {
+ "id": 1,
+ "name": "Katheryn Gross"
+ },
+ {
+ "id": 2,
+ "name": "Ingrid Branch"
+ }
+ ],
+ "greeting": "Hello, Mcguire Hodge! You have 10 unread messages.",
+ "favoriteFruit": "apple"
+ },
+ {
+ "_id": "60ca4f9ce40b355a63bad1d5",
+ "index": 1,
+ "guid": "fde167ba-15d4-4d8e-b3e0-0e248d25ffed",
+ "isActive": true,
+ "balance": "$1,959.39",
+ "picture": "http://placehold.it/32x32",
+ "age": 32,
+ "eyeColor": "green",
+ "name": "Sybil Tucker",
+ "gender": "female",
+ "company": "TROPOLI",
+ "email": "sybiltucker@tropoli.com",
+ "phone": "+1 (980) 550-3355",
+ "address": "990 Beayer Place, Dowling, Louisiana, 3955",
+ "about": "Voluptate commodo anim elit ea nulla in culpa qui do in voluptate proident do proident. Incididunt non occaecat sint irure ex reprehenderit voluptate nulla ea ullamco. Sit incididunt enim labore veniam ipsum amet reprehenderit consectetur elit. Irure consectetur sunt sint ex nulla amet sint ea pariatur. Ad irure non sunt ex anim. Voluptate incididunt dolor voluptate id mollit officia.\r\n",
+ "registered": "2016-01-19T04:17:57 +06:00",
+ "latitude": -86.800363,
+ "longitude": -75.422022,
+ "tags": [
+ "dolore",
+ "est",
+ "non",
+ "reprehenderit",
+ "dolor",
+ "dolor",
+ "irure"
+ ],
+ "friends": [
+ {
+ "id": 0,
+ "name": "Hunter Woodard"
+ },
+ {
+ "id": 1,
+ "name": "Gwendolyn Morton"
+ },
+ {
+ "id": 2,
+ "name": "Daphne Wiley"
+ }
+ ],
+ "greeting": "Hello, Sybil Tucker! You have 10 unread messages.",
+ "favoriteFruit": "strawberry"
+ },
+ {
+ "_id": "60ca4f9c43a5646bf7f31d1b",
+ "index": 2,
+ "guid": "3214362c-faa2-4282-8861-8c6a45e3f779",
+ "isActive": false,
+ "balance": "$3,838.20",
+ "picture": "http://placehold.it/32x32",
+ "age": 36,
+ "eyeColor": "blue",
+ "name": "Zelma Fuller",
+ "gender": "female",
+ "company": "KIDGREASE",
+ "email": "zelmafuller@kidgrease.com",
+ "phone": "+1 (865) 430-2263",
+ "address": "864 Furman Street, Norris, Nevada, 6768",
+ "about": "Anim qui ex velit exercitation sint irure fugiat sint ullamco aute nisi ipsum laboris. Fugiat deserunt qui do cillum deserunt. Officia ut adipisicing reprehenderit esse ex pariatur cupidatat amet amet id excepteur fugiat minim.\r\n",
+ "registered": "2016-12-31T02:47:40 +06:00",
+ "latitude": 45.942578,
+ "longitude": 12.857339,
+ "tags": [
+ "exercitation",
+ "non",
+ "officia",
+ "occaecat",
+ "sunt",
+ "cupidatat",
+ "eiusmod"
+ ],
+ "friends": [
+ {
+ "id": 0,
+ "name": "Stacy Willis"
+ },
+ {
+ "id": 1,
+ "name": "Oneil Michael"
+ },
+ {
+ "id": 2,
+ "name": "Chasity Mcgowan"
+ }
+ ],
+ "greeting": "Hello, Zelma Fuller! You have 10 unread messages.",
+ "favoriteFruit": "apple"
+ },
+ {
+ "_id": "60ca4f9cd83cfc496df01adb",
+ "index": 3,
+ "guid": "cd6e6ad9-cf3f-4d6f-afa3-40e7e2fe9956",
+ "isActive": true,
+ "balance": "$3,395.72",
+ "picture": "http://placehold.it/32x32",
+ "age": 35,
+ "eyeColor": "blue",
+ "name": "Collins Morrow",
+ "gender": "male",
+ "company": "COMVEYOR",
+ "email": "collinsmorrow@comveyor.com",
+ "phone": "+1 (924) 542-3148",
+ "address": "604 Leonora Court, Kenvil, Puerto Rico, 9586",
+ "about": "Incididunt tempor deserunt eiusmod laborum aliquip nostrud consectetur exercitation labore sunt exercitation amet id. Sunt ad officia quis eiusmod velit irure voluptate. Tempor duis occaecat ad sint ullamco adipisicing sunt do labore. Id proident amet dolor fugiat deserunt proident labore irure. Lorem est deserunt cupidatat eu aute adipisicing eu. Quis laborum do nulla irure et mollit non. Fugiat exercitation veniam ad elit consequat adipisicing.\r\n",
+ "registered": "2019-01-11T03:50:33 +06:00",
+ "latitude": -48.712358,
+ "longitude": 46.192179,
+ "tags": [
+ "in",
+ "anim",
+ "culpa",
+ "fugiat",
+ "sint",
+ "ex",
+ "dolore"
+ ],
+ "friends": [
+ {
+ "id": 0,
+ "name": "Melody Mcdowell"
+ },
+ {
+ "id": 1,
+ "name": "Reilly Mullen"
+ },
+ {
+ "id": 2,
+ "name": "Lauri Garner"
+ }
+ ],
+ "greeting": "Hello, Collins Morrow! You have 7 unread messages.",
+ "favoriteFruit": "strawberry"
+ },
+ {
+ "_id": "60ca4f9ce984e1b0f55d90b5",
+ "index": 4,
+ "guid": "a666b11e-7ac1-4525-ad7a-0a2ab6046e91",
+ "isActive": false,
+ "balance": "$3,014.28",
+ "picture": "http://placehold.it/32x32",
+ "age": 28,
+ "eyeColor": "brown",
+ "name": "Valentine Klein",
+ "gender": "male",
+ "company": "TERRASYS",
+ "email": "valentineklein@terrasys.com",
+ "phone": "+1 (835) 556-3161",
+ "address": "942 Pulaski Street, Alfarata, Kansas, 1198",
+ "about": "Sint pariatur cillum aliquip ullamco et tempor qui cillum do in dolor. Consequat cillum reprehenderit adipisicing dolor Lorem. Velit fugiat non quis incididunt occaecat velit aliqua voluptate nostrud Lorem consectetur commodo et.\r\n",
+ "registered": "2019-02-20T04:47:41 +06:00",
+ "latitude": 14.080616,
+ "longitude": 100.694685,
+ "tags": [
+ "nulla",
+ "culpa",
+ "anim",
+ "ea",
+ "laborum",
+ "eu",
+ "incididunt"
+ ],
+ "friends": [
+ {
+ "id": 0,
+ "name": "Wilkins Mcknight"
+ },
+ {
+ "id": 1,
+ "name": "Weiss Hunter"
+ },
+ {
+ "id": 2,
+ "name": "Butler Mckinney"
+ }
+ ],
+ "greeting": "Hello, Valentine Klein! You have 8 unread messages.",
+ "favoriteFruit": "banana"
+ },
+ {
+ "_id": "60ca4f9cc03ceef660c19748",
+ "index": 5,
+ "guid": "c06b663c-cc8a-407a-8099-64216899643c",
+ "isActive": false,
+ "balance": "$1,182.77",
+ "picture": "http://placehold.it/32x32",
+ "age": 25,
+ "eyeColor": "brown",
+ "name": "Cleo Hartman",
+ "gender": "female",
+ "company": "GAZAK",
+ "email": "cleohartman@gazak.com",
+ "phone": "+1 (817) 502-2609",
+ "address": "451 Clove Road, Rivereno, North Dakota, 3390",
+ "about": "Non dolor consectetur sit fugiat aute fugiat in esse voluptate officia sit aute. Ut et ex aliquip eu. Enim aliquip aliquip minim ex veniam sunt dolore do dolor reprehenderit pariatur tempor nulla. Sit ut voluptate aliquip pariatur anim commodo ipsum elit aute aliqua adipisicing officia incididunt. Adipisicing irure cupidatat ipsum in id fugiat ad Lorem magna magna.\r\n",
+ "registered": "2018-12-01T07:41:00 +06:00",
+ "latitude": -10.880851,
+ "longitude": 58.654307,
+ "tags": [
+ "ipsum",
+ "do",
+ "mollit",
+ "excepteur",
+ "aute",
+ "dolore",
+ "reprehenderit"
+ ],
+ "friends": [
+ {
+ "id": 0,
+ "name": "Amy Henry"
+ },
+ {
+ "id": 1,
+ "name": "Cathleen Edwards"
+ },
+ {
+ "id": 2,
+ "name": "Carey Terrell"
+ }
+ ],
+ "greeting": "Hello, Cleo Hartman! You have 10 unread messages.",
+ "favoriteFruit": "strawberry"
+ },
+ {
+ "_id": "60ca4f9c30055f4208a15bc9",
+ "index": 6,
+ "guid": "86384b2a-bfc3-43f6-8c28-684236fb557b",
+ "isActive": true,
+ "balance": "$3,461.71",
+ "picture": "http://placehold.it/32x32",
+ "age": 31,
+ "eyeColor": "blue",
+ "name": "Rowena Keller",
+ "gender": "female",
+ "company": "MEDMEX",
+ "email": "rowenakeller@medmex.com",
+ "phone": "+1 (834) 439-3203",
+ "address": "383 Mill Lane, Hannasville, Hawaii, 1404",
+ "about": "Aliquip reprehenderit Lorem duis aliqua. Est exercitation incididunt quis consectetur et fugiat adipisicing nisi reprehenderit amet amet quis dolore. Mollit ullamco tempor in labore ex irure qui et est sint.\r\n",
+ "registered": "2014-09-04T10:21:32 +05:00",
+ "latitude": -81.799165,
+ "longitude": 33.153719,
+ "tags": [
+ "cillum",
+ "cillum",
+ "exercitation",
+ "do",
+ "cillum",
+ "non",
+ "est"
+ ],
+ "friends": [
+ {
+ "id": 0,
+ "name": "Decker Rosales"
+ },
+ {
+ "id": 1,
+ "name": "Katharine Mccullough"
+ },
+ {
+ "id": 2,
+ "name": "Roach Pitts"
+ }
+ ],
+ "greeting": "Hello, Rowena Keller! You have 3 unread messages.",
+ "favoriteFruit": "apple"
+ }
+]
--- /dev/null
+// Everything in this file is marked #private because I do not think
+// that this code will be needed outside of this module. I do not see
+// the value of having access to the tokenizer and parser of JSON directly.
+
+
+package json
+use package core
+
+#private
+Tokenizer :: struct {
+ data: [] u8;
+ use position := Position.{ 0, 1, 1 };
+}
+
+#private
+Token :: struct {
+ Kind :: enum {
+ Invalid;
+
+ Open_Brace; // {
+ Close_Brace; // }
+
+ Open_Bracket; // [
+ Close_Bracket; // ]
+
+ Comma;
+ Colon;
+
+ Null;
+ True;
+ False;
+
+ Integer;
+ Float;
+ String;
+ }
+
+ kind: Kind = .Invalid;
+ text: str = null_str;
+ use position: Position = .{ 0, 1, 1 };
+}
+
+#private
+Position :: struct {
+ offset : u32; // Offset into the stream
+ line, column : u32; // Line and column number
+}
+
+#private
+Tokenizer_Error :: enum {
+ None;
+ EOF;
+ Illegal_Character;
+ String_Unterminated;
+}
+
+
+#private
+token_get :: (use tkn: ^Tokenizer) -> (Token, Tokenizer_Error) {
+ err := Tokenizer_Error.None;
+
+ skip_whitespace(tkn);
+ token := Token.{};
+ token.position = tkn.position;
+
+ curr_char := data[offset];
+ next_char, has_next := next_character(tkn);
+ if !has_next do return .{}, .EOF;
+
+ switch curr_char {
+ case #char "{" do token.kind = .Open_Brace;
+ case #char "}" do token.kind = .Close_Brace;
+ case #char "[" do token.kind = .Open_Bracket;
+ case #char "]" do token.kind = .Close_Bracket;
+ case #char "," do token.kind = .Comma;
+ case #char ":" do token.kind = .Colon;
+
+ case #char "a" .. #char "z" {
+ token.kind = .Invalid;
+ skip_alpha_numeric(tkn);
+
+ identifier := data.data[token.offset .. offset];
+ if identifier == "null" do token.kind = .Null;
+ if identifier == "true" do token.kind = .True;
+ if identifier == "false" do token.kind = .False;
+ }
+
+ case #char "-" {
+ next_character(tkn);
+ switch data[offset] {
+ case #char "0" .. #char "9" ---
+ case #default {
+ err = .Illegal_Character;
+ break break;
+ }
+ }
+
+ fallthrough;
+ }
+
+ case #char "0" .. #char "9" {
+ token.kind = .Integer;
+ skip_numeric(tkn);
+
+ if data[offset] == #char "." {
+ token.kind = .Float;
+ next_character(tkn);
+ skip_numeric(tkn);
+ }
+
+ if data[offset] == #char "e" || data[offset] == #char "E" {
+ next_character(tkn);
+ if data[offset] == #char "-" || data[offset] == #char "+" {
+ next_character(tkn);
+ }
+ skip_numeric(tkn);
+ }
+ }
+
+ case #char "\"" {
+ token.kind = .String;
+
+ while offset < data.count {
+ ch := data[offset];
+ if ch == #char "\n" {
+ err = .String_Unterminated;
+ break break;
+ }
+
+ next_character(tkn);
+ if ch == #char "\"" {
+ break;
+ }
+
+ if ch == #char "\\" {
+ skip_escape(tkn);
+ }
+ }
+ }
+ }
+
+ token.text = data.data[token.offset .. offset];
+
+ if token.kind == .Invalid do err = .Illegal_Character;
+
+ return token, err;
+}
+
+#private_file
+next_character :: (use tkn: ^Tokenizer) -> (u8, bool) {
+ if offset >= data.count do return 0, false;
+
+ retval := data[offset];
+ offset += 1;
+ column += offset;
+
+ return retval, true;
+}
+
+#private_file
+skip_whitespace :: (use tkn: ^Tokenizer) {
+ while offset < data.count {
+ switch data[offset] {
+ case #char "\t", #char " ", #char "\r", #char "\v" {
+ next_character(tkn);
+ }
+
+ case #char "\n" {
+ line += 1;
+ column = 1;
+ offset += 1;
+ }
+
+ case #default {
+ break break;
+ }
+ }
+ }
+}
+
+#private_file
+skip_alpha_numeric :: (use tkn: ^Tokenizer) {
+ while offset < data.count {
+ switch data[offset] {
+ case #char "A" .. #char "Z", #char "a" .. #char "z", #char "0" .. #char "9", #char "_" {
+ next_character(tkn);
+ continue;
+ }
+ }
+
+ break;
+ }
+}
+
+#private_file
+skip_numeric :: (use tkn: ^Tokenizer) {
+ while offset < data.count {
+ switch data[offset] {
+ case #char "0" .. #char "9" {
+ next_character(tkn);
+ continue;
+ }
+ }
+
+ break;
+ }
+}
+
+#private_file
+skip_escape :: (use tkn: ^Tokenizer) {
+ switch data[offset] {
+ case #char "u" {
+ for i: 4 {
+ ch, _ := next_character(tkn);
+ switch ch {
+ case #char "0" .. #char "9",
+ #char "A" .. #char "F",
+ #char "a" .. #char "f" ---
+
+ case #default do return;
+ }
+ }
+ }
+
+ case #default {
+ next_character(tkn);
+ }
+ }
+}
\ No newline at end of file
package json
use package core
-null_value : Value
+null_value := Value.{}
+
+Json :: struct {
+ // This is the allocator for all of the values in the JSON tree.
+ // It is not the allocator the arrays and objects however. Those
+ // have their own allocator, which I'm assuming will always be
+ // the general purpose heap allocator.
+ allocator: Allocator;
+
+ root: ^Value;
+}
Value :: struct {
Type :: enum {
Object;
}
- type : Type;
- allocator : Allocator;
- use value : struct #union {
- bool_ : bool;
- int_ : i64;
- float_ : f64;
- str_ : str; // This is allocated out of the allocator above.
-
- @CompilerBug @Cleanup // I don't want these to be pointers in the long run. In theory, they should be
- // able to be normal values, but there is a compiler bug that prevents the size and alignment of Value
- // being known.
- //
- // Thinking about it a little more, I think having these be pointers will be better from a performance
- // point of view, because the overhead of copying the return/parameter values would be significant.
- array_ : [..] ^Value;
- object_ : [..] struct {
- key : str; // This is allocated out of the allocator on the Value.
- value : ^Value;
- };
+ type := Type.Null;
+}
+
+Value_Bool :: struct {
+ use base := Value.{ type = .Bool };
+ bool_: bool;
+}
+
+Value_Integer :: struct {
+ use base := Value.{ type = .Integer };
+ int_: i64;
+}
+
+Value_Float :: struct {
+ use base := Value.{ type = .Float };
+ float_: f64;
+}
+
+Value_String :: struct {
+ use base := Value.{ type = .String };
+ str_: str;
+}
+
+Value_Array :: struct {
+ use base := Value.{ type = .Array };
+ array_: [..] ^Value;
+}
+
+Value_Object :: struct {
+ use base := Value.{ type = .Object };
+ object_: [..] struct {
+ key : str;
+ value : ^Value;
};
}
return v == ^null_value || v.type == .Null;
}
-to_str :: (v: ^Value) -> str do return null_str;
+to_str :: (v: ^Value) -> str {
+ if v == null do return null_str;
+
+ switch v.type {
+ case .String do return (cast(^Value_String) v).str_;
+ case #default do return "";
+ }
+}
+#operator [] get
get :: (v: ^Value, key: str) -> ^Value {
if v.type != .Object do return ^null_value;
- for ^entry: v.object_ {
+ v_obj := cast(^Value_Object) v;
+
+ for ^entry: v_obj.object_ {
if entry.key == key do return entry.value;
}
return ^null_value;
}
-free :: (v: ^Value) do switch v.type {
- case .String {
- raw_free(v.allocator, v.str_.data);
- }
+free :: proc {
+ (v: ^Value, allocator: Allocator) do switch v.type {
+ case .String {
+ v_str := cast(^Value_String) v;
+ raw_free(allocator, v_str.str_.data);
+ }
- case .Array {
- for elem: v.array_ {
- free(elem);
+ case .Array {
+ v_arr := cast(^Value_Array) v;
+ for elem: v_arr.array_ {
+ free(elem, allocator);
+ }
+ array.free(^v_arr.array_);
}
- array.free(^v.array_);
- }
- case .Object {
- for ^entry: v.object_ {
- raw_free(v.allocator, entry.key.data);
- free(entry.value);
+ case .Object {
+ v_obj := cast(^Value_Object) v;
+ for ^entry: v_obj.object_ {
+ raw_free(allocator, entry.key.data);
+ free(entry.value, allocator);
+ }
+ array.free(^v_obj.object_);
}
- array.free(^v.object_);
- }
+ },
+
+ (use j: Json) {
+ free(root, allocator);
+ },
}