| ... | @@ -3,6 +3,7 @@ | ... | @@ -3,6 +3,7 @@ |
| 3 | // https://tools.ietf.org/html/rfc8259 | 3 | // https://tools.ietf.org/html/rfc8259 |
| 4 | | 4 | |
| 5 | const std = @import("index.zig"); | 5 | const std = @import("index.zig"); |
| | 6 | const debug = std.debug; |
| 6 | const mem = std.mem; | 7 | const mem = std.mem; |
| 7 | | 8 | |
| 8 | const u1 = @IntType(false, 1); | 9 | const u1 = @IntType(false, 1); |
| ... | @@ -86,7 +87,9 @@ pub const Token = struct { | ... | @@ -86,7 +87,9 @@ pub const Token = struct { |
| 86 | // parsing state requires ~40-50 bytes of stack space. | 87 | // parsing state requires ~40-50 bytes of stack space. |
| 87 | // | 88 | // |
| 88 | // Conforms strictly to RFC8529. | 89 | // Conforms strictly to RFC8529. |
| 89 | pub const StreamingJsonParser = struct { | 90 | // |
| | 91 | // For a non-byte based wrapper, consider using TokenStream instead. |
| | 92 | pub const StreamingParser = struct { |
| 90 | // Current state | 93 | // Current state |
| 91 | state: State, | 94 | state: State, |
| 92 | // How many bytes we have counted for the current token | 95 | // How many bytes we have counted for the current token |
| ... | @@ -109,13 +112,13 @@ pub const StreamingJsonParser = struct { | ... | @@ -109,13 +112,13 @@ pub const StreamingJsonParser = struct { |
| 109 | const array_bit = 1; | 112 | const array_bit = 1; |
| 110 | const max_stack_size = @maxValue(u8); | 113 | const max_stack_size = @maxValue(u8); |
| 111 | | 114 | |
| 112 | pub fn init() StreamingJsonParser { | 115 | pub fn init() StreamingParser { |
| 113 | var p: StreamingJsonParser = undefined; | 116 | var p: StreamingParser = undefined; |
| 114 | p.reset(); | 117 | p.reset(); |
| 115 | return p; | 118 | return p; |
| 116 | } | 119 | } |
| 117 | | 120 | |
| 118 | pub fn reset(p: *StreamingJsonParser) void { | 121 | pub fn reset(p: *StreamingParser) void { |
| 119 | p.state = State.TopLevelBegin; | 122 | p.state = State.TopLevelBegin; |
| 120 | p.count = 0; | 123 | p.count = 0; |
| 121 | // Set before ever read in main transition function | 124 | // Set before ever read in main transition function |
| ... | @@ -175,7 +178,7 @@ pub const StreamingJsonParser = struct { | ... | @@ -175,7 +178,7 @@ pub const StreamingJsonParser = struct { |
| 175 | | 178 | |
| 176 | // Only call this function to generate array/object final state. | 179 | // Only call this function to generate array/object final state. |
| 177 | pub fn fromInt(x: var) State { | 180 | pub fn fromInt(x: var) State { |
| 178 | std.debug.assert(x == 0 or x == 1); | 181 | debug.assert(x == 0 or x == 1); |
| 179 | const T = @TagType(State); | 182 | const T = @TagType(State); |
| 180 | return State(T(x)); | 183 | return State(T(x)); |
| 181 | } | 184 | } |
| ... | @@ -205,7 +208,7 @@ pub const StreamingJsonParser = struct { | ... | @@ -205,7 +208,7 @@ pub const StreamingJsonParser = struct { |
| 205 | // tokens. token2 is always null if token1 is null. | 208 | // tokens. token2 is always null if token1 is null. |
| 206 | // | 209 | // |
| 207 | // There is currently no error recovery on a bad stream. | 210 | // There is currently no error recovery on a bad stream. |
| 208 | pub fn feed(p: *StreamingJsonParser, c: u8, token1: *?Token, token2: *?Token) Error!void { | 211 | pub fn feed(p: *StreamingParser, c: u8, token1: *?Token, token2: *?Token) Error!void { |
| 209 | token1.* = null; | 212 | token1.* = null; |
| 210 | token2.* = null; | 213 | token2.* = null; |
| 211 | p.count += 1; | 214 | p.count += 1; |
| ... | @@ -217,7 +220,7 @@ pub const StreamingJsonParser = struct { | ... | @@ -217,7 +220,7 @@ pub const StreamingJsonParser = struct { |
| 217 | } | 220 | } |
| 218 | | 221 | |
| 219 | // Perform a single transition on the state machine and return any possible token. | 222 | // Perform a single transition on the state machine and return any possible token. |
| 220 | fn transition(p: *StreamingJsonParser, c: u8, token: *?Token) Error!bool { | 223 | fn transition(p: *StreamingParser, c: u8, token: *?Token) Error!bool { |
| 221 | switch (p.state) { | 224 | switch (p.state) { |
| 222 | State.TopLevelBegin => switch (c) { | 225 | State.TopLevelBegin => switch (c) { |
| 223 | '{' => { | 226 | '{' => { |
| ... | @@ -852,10 +855,116 @@ pub const StreamingJsonParser = struct { | ... | @@ -852,10 +855,116 @@ pub const StreamingJsonParser = struct { |
| 852 | } | 855 | } |
| 853 | }; | 856 | }; |
| 854 | | 857 | |
| | 858 | // A small wrapper over a StreamingParser for full slices. Returns a stream of json Tokens. |
| | 859 | pub const TokenStream = struct { |
| | 860 | i: usize, |
| | 861 | slice: []const u8, |
| | 862 | parser: StreamingParser, |
| | 863 | token: ?Token, |
| | 864 | |
| | 865 | pub fn init(slice: []const u8) TokenStream { |
| | 866 | return TokenStream{ |
| | 867 | .i = 0, |
| | 868 | .slice = slice, |
| | 869 | .parser = StreamingParser.init(), |
| | 870 | .token = null, |
| | 871 | }; |
| | 872 | } |
| | 873 | |
| | 874 | pub fn next(self: *TokenStream) !?Token { |
| | 875 | if (self.token) |token| { |
| | 876 | self.token = null; |
| | 877 | return token; |
| | 878 | } |
| | 879 | |
| | 880 | var t1: ?Token = undefined; |
| | 881 | var t2: ?Token = undefined; |
| | 882 | |
| | 883 | while (self.i < self.slice.len) { |
| | 884 | try self.parser.feed(self.slice[self.i], &t1, &t2); |
| | 885 | self.i += 1; |
| | 886 | |
| | 887 | if (t1) |token| { |
| | 888 | self.token = t2; |
| | 889 | return token; |
| | 890 | } |
| | 891 | } |
| | 892 | |
| | 893 | if (self.i > self.slice.len) { |
| | 894 | try self.parser.feed(' ', &t1, &t2); |
| | 895 | self.i += 1; |
| | 896 | |
| | 897 | if (t1) |token| { |
| | 898 | return token; |
| | 899 | } |
| | 900 | } |
| | 901 | |
| | 902 | return null; |
| | 903 | } |
| | 904 | }; |
| | 905 | |
| | 906 | fn checkNext(p: *TokenStream, id: Token.Id) void { |
| | 907 | const token = ??(p.next() catch unreachable); |
| | 908 | debug.assert(token.id == id); |
| | 909 | } |
| | 910 | |
| | 911 | test "token" { |
| | 912 | const s = |
| | 913 | \\{ |
| | 914 | \\ "Image": { |
| | 915 | \\ "Width": 800, |
| | 916 | \\ "Height": 600, |
| | 917 | \\ "Title": "View from 15th Floor", |
| | 918 | \\ "Thumbnail": { |
| | 919 | \\ "Url": "http://www.example.com/image/481989943", |
| | 920 | \\ "Height": 125, |
| | 921 | \\ "Width": 100 |
| | 922 | \\ }, |
| | 923 | \\ "Animated" : false, |
| | 924 | \\ "IDs": [116, 943, 234, 38793] |
| | 925 | \\ } |
| | 926 | \\} |
| | 927 | ; |
| | 928 | |
| | 929 | var p = TokenStream.init(s); |
| | 930 | |
| | 931 | checkNext(&p, Token.Id.ObjectBegin); |
| | 932 | checkNext(&p, Token.Id.String); // Image |
| | 933 | checkNext(&p, Token.Id.ObjectBegin); |
| | 934 | checkNext(&p, Token.Id.String); // Width |
| | 935 | checkNext(&p, Token.Id.Number); |
| | 936 | checkNext(&p, Token.Id.String); // Height |
| | 937 | checkNext(&p, Token.Id.Number); |
| | 938 | checkNext(&p, Token.Id.String); // Title |
| | 939 | checkNext(&p, Token.Id.String); |
| | 940 | checkNext(&p, Token.Id.String); // Thumbnail |
| | 941 | checkNext(&p, Token.Id.ObjectBegin); |
| | 942 | checkNext(&p, Token.Id.String); // Url |
| | 943 | checkNext(&p, Token.Id.String); |
| | 944 | checkNext(&p, Token.Id.String); // Height |
| | 945 | checkNext(&p, Token.Id.Number); |
| | 946 | checkNext(&p, Token.Id.String); // Width |
| | 947 | checkNext(&p, Token.Id.Number); |
| | 948 | checkNext(&p, Token.Id.ObjectEnd); |
| | 949 | checkNext(&p, Token.Id.String); // Animated |
| | 950 | checkNext(&p, Token.Id.False); |
| | 951 | checkNext(&p, Token.Id.String); // IDs |
| | 952 | checkNext(&p, Token.Id.ArrayBegin); |
| | 953 | checkNext(&p, Token.Id.Number); |
| | 954 | checkNext(&p, Token.Id.Number); |
| | 955 | checkNext(&p, Token.Id.Number); |
| | 956 | checkNext(&p, Token.Id.Number); |
| | 957 | checkNext(&p, Token.Id.ArrayEnd); |
| | 958 | checkNext(&p, Token.Id.ObjectEnd); |
| | 959 | checkNext(&p, Token.Id.ObjectEnd); |
| | 960 | |
| | 961 | debug.assert((try p.next()) == null); |
| | 962 | } |
| | 963 | |
| 855 | // Validate a JSON string. This does not limit number precision so a decoder may not necessarily | 964 | // Validate a JSON string. This does not limit number precision so a decoder may not necessarily |
| 856 | // be able to decode the string even if this returns true. | 965 | // be able to decode the string even if this returns true. |
| 857 | pub fn validate(s: []const u8) bool { | 966 | pub fn validate(s: []const u8) bool { |
| 858 | var p = StreamingJsonParser.init(); | 967 | var p = StreamingParser.init(); |
| 859 | | 968 | |
| 860 | for (s) |c, i| { | 969 | for (s) |c, i| { |
| 861 | var token1: ?Token = undefined; | 970 | var token1: ?Token = undefined; |
| ... | @@ -897,46 +1006,46 @@ pub const Value = union(enum) { | ... | @@ -897,46 +1006,46 @@ pub const Value = union(enum) { |
| 897 | pub fn dump(self: *const Value) void { | 1006 | pub fn dump(self: *const Value) void { |
| 898 | switch (self.*) { | 1007 | switch (self.*) { |
| 899 | Value.Null => { | 1008 | Value.Null => { |
| 900 | std.debug.warn("null"); | 1009 | debug.warn("null"); |
| 901 | }, | 1010 | }, |
| 902 | Value.Bool => |inner| { | 1011 | Value.Bool => |inner| { |
| 903 | std.debug.warn("{}", inner); | 1012 | debug.warn("{}", inner); |
| 904 | }, | 1013 | }, |
| 905 | Value.Integer => |inner| { | 1014 | Value.Integer => |inner| { |
| 906 | std.debug.warn("{}", inner); | 1015 | debug.warn("{}", inner); |
| 907 | }, | 1016 | }, |
| 908 | Value.Float => |inner| { | 1017 | Value.Float => |inner| { |
| 909 | std.debug.warn("{.5}", inner); | 1018 | debug.warn("{.5}", inner); |
| 910 | }, | 1019 | }, |
| 911 | Value.String => |inner| { | 1020 | Value.String => |inner| { |
| 912 | std.debug.warn("\"{}\"", inner); | 1021 | debug.warn("\"{}\"", inner); |
| 913 | }, | 1022 | }, |
| 914 | Value.Array => |inner| { | 1023 | Value.Array => |inner| { |
| 915 | var not_first = false; | 1024 | var not_first = false; |
| 916 | std.debug.warn("["); | 1025 | debug.warn("["); |
| 917 | for (inner.toSliceConst()) |value| { | 1026 | for (inner.toSliceConst()) |value| { |
| 918 | if (not_first) { | 1027 | if (not_first) { |
| 919 | std.debug.warn(","); | 1028 | debug.warn(","); |
| 920 | } | 1029 | } |
| 921 | not_first = true; | 1030 | not_first = true; |
| 922 | value.dump(); | 1031 | value.dump(); |
| 923 | } | 1032 | } |
| 924 | std.debug.warn("]"); | 1033 | debug.warn("]"); |
| 925 | }, | 1034 | }, |
| 926 | Value.Object => |inner| { | 1035 | Value.Object => |inner| { |
| 927 | var not_first = false; | 1036 | var not_first = false; |
| 928 | std.debug.warn("{{"); | 1037 | debug.warn("{{"); |
| 929 | var it = inner.iterator(); | 1038 | var it = inner.iterator(); |
| 930 | | 1039 | |
| 931 | while (it.next()) |entry| { | 1040 | while (it.next()) |entry| { |
| 932 | if (not_first) { | 1041 | if (not_first) { |
| 933 | std.debug.warn(","); | 1042 | debug.warn(","); |
| 934 | } | 1043 | } |
| 935 | not_first = true; | 1044 | not_first = true; |
| 936 | std.debug.warn("\"{}\":", entry.key); | 1045 | debug.warn("\"{}\":", entry.key); |
| 937 | entry.value.dump(); | 1046 | entry.value.dump(); |
| 938 | } | 1047 | } |
| 939 | std.debug.warn("}}"); | 1048 | debug.warn("}}"); |
| 940 | }, | 1049 | }, |
| 941 | } | 1050 | } |
| 942 | } | 1051 | } |
| ... | @@ -952,53 +1061,53 @@ pub const Value = union(enum) { | ... | @@ -952,53 +1061,53 @@ pub const Value = union(enum) { |
| 952 | fn dumpIndentLevel(self: *const Value, indent: usize, level: usize) void { | 1061 | fn dumpIndentLevel(self: *const Value, indent: usize, level: usize) void { |
| 953 | switch (self.*) { | 1062 | switch (self.*) { |
| 954 | Value.Null => { | 1063 | Value.Null => { |
| 955 | std.debug.warn("null"); | 1064 | debug.warn("null"); |
| 956 | }, | 1065 | }, |
| 957 | Value.Bool => |inner| { | 1066 | Value.Bool => |inner| { |
| 958 | std.debug.warn("{}", inner); | 1067 | debug.warn("{}", inner); |
| 959 | }, | 1068 | }, |
| 960 | Value.Integer => |inner| { | 1069 | Value.Integer => |inner| { |
| 961 | std.debug.warn("{}", inner); | 1070 | debug.warn("{}", inner); |
| 962 | }, | 1071 | }, |
| 963 | Value.Float => |inner| { | 1072 | Value.Float => |inner| { |
| 964 | std.debug.warn("{.5}", inner); | 1073 | debug.warn("{.5}", inner); |
| 965 | }, | 1074 | }, |
| 966 | Value.String => |inner| { | 1075 | Value.String => |inner| { |
| 967 | std.debug.warn("\"{}\"", inner); | 1076 | debug.warn("\"{}\"", inner); |
| 968 | }, | 1077 | }, |
| 969 | Value.Array => |inner| { | 1078 | Value.Array => |inner| { |
| 970 | var not_first = false; | 1079 | var not_first = false; |
| 971 | std.debug.warn("[\n"); | 1080 | debug.warn("[\n"); |
| 972 | | 1081 | |
| 973 | for (inner.toSliceConst()) |value| { | 1082 | for (inner.toSliceConst()) |value| { |
| 974 | if (not_first) { | 1083 | if (not_first) { |
| 975 | std.debug.warn(",\n"); | 1084 | debug.warn(",\n"); |
| 976 | } | 1085 | } |
| 977 | not_first = true; | 1086 | not_first = true; |
| 978 | padSpace(level + indent); | 1087 | padSpace(level + indent); |
| 979 | value.dumpIndentLevel(indent, level + indent); | 1088 | value.dumpIndentLevel(indent, level + indent); |
| 980 | } | 1089 | } |
| 981 | std.debug.warn("\n"); | 1090 | debug.warn("\n"); |
| 982 | padSpace(level); | 1091 | padSpace(level); |
| 983 | std.debug.warn("]"); | 1092 | debug.warn("]"); |
| 984 | }, | 1093 | }, |
| 985 | Value.Object => |inner| { | 1094 | Value.Object => |inner| { |
| 986 | var not_first = false; | 1095 | var not_first = false; |
| 987 | std.debug.warn("{{\n"); | 1096 | debug.warn("{{\n"); |
| 988 | var it = inner.iterator(); | 1097 | var it = inner.iterator(); |
| 989 | | 1098 | |
| 990 | while (it.next()) |entry| { | 1099 | while (it.next()) |entry| { |
| 991 | if (not_first) { | 1100 | if (not_first) { |
| 992 | std.debug.warn(",\n"); | 1101 | debug.warn(",\n"); |
| 993 | } | 1102 | } |
| 994 | not_first = true; | 1103 | not_first = true; |
| 995 | padSpace(level + indent); | 1104 | padSpace(level + indent); |
| 996 | std.debug.warn("\"{}\": ", entry.key); | 1105 | debug.warn("\"{}\": ", entry.key); |
| 997 | entry.value.dumpIndentLevel(indent, level + indent); | 1106 | entry.value.dumpIndentLevel(indent, level + indent); |
| 998 | } | 1107 | } |
| 999 | std.debug.warn("\n"); | 1108 | debug.warn("\n"); |
| 1000 | padSpace(level); | 1109 | padSpace(level); |
| 1001 | std.debug.warn("}}"); | 1110 | debug.warn("}}"); |
| 1002 | }, | 1111 | }, |
| 1003 | } | 1112 | } |
| 1004 | } | 1113 | } |
| ... | @@ -1006,13 +1115,13 @@ pub const Value = union(enum) { | ... | @@ -1006,13 +1115,13 @@ pub const Value = union(enum) { |
| 1006 | fn padSpace(indent: usize) void { | 1115 | fn padSpace(indent: usize) void { |
| 1007 | var i: usize = 0; | 1116 | var i: usize = 0; |
| 1008 | while (i < indent) : (i += 1) { | 1117 | while (i < indent) : (i += 1) { |
| 1009 | std.debug.warn(" "); | 1118 | debug.warn(" "); |
| 1010 | } | 1119 | } |
| 1011 | } | 1120 | } |
| 1012 | }; | 1121 | }; |
| 1013 | | 1122 | |
| 1014 | // A non-stream JSON parser which constructs a tree of Value's. | 1123 | // A non-stream JSON parser which constructs a tree of Value's. |
| 1015 | pub const JsonParser = struct { | 1124 | pub const Parser = struct { |
| 1016 | allocator: *Allocator, | 1125 | allocator: *Allocator, |
| 1017 | state: State, | 1126 | state: State, |
| 1018 | copy_strings: bool, | 1127 | copy_strings: bool, |
| ... | @@ -1026,8 +1135,8 @@ pub const JsonParser = struct { | ... | @@ -1026,8 +1135,8 @@ pub const JsonParser = struct { |
| 1026 | Simple, | 1135 | Simple, |
| 1027 | }; | 1136 | }; |
| 1028 | | 1137 | |
| 1029 | pub fn init(allocator: *Allocator, copy_strings: bool) JsonParser { | 1138 | pub fn init(allocator: *Allocator, copy_strings: bool) Parser { |
| 1030 | return JsonParser{ | 1139 | return Parser{ |
| 1031 | .allocator = allocator, | 1140 | .allocator = allocator, |
| 1032 | .state = State.Simple, | 1141 | .state = State.Simple, |
| 1033 | .copy_strings = copy_strings, | 1142 | .copy_strings = copy_strings, |
| ... | @@ -1035,52 +1144,26 @@ pub const JsonParser = struct { | ... | @@ -1035,52 +1144,26 @@ pub const JsonParser = struct { |
| 1035 | }; | 1144 | }; |
| 1036 | } | 1145 | } |
| 1037 | | 1146 | |
| 1038 | pub fn deinit(p: *JsonParser) void { | 1147 | pub fn deinit(p: *Parser) void { |
| 1039 | p.stack.deinit(); | 1148 | p.stack.deinit(); |
| 1040 | } | 1149 | } |
| 1041 | | 1150 | |
| 1042 | pub fn reset(p: *JsonParser) void { | 1151 | pub fn reset(p: *Parser) void { |
| 1043 | p.state = State.Simple; | 1152 | p.state = State.Simple; |
| 1044 | p.stack.shrink(0); | 1153 | p.stack.shrink(0); |
| 1045 | } | 1154 | } |
| 1046 | | 1155 | |
| 1047 | pub fn parse(p: *JsonParser, input: []const u8) !ValueTree { | 1156 | pub fn parse(p: *Parser, input: []const u8) !ValueTree { |
| 1048 | var mp = StreamingJsonParser.init(); | 1157 | var s = TokenStream.init(input); |
| 1049 | | 1158 | |
| 1050 | var arena = ArenaAllocator.init(p.allocator); | 1159 | var arena = ArenaAllocator.init(p.allocator); |
| 1051 | errdefer arena.deinit(); | 1160 | errdefer arena.deinit(); |
| 1052 | | 1161 | |
| 1053 | for (input) |c, i| { | 1162 | while (try s.next()) |token| { |
| 1054 | var mt1: ?Token = undefined; | 1163 | try p.transition(&arena.allocator, input, s.i - 1, token); |
| 1055 | var mt2: ?Token = undefined; | | |
| 1056 | | | |
| 1057 | try mp.feed(c, &mt1, &mt2); | | |
| 1058 | if (mt1) |t1| { | | |
| 1059 | try p.transition(&arena.allocator, input, i, t1); | | |
| 1060 | | | |
| 1061 | if (mt2) |t2| { | | |
| 1062 | try p.transition(&arena.allocator, input, i, t2); | | |
| 1063 | } | | |
| 1064 | } | | |
| 1065 | } | 1164 | } |
| 1066 | | 1165 | |
| 1067 | // Handle top-level lonely number values. | 1166 | debug.assert(p.stack.len == 1); |
| 1068 | { | | |
| 1069 | const i = input.len; | | |
| 1070 | var mt1: ?Token = undefined; | | |
| 1071 | var mt2: ?Token = undefined; | | |
| 1072 | | | |
| 1073 | try mp.feed(' ', &mt1, &mt2); | | |
| 1074 | if (mt1) |t1| { | | |
| 1075 | try p.transition(&arena.allocator, input, i, t1); | | |
| 1076 | } | | |
| 1077 | } | | |
| 1078 | | | |
| 1079 | if (!mp.complete) { | | |
| 1080 | return error.IncompleteJsonInput; | | |
| 1081 | } | | |
| 1082 | | | |
| 1083 | std.debug.assert(p.stack.len == 1); | | |
| 1084 | | 1167 | |
| 1085 | return ValueTree{ | 1168 | return ValueTree{ |
| 1086 | .arena = arena, | 1169 | .arena = arena, |
| ... | @@ -1090,7 +1173,7 @@ pub const JsonParser = struct { | ... | @@ -1090,7 +1173,7 @@ pub const JsonParser = struct { |
| 1090 | | 1173 | |
| 1091 | // Even though p.allocator exists, we take an explicit allocator so that allocation state | 1174 | // Even though p.allocator exists, we take an explicit allocator so that allocation state |
| 1092 | // can be cleaned up on error correctly during a `parse` on call. | 1175 | // can be cleaned up on error correctly during a `parse` on call. |
| 1093 | fn transition(p: *JsonParser, allocator: *Allocator, input: []const u8, i: usize, token: *const Token) !void { | 1176 | fn transition(p: *Parser, allocator: *Allocator, input: []const u8, i: usize, token: *const Token) !void { |
| 1094 | switch (p.state) { | 1177 | switch (p.state) { |
| 1095 | State.ObjectKey => switch (token.id) { | 1178 | State.ObjectKey => switch (token.id) { |
| 1096 | Token.Id.ObjectEnd => { | 1179 | Token.Id.ObjectEnd => { |
| ... | @@ -1223,7 +1306,7 @@ pub const JsonParser = struct { | ... | @@ -1223,7 +1306,7 @@ pub const JsonParser = struct { |
| 1223 | } | 1306 | } |
| 1224 | } | 1307 | } |
| 1225 | | 1308 | |
| 1226 | fn pushToParent(p: *JsonParser, value: *const Value) !void { | 1309 | fn pushToParent(p: *Parser, value: *const Value) !void { |
| 1227 | switch (p.stack.at(p.stack.len - 1)) { | 1310 | switch (p.stack.at(p.stack.len - 1)) { |
| 1228 | // Object Parent -> [ ..., object, <key>, value ] | 1311 | // Object Parent -> [ ..., object, <key>, value ] |
| 1229 | Value.String => |key| { | 1312 | Value.String => |key| { |
| ... | @@ -1244,14 +1327,14 @@ pub const JsonParser = struct { | ... | @@ -1244,14 +1327,14 @@ pub const JsonParser = struct { |
| 1244 | } | 1327 | } |
| 1245 | } | 1328 | } |
| 1246 | | 1329 | |
| 1247 | fn parseString(p: *JsonParser, allocator: *Allocator, token: *const Token, input: []const u8, i: usize) !Value { | 1330 | fn parseString(p: *Parser, allocator: *Allocator, token: *const Token, input: []const u8, i: usize) !Value { |
| 1248 | // TODO: We don't strictly have to copy values which do not contain any escape | 1331 | // TODO: We don't strictly have to copy values which do not contain any escape |
| 1249 | // characters if flagged with the option. | 1332 | // characters if flagged with the option. |
| 1250 | const slice = token.slice(input, i); | 1333 | const slice = token.slice(input, i); |
| 1251 | return Value{ .String = try mem.dupe(p.allocator, u8, slice) }; | 1334 | return Value{ .String = try mem.dupe(p.allocator, u8, slice) }; |
| 1252 | } | 1335 | } |
| 1253 | | 1336 | |
| 1254 | fn parseNumber(p: *JsonParser, token: *const Token, input: []const u8, i: usize) !Value { | 1337 | fn parseNumber(p: *Parser, token: *const Token, input: []const u8, i: usize) !Value { |
| 1255 | return if (token.number_is_integer) | 1338 | return if (token.number_is_integer) |
| 1256 | Value{ .Integer = try std.fmt.parseInt(i64, token.slice(input, i), 10) } | 1339 | Value{ .Integer = try std.fmt.parseInt(i64, token.slice(input, i), 10) } |
| 1257 | else | 1340 | else |
| ... | @@ -1259,10 +1342,8 @@ pub const JsonParser = struct { | ... | @@ -1259,10 +1342,8 @@ pub const JsonParser = struct { |
| 1259 | } | 1342 | } |
| 1260 | }; | 1343 | }; |
| 1261 | | 1344 | |
| 1262 | const debug = std.debug; | | |
| 1263 | | | |
| 1264 | test "json parser dynamic" { | 1345 | test "json parser dynamic" { |
| 1265 | var p = JsonParser.init(std.debug.global_allocator, false); | 1346 | var p = Parser.init(debug.global_allocator, false); |
| 1266 | defer p.deinit(); | 1347 | defer p.deinit(); |
| 1267 | | 1348 | |
| 1268 | const s = | 1349 | const s = |