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");...@@ -6,13 +6,13 @@ const tracer = @import("tracer");
6const Error = std.mem.Allocator.Error;6const Error = std.mem.Allocator.Error;
7const ObjectHashMap = std.AutoArrayHashMapUnmanaged(StringIndex, ValueIndex);7const 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 {
10 const t = tracer.trace(@src(), "", .{});10 const t = tracer.trace(@src(), "", .{});
11 defer t.end();11 defer t.end();
1212
13 _ = path;13 _ = path;
1414
15 var p = Parser.init(alloc, inreader.any());15 var p = Parser.init(alloc, inreader.any(), options);
16 defer p.temp.deinit(alloc);16 defer p.temp.deinit(alloc);
17 defer p.strings_map.deinit(alloc);17 defer p.strings_map.deinit(alloc);
18 errdefer p.extras.deinit(alloc);18 errdefer p.extras.deinit(alloc);
...@@ -66,17 +66,22 @@ fn parseObject(alloc: std.mem.Allocator, p: *Parser) anyerror!?ValueIndex {...@@ -66,17 +66,22 @@ fn parseObject(alloc: std.mem.Allocator, p: *Parser) anyerror!?ValueIndex {
66 const t = tracer.trace(@src(), "", .{});66 const t = tracer.trace(@src(), "", .{});
67 defer t.end();67 defer t.end();
6868
69 p.depth += 1;
70 defer p.depth -= 1;
71 if (p.depth > p.maximum_depth) return error.JsonExpectedTODO;
72
69 _ = try p.eatByte('{') orelse return null;73 _ = try p.eatByte('{') orelse return null;
74 try parseWs(p);
7075
71 var sfa = std.heap.stackFallback(std.mem.page_size, alloc);76 var sfa = std.heap.stackFallback(std.mem.page_size, alloc);
72 const alloc_local = sfa.get();77 const alloc_local = sfa.get();
73 var members = ObjectHashMap{};78 var members = ObjectHashMap{};
74 defer members.deinit(alloc_local);79 defer members.deinit(alloc_local);
7580
81 if (try p.eatByte('}')) |_| {
82 return try p.addObject(alloc, &members);
83 }
76 while (true) {84 while (true) {
77 try parseWs(p);
78 if (try p.eatByte('}')) |_| break;
79
80 const key = try parseString(alloc, p) orelse return error.JsonExpectedObjectKey;85 const key = try parseString(alloc, p) orelse return error.JsonExpectedObjectKey;
81 try parseWs(p);86 try parseWs(p);
82 _ = try p.eatByte(':') orelse return error.JsonExpectedObjectColon;87 _ = try p.eatByte(':') orelse return error.JsonExpectedObjectColon;
...@@ -89,6 +94,7 @@ fn parseObject(alloc: std.mem.Allocator, p: *Parser) anyerror!?ValueIndex {...@@ -89,6 +94,7 @@ fn parseObject(alloc: std.mem.Allocator, p: *Parser) anyerror!?ValueIndex {
89 break;94 break;
90 };95 };
91 try parseWs(p);96 try parseWs(p);
97 if (!p.support_trailing_commas) continue;
92 if (try p.eatByte('}')) |_| break;98 if (try p.eatByte('}')) |_| break;
93 }99 }
94 return try p.addObject(alloc, &members);100 return try p.addObject(alloc, &members);
...@@ -98,17 +104,22 @@ fn parseArray(alloc: std.mem.Allocator, p: *Parser) anyerror!?ValueIndex {...@@ -98,17 +104,22 @@ fn parseArray(alloc: std.mem.Allocator, p: *Parser) anyerror!?ValueIndex {
98 const t = tracer.trace(@src(), "", .{});104 const t = tracer.trace(@src(), "", .{});
99 defer t.end();105 defer t.end();
100106
107 p.depth += 1;
108 defer p.depth -= 1;
109 if (p.depth > p.maximum_depth) return error.JsonExpectedTODO;
110
101 _ = try p.eatByte('[') orelse return null;111 _ = try p.eatByte('[') orelse return null;
112 try parseWs(p);
102113
103 var sfa = std.heap.stackFallback(std.mem.page_size, alloc);114 var sfa = std.heap.stackFallback(std.mem.page_size, alloc);
104 const alloc_local = sfa.get();115 const alloc_local = sfa.get();
105 var elements = std.ArrayListUnmanaged(ValueIndex){};116 var elements = std.ArrayListUnmanaged(ValueIndex){};
106 defer elements.deinit(alloc_local);117 defer elements.deinit(alloc_local);
107118
119 if (try p.eatByte(']')) |_| {
120 return try p.addArray(alloc, elements.items);
121 }
108 while (true) {122 while (true) {
109 try parseWs(p);
110 if (try p.eatByte(']')) |_| break;
111
112 const elem = try parseValue(alloc, p);123 const elem = try parseValue(alloc, p);
113 try elements.append(alloc_local, elem);124 try elements.append(alloc_local, elem);
114 try parseWs(p);125 try parseWs(p);
...@@ -117,6 +128,7 @@ fn parseArray(alloc: std.mem.Allocator, p: *Parser) anyerror!?ValueIndex {...@@ -117,6 +128,7 @@ fn parseArray(alloc: std.mem.Allocator, p: *Parser) anyerror!?ValueIndex {
117 break;128 break;
118 };129 };
119 try parseWs(p);130 try parseWs(p);
131 if (!p.support_trailing_commas) continue;
120 if (try p.eatByte(']')) |_| break;132 if (try p.eatByte(']')) |_| break;
121 }133 }
122 return try p.addArray(alloc, elements.items);134 return try p.addArray(alloc, elements.items);
...@@ -237,14 +249,25 @@ const Parser = struct {...@@ -237,14 +249,25 @@ const Parser = struct {
237 col: usize = 1,249 col: usize = 1,
238 extras: std.ArrayListUnmanaged(u8) = .{},250 extras: std.ArrayListUnmanaged(u8) = .{},
239 strings_map: std.StringArrayHashMapUnmanaged(StringIndex) = .{},251 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 {
242 return .{258 return .{
243 .any = any,259 .any = any,
244 .arena = allocator,260 .arena = allocator,
261 .support_trailing_commas = options.support_trailing_commas,
262 .maximum_depth = options.maximum_depth,
245 };263 };
246 }264 }
247265
266 pub const Options = struct {
267 support_trailing_commas: bool,
268 maximum_depth: u16,
269 };
270
248 pub fn avail(p: *Parser) usize {271 pub fn avail(p: *Parser) usize {
249 return p.temp.items.len - p.idx;272 return p.temp.items.len - p.idx;
250 }273 }
test.zig+8-8
...@@ -4,7 +4,7 @@ const json = @import("json");...@@ -4,7 +4,7 @@ const json = @import("json");
4fn parse_full(buffer: []const u8) !void {4fn parse_full(buffer: []const u8) !void {
5 const alloc = std.testing.allocator;5 const alloc = std.testing.allocator;
6 var fbs = std.io.fixedBufferStream(buffer);6 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 });
8 defer doc.deinit(alloc);8 defer doc.deinit(alloc);
9}9}
1010
...@@ -264,7 +264,7 @@ fn expectPass(path: []const u8) !void {...@@ -264,7 +264,7 @@ fn expectPass(path: []const u8) !void {
264 const alloc = std.testing.allocator;264 const alloc = std.testing.allocator;
265 var file = try std.fs.cwd().openFile(path, .{});265 var file = try std.fs.cwd().openFile(path, .{});
266 defer file.close();266 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 });
268 defer doc.deinit(alloc);268 defer doc.deinit(alloc);
269}269}
270270
...@@ -370,7 +370,7 @@ fn expectFail(path: []const u8) !void {...@@ -370,7 +370,7 @@ fn expectFail(path: []const u8) !void {
370 const alloc = std.testing.allocator;370 const alloc = std.testing.allocator;
371 var file = try std.fs.cwd().openFile(path, .{});371 var file = try std.fs.cwd().openFile(path, .{});
372 defer file.close();372 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;
374 defer doc.deinit(alloc);374 defer doc.deinit(alloc);
375 try std.testing.expect(false);375 try std.testing.expect(false);
376}376}
...@@ -384,7 +384,7 @@ test { try expectFail(JSONTestSuite_root ++ "/n_array_comma_and_number.json"); }...@@ -384,7 +384,7 @@ test { try expectFail(JSONTestSuite_root ++ "/n_array_comma_and_number.json"); }
384test { try expectFail(JSONTestSuite_root ++ "/n_array_double_comma.json"); }384test { try expectFail(JSONTestSuite_root ++ "/n_array_double_comma.json"); }
385test { try expectFail(JSONTestSuite_root ++ "/n_array_double_extra_comma.json"); }385test { try expectFail(JSONTestSuite_root ++ "/n_array_double_extra_comma.json"); }
386test { try expectFail(JSONTestSuite_root ++ "/n_array_extra_close.json"); }386test { 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"); }
388test { try expectFail(JSONTestSuite_root ++ "/n_array_incomplete_invalid_value.json"); }388test { try expectFail(JSONTestSuite_root ++ "/n_array_incomplete_invalid_value.json"); }
389test { try expectFail(JSONTestSuite_root ++ "/n_array_incomplete.json"); }389test { try expectFail(JSONTestSuite_root ++ "/n_array_incomplete.json"); }
390test { try expectFail(JSONTestSuite_root ++ "/n_array_inner_array_no_comma.json"); }390test { 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"); }...@@ -394,7 +394,7 @@ test { try expectFail(JSONTestSuite_root ++ "/n_array_just_comma.json"); }
394test { try expectFail(JSONTestSuite_root ++ "/n_array_just_minus.json"); }394test { try expectFail(JSONTestSuite_root ++ "/n_array_just_minus.json"); }
395test { try expectFail(JSONTestSuite_root ++ "/n_array_missing_value.json"); }395test { try expectFail(JSONTestSuite_root ++ "/n_array_missing_value.json"); }
396test { try expectFail(JSONTestSuite_root ++ "/n_array_newlines_unclosed.json"); }396test { 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"); }
398test { try expectFail(JSONTestSuite_root ++ "/n_array_number_and_several_commas.json"); }398test { try expectFail(JSONTestSuite_root ++ "/n_array_number_and_several_commas.json"); }
399test { try expectFail(JSONTestSuite_root ++ "/n_array_spaces_vertical_tab_formfeed.json"); }399test { try expectFail(JSONTestSuite_root ++ "/n_array_spaces_vertical_tab_formfeed.json"); }
400test { try expectFail(JSONTestSuite_root ++ "/n_array_star_inside.json"); }400test { try expectFail(JSONTestSuite_root ++ "/n_array_star_inside.json"); }
...@@ -475,7 +475,7 @@ test { try expectFail(JSONTestSuite_root ++ "/n_object_non_string_key.json"); }...@@ -475,7 +475,7 @@ test { try expectFail(JSONTestSuite_root ++ "/n_object_non_string_key.json"); }
475test { try expectFail(JSONTestSuite_root ++ "/n_object_repeated_null_null.json"); }475test { try expectFail(JSONTestSuite_root ++ "/n_object_repeated_null_null.json"); }
476test { try expectFail(JSONTestSuite_root ++ "/n_object_several_trailing_commas.json"); }476test { try expectFail(JSONTestSuite_root ++ "/n_object_several_trailing_commas.json"); }
477test { try expectFail(JSONTestSuite_root ++ "/n_object_single_quote.json"); }477test { 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"); }
479test { try expectFail(JSONTestSuite_root ++ "/n_object_trailing_comment.json"); }479test { try expectFail(JSONTestSuite_root ++ "/n_object_trailing_comment.json"); }
480test { try expectFail(JSONTestSuite_root ++ "/n_object_trailing_comment_open.json"); }480test { try expectFail(JSONTestSuite_root ++ "/n_object_trailing_comment_open.json"); }
481test { try expectFail(JSONTestSuite_root ++ "/n_object_trailing_comment_slash_open_incomplete.json"); }481test { 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");...@@ -515,7 +515,7 @@ test { try expectFail(JSONTestSuite_root ++ "/n_string_unescaped_newline.json");
515test { try expectFail(JSONTestSuite_root ++ "/n_string_unescaped_tab.json"); }515test { try expectFail(JSONTestSuite_root ++ "/n_string_unescaped_tab.json"); }
516test { try expectFail(JSONTestSuite_root ++ "/n_string_unicode_CapitalU.json"); }516test { try expectFail(JSONTestSuite_root ++ "/n_string_unicode_CapitalU.json"); }
517test { try expectFail(JSONTestSuite_root ++ "/n_string_with_trailing_garbage.json"); }517test { 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"); }
519test { try expectFail(JSONTestSuite_root ++ "/n_structure_angle_bracket_..json"); }519test { try expectFail(JSONTestSuite_root ++ "/n_structure_angle_bracket_..json"); }
520test { try expectFail(JSONTestSuite_root ++ "/n_structure_angle_bracket_null.json"); }520test { try expectFail(JSONTestSuite_root ++ "/n_structure_angle_bracket_null.json"); }
521test { try expectFail(JSONTestSuite_root ++ "/n_structure_array_trailing_garbage.json"); }521test { 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...@@ -539,7 +539,7 @@ test { try expectFail(JSONTestSuite_root ++ "/n_structure_object_with_comment.js
539test { try expectFail(JSONTestSuite_root ++ "/n_structure_object_with_trailing_garbage.json"); }539test { try expectFail(JSONTestSuite_root ++ "/n_structure_object_with_trailing_garbage.json"); }
540test { try expectFail(JSONTestSuite_root ++ "/n_structure_open_array_apostrophe.json"); }540test { try expectFail(JSONTestSuite_root ++ "/n_structure_open_array_apostrophe.json"); }
541test { try expectFail(JSONTestSuite_root ++ "/n_structure_open_array_comma.json"); }541test { 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"); }
543test { try expectFail(JSONTestSuite_root ++ "/n_structure_open_array_open_object.json"); }543test { try expectFail(JSONTestSuite_root ++ "/n_structure_open_array_open_object.json"); }
544test { try expectFail(JSONTestSuite_root ++ "/n_structure_open_array_open_string.json"); }544test { try expectFail(JSONTestSuite_root ++ "/n_structure_open_array_open_string.json"); }
545test { try expectFail(JSONTestSuite_root ++ "/n_structure_open_array_string.json"); }545test { try expectFail(JSONTestSuite_root ++ "/n_structure_open_array_string.json"); }