authorgravatar for marc@tiehu.isMarc Tiehuis <marc@tiehu.is> 2018-06-07 03:24:36+12:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-06-06 11:24:36-04:00
loge7f141b3762b9b6c07e17cfa68f9d4c3fd02aba2
tree87b22a6992207d3f8f1523aa71cce05ae4441f59
parentf389e5373580a5a4ac48ccdb8da9dc951c01dee5

Add json.TokenStream (#1062)

This hides some of the low-level parsing details from the StreamingParser. These don't need to be known when parsing a complete slice at once (which is we can usually do). Also, remove `Json` from Parser names. The namespace `json` is sufficient.

1 files changed, 159 insertions(+), 78 deletions(-)

std/json.zig+159-78
...@@ -3,6 +3,7 @@...@@ -3,6 +3,7 @@
3// https://tools.ietf.org/html/rfc82593// https://tools.ietf.org/html/rfc8259
44
5const std = @import("index.zig");5const std = @import("index.zig");
6const debug = std.debug;
6const mem = std.mem;7const mem = std.mem;
78
8const u1 = @IntType(false, 1);9const 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.
89pub const StreamingJsonParser = struct {90//
91// For a non-byte based wrapper, consider using TokenStream instead.
92pub const StreamingParser = struct {
90 // Current state93 // Current state
91 state: State,94 state: State,
92 // How many bytes we have counted for the current token95 // 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);
111114
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 }
117120
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 function124 // Set before ever read in main transition function
...@@ -175,7 +178,7 @@ pub const StreamingJsonParser = struct {...@@ -175,7 +178,7 @@ pub const StreamingJsonParser = struct {
175178
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 }
218221
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};
854857
858// A small wrapper over a StreamingParser for full slices. Returns a stream of json Tokens.
859pub 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
906fn checkNext(p: *TokenStream, id: Token.Id) void {
907 const token = ??(p.next() catch unreachable);
908 debug.assert(token.id == id);
909}
910
911test "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 necessarily964// 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.
857pub fn validate(s: []const u8) bool {966pub fn validate(s: []const u8) bool {
858 var p = StreamingJsonParser.init();967 var p = StreamingParser.init();
859968
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();
9301039
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");
9721081
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();
9891098
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};
10131122
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.
1015pub const JsonParser = struct {1124pub 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 };
10281137
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 }
10371146
1038 pub fn deinit(p: *JsonParser) void {1147 pub fn deinit(p: *Parser) void {
1039 p.stack.deinit();1148 p.stack.deinit();
1040 }1149 }
10411150
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 }
10461155
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);
10491158
1050 var arena = ArenaAllocator.init(p.allocator);1159 var arena = ArenaAllocator.init(p.allocator);
1051 errdefer arena.deinit();1160 errdefer arena.deinit();
10521161
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 }
10661165
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);
10841167
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 {
10901173
1091 // Even though p.allocator exists, we take an explicit allocator so that allocation state1174 // 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 }
12251308
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 }
12461329
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 escape1331 // 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 }
12531336
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 else1340 else
...@@ -1259,10 +1342,8 @@ pub const JsonParser = struct {...@@ -1259,10 +1342,8 @@ pub const JsonParser = struct {
1259 }1342 }
1260};1343};
12611344
1262const debug = std.debug;
1263
1264test "json parser dynamic" {1345test "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();
12671348
1268 const s =1349 const s =