authorgravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2024-06-01 05:43:37 -07:00
committergravatar for hello@nektro.netMeghan Denny <hello@nektro.net> 2024-06-01 05:43:37 -07:00
loge316f6825a11e85a0d1c96f138b4138f8832eb48
treecc7cedf699aaf0559c75f4390bac3e686a0ca5c3
parentf6876ad86acca947988ae1609d88d83d1668907a

pass all

284/284 tests passed make trailing comma support and max depth options

2 files changed, 40 insertions(+), 17 deletions(-)

json.zig+32-9
......@@ -6,13 +6,13 @@ const tracer = @import("tracer");
66const Error = std.mem.Allocator.Error;
77const ObjectHashMap = std.AutoArrayHashMapUnmanaged(StringIndex, ValueIndex);
88
9pub fn parse(alloc: std.mem.Allocator, path: string, inreader: anytype) anyerror!Document {
9pub fn parse(alloc: std.mem.Allocator, path: string, inreader: anytype, options: Parser.Options) anyerror!Document {
1010 const t = tracer.trace(@src(), "", .{});
1111 defer t.end();
1212
1313 _ = path;
1414
15 var p = Parser.init(alloc, inreader.any());
15 var p = Parser.init(alloc, inreader.any(), options);
1616 defer p.temp.deinit(alloc);
1717 defer p.strings_map.deinit(alloc);
1818 errdefer p.extras.deinit(alloc);
......@@ -66,17 +66,22 @@ fn parseObject(alloc: std.mem.Allocator, p: *Parser) anyerror!?ValueIndex {
6666 const t = tracer.trace(@src(), "", .{});
6767 defer t.end();
6868
69 p.depth += 1;
70 defer p.depth -= 1;
71 if (p.depth > p.maximum_depth) return error.JsonExpectedTODO;
72
6973 _ = try p.eatByte('{') orelse return null;
74 try parseWs(p);
7075
7176 var sfa = std.heap.stackFallback(std.mem.page_size, alloc);
7277 const alloc_local = sfa.get();
7378 var members = ObjectHashMap{};
7479 defer members.deinit(alloc_local);
7580
81 if (try p.eatByte('}')) |_| {
82 return try p.addObject(alloc, &members);
83 }
7684 while (true) {
77 try parseWs(p);
78 if (try p.eatByte('}')) |_| break;
79
8085 const key = try parseString(alloc, p) orelse return error.JsonExpectedObjectKey;
8186 try parseWs(p);
8287 _ = try p.eatByte(':') orelse return error.JsonExpectedObjectColon;
......@@ -89,6 +94,7 @@ fn parseObject(alloc: std.mem.Allocator, p: *Parser) anyerror!?ValueIndex {
8994 break;
9095 };
9196 try parseWs(p);
97 if (!p.support_trailing_commas) continue;
9298 if (try p.eatByte('}')) |_| break;
9399 }
94100 return try p.addObject(alloc, &members);
......@@ -98,17 +104,22 @@ fn parseArray(alloc: std.mem.Allocator, p: *Parser) anyerror!?ValueIndex {
98104 const t = tracer.trace(@src(), "", .{});
99105 defer t.end();
100106
107 p.depth += 1;
108 defer p.depth -= 1;
109 if (p.depth > p.maximum_depth) return error.JsonExpectedTODO;
110
101111 _ = try p.eatByte('[') orelse return null;
112 try parseWs(p);
102113
103114 var sfa = std.heap.stackFallback(std.mem.page_size, alloc);
104115 const alloc_local = sfa.get();
105116 var elements = std.ArrayListUnmanaged(ValueIndex){};
106117 defer elements.deinit(alloc_local);
107118
119 if (try p.eatByte(']')) |_| {
120 return try p.addArray(alloc, elements.items);
121 }
108122 while (true) {
109 try parseWs(p);
110 if (try p.eatByte(']')) |_| break;
111
112123 const elem = try parseValue(alloc, p);
113124 try elements.append(alloc_local, elem);
114125 try parseWs(p);
......@@ -117,6 +128,7 @@ fn parseArray(alloc: std.mem.Allocator, p: *Parser) anyerror!?ValueIndex {
117128 break;
118129 };
119130 try parseWs(p);
131 if (!p.support_trailing_commas) continue;
120132 if (try p.eatByte(']')) |_| break;
121133 }
122134 return try p.addArray(alloc, elements.items);
......@@ -237,14 +249,25 @@ const Parser = struct {
237249 col: usize = 1,
238250 extras: std.ArrayListUnmanaged(u8) = .{},
239251 strings_map: std.StringArrayHashMapUnmanaged(StringIndex) = .{},
252 depth: u16 = 0,
240253
241 pub fn init(allocator: std.mem.Allocator, any: std.io.AnyReader) Parser {
254 support_trailing_commas: bool,
255 maximum_depth: u16,
256
257 pub fn init(allocator: std.mem.Allocator, any: std.io.AnyReader, options: Options) Parser {
242258 return .{
243259 .any = any,
244260 .arena = allocator,
261 .support_trailing_commas = options.support_trailing_commas,
262 .maximum_depth = options.maximum_depth,
245263 };
246264 }
247265
266 pub const Options = struct {
267 support_trailing_commas: bool,
268 maximum_depth: u16,
269 };
270
248271 pub fn avail(p: *Parser) usize {
249272 return p.temp.items.len - p.idx;
250273 }
test.zig+8-8
......@@ -4,7 +4,7 @@ const json = @import("json");
44fn parse_full(buffer: []const u8) !void {
55 const alloc = std.testing.allocator;
66 var fbs = std.io.fixedBufferStream(buffer);
7 var doc = try json.parse(alloc, "", fbs.reader());
7 var doc = try json.parse(alloc, "", fbs.reader(), .{ .support_trailing_commas = true, .maximum_depth = 100 });
88 defer doc.deinit(alloc);
99}
1010
......@@ -264,7 +264,7 @@ fn expectPass(path: []const u8) !void {
264264 const alloc = std.testing.allocator;
265265 var file = try std.fs.cwd().openFile(path, .{});
266266 defer file.close();
267 var doc = try json.parse(alloc, path, file.reader());
267 var doc = try json.parse(alloc, path, file.reader(), .{ .support_trailing_commas = false, .maximum_depth = 100 });
268268 defer doc.deinit(alloc);
269269}
270270
......@@ -370,7 +370,7 @@ fn expectFail(path: []const u8) !void {
370370 const alloc = std.testing.allocator;
371371 var file = try std.fs.cwd().openFile(path, .{});
372372 defer file.close();
373 var doc = json.parse(alloc, path, file.reader()) catch return;
373 var doc = json.parse(alloc, path, file.reader(), .{ .support_trailing_commas = false, .maximum_depth = 100 }) catch return;
374374 defer doc.deinit(alloc);
375375 try std.testing.expect(false);
376376}
......@@ -384,7 +384,7 @@ test { try expectFail(JSONTestSuite_root ++ "/n_array_comma_and_number.json"); }
384384test { try expectFail(JSONTestSuite_root ++ "/n_array_double_comma.json"); }
385385test { try expectFail(JSONTestSuite_root ++ "/n_array_double_extra_comma.json"); }
386386test { try expectFail(JSONTestSuite_root ++ "/n_array_extra_close.json"); }
387test { try expectPass(JSONTestSuite_root ++ "/n_array_extra_comma.json"); }
387test { try expectFail(JSONTestSuite_root ++ "/n_array_extra_comma.json"); }
388388test { try expectFail(JSONTestSuite_root ++ "/n_array_incomplete_invalid_value.json"); }
389389test { try expectFail(JSONTestSuite_root ++ "/n_array_incomplete.json"); }
390390test { try expectFail(JSONTestSuite_root ++ "/n_array_inner_array_no_comma.json"); }
......@@ -394,7 +394,7 @@ test { try expectFail(JSONTestSuite_root ++ "/n_array_just_comma.json"); }
394394test { try expectFail(JSONTestSuite_root ++ "/n_array_just_minus.json"); }
395395test { try expectFail(JSONTestSuite_root ++ "/n_array_missing_value.json"); }
396396test { try expectFail(JSONTestSuite_root ++ "/n_array_newlines_unclosed.json"); }
397test { try expectPass(JSONTestSuite_root ++ "/n_array_number_and_comma.json"); }
397test { try expectFail(JSONTestSuite_root ++ "/n_array_number_and_comma.json"); }
398398test { try expectFail(JSONTestSuite_root ++ "/n_array_number_and_several_commas.json"); }
399399test { try expectFail(JSONTestSuite_root ++ "/n_array_spaces_vertical_tab_formfeed.json"); }
400400test { try expectFail(JSONTestSuite_root ++ "/n_array_star_inside.json"); }
......@@ -475,7 +475,7 @@ test { try expectFail(JSONTestSuite_root ++ "/n_object_non_string_key.json"); }
475475test { try expectFail(JSONTestSuite_root ++ "/n_object_repeated_null_null.json"); }
476476test { try expectFail(JSONTestSuite_root ++ "/n_object_several_trailing_commas.json"); }
477477test { try expectFail(JSONTestSuite_root ++ "/n_object_single_quote.json"); }
478test { try expectPass(JSONTestSuite_root ++ "/n_object_trailing_comma.json"); }
478test { try expectFail(JSONTestSuite_root ++ "/n_object_trailing_comma.json"); }
479479test { try expectFail(JSONTestSuite_root ++ "/n_object_trailing_comment.json"); }
480480test { try expectFail(JSONTestSuite_root ++ "/n_object_trailing_comment_open.json"); }
481481test { try expectFail(JSONTestSuite_root ++ "/n_object_trailing_comment_slash_open_incomplete.json"); }
......@@ -515,7 +515,7 @@ test { try expectFail(JSONTestSuite_root ++ "/n_string_unescaped_newline.json");
515515test { try expectFail(JSONTestSuite_root ++ "/n_string_unescaped_tab.json"); }
516516test { try expectFail(JSONTestSuite_root ++ "/n_string_unicode_CapitalU.json"); }
517517test { try expectFail(JSONTestSuite_root ++ "/n_string_with_trailing_garbage.json"); }
518// test { try expectFail(JSONTestSuite_root ++ "/n_structure_100000_opening_arrays.json"); }
518test { try expectFail(JSONTestSuite_root ++ "/n_structure_100000_opening_arrays.json"); }
519519test { try expectFail(JSONTestSuite_root ++ "/n_structure_angle_bracket_..json"); }
520520test { try expectFail(JSONTestSuite_root ++ "/n_structure_angle_bracket_null.json"); }
521521test { try expectFail(JSONTestSuite_root ++ "/n_structure_array_trailing_garbage.json"); }
......@@ -539,7 +539,7 @@ test { try expectFail(JSONTestSuite_root ++ "/n_structure_object_with_comment.js
539539test { try expectFail(JSONTestSuite_root ++ "/n_structure_object_with_trailing_garbage.json"); }
540540test { try expectFail(JSONTestSuite_root ++ "/n_structure_open_array_apostrophe.json"); }
541541test { try expectFail(JSONTestSuite_root ++ "/n_structure_open_array_comma.json"); }
542// test { try expectFail(JSONTestSuite_root ++ "/n_structure_open_array_object.json"); }
542test { try expectFail(JSONTestSuite_root ++ "/n_structure_open_array_object.json"); }
543543test { try expectFail(JSONTestSuite_root ++ "/n_structure_open_array_open_object.json"); }
544544test { try expectFail(JSONTestSuite_root ++ "/n_structure_open_array_open_string.json"); }
545545test { try expectFail(JSONTestSuite_root ++ "/n_structure_open_array_string.json"); }