| ... | ... | @@ -4,8 +4,8 @@ const extras = @import("extras"); |
| 4 | 4 | const tracer = @import("tracer"); |
| 5 | 5 | const intrusive_parser = @import("intrusive-parser"); |
| 6 | 6 | |
| 7 | | const Error = error{ OutOfMemory, EndOfStream, MalformedJson }; |
| 8 | | const ObjectHashMap = std.AutoArrayHashMapUnmanaged(StringIndex, ValueIndex); |
| 7 | pub const Error = error{ OutOfMemory, EndOfStream, MalformedJson }; |
| 8 | pub const ObjectHashMap = std.AutoArrayHashMapUnmanaged(StringIndex, ValueIndex); |
| 9 | 9 | |
| 10 | 10 | pub fn parse(alloc: std.mem.Allocator, path: string, inreader: anytype, options: Parser.Options) (@TypeOf(inreader).Error || Error)!Document { |
| 11 | 11 | const t = tracer.trace(@src(), "", .{}); |
| ... | ... | @@ -13,19 +13,8 @@ pub fn parse(alloc: std.mem.Allocator, path: string, inreader: anytype, options: |
| 13 | 13 | |
| 14 | 14 | _ = path; |
| 15 | 15 | |
| 16 | | var p = Parser.init(alloc, inreader.any(), options); |
| 17 | | defer p.parser.deinit(); |
| 18 | | defer p.numbers_map.deinit(alloc); |
| 19 | | |
| 20 | | comptime std.debug.assert(@intFromEnum(Value.zero) == 0); |
| 21 | | try p.parser.data.ensureUnusedCapacity(alloc, 4096); |
| 22 | | p.parser.data.appendAssumeCapacity(@intFromEnum(Value.Tag.zero)); |
| 23 | | p.parser.data.appendAssumeCapacity(@intFromEnum(Value.Tag.null)); |
| 24 | | p.parser.data.appendAssumeCapacity(@intFromEnum(Value.Tag.true)); |
| 25 | | p.parser.data.appendAssumeCapacity(@intFromEnum(Value.Tag.false)); |
| 26 | | _ = try p.addStr(alloc, ""); |
| 27 | | std.debug.assert(try p.addArray(alloc, &.{}) == .empty_array); |
| 28 | | std.debug.assert(try p.addObject(alloc, &ObjectHashMap{}) == .empty_object); |
| 16 | var p = try Parser.init(alloc, inreader.any(), options); |
| 17 | defer p.deinit(); |
| 29 | 18 | |
| 30 | 19 | const root = try parseElementPrecise(alloc, &p, @TypeOf(inreader).Error || Error); |
| 31 | 20 | if (p.avail() > 0) return error.MalformedJson; |
| ... | ... | @@ -251,7 +240,7 @@ fn parseWs(p: *Parser) !void { |
| 251 | 240 | } |
| 252 | 241 | } |
| 253 | 242 | |
| 254 | | const Parser = struct { |
| 243 | pub const Parser = struct { |
| 255 | 244 | parser: intrusive_parser.Parser, |
| 256 | 245 | numbers_map: std.StringArrayHashMapUnmanaged(NumberIndex) = .{}, |
| 257 | 246 | depth: u16 = 0, |
| ... | ... | @@ -259,12 +248,28 @@ const Parser = struct { |
| 259 | 248 | support_trailing_commas: bool, |
| 260 | 249 | maximum_depth: u16, |
| 261 | 250 | |
| 262 | | pub fn init(allocator: std.mem.Allocator, any: std.io.AnyReader, options: Options) Parser { |
| 263 | | return .{ |
| 251 | pub fn init(allocator: std.mem.Allocator, any: std.io.AnyReader, options: Options) !Parser { |
| 252 | var p: Parser = .{ |
| 264 | 253 | .parser = intrusive_parser.Parser.init(allocator, any, @intFromEnum(Value.Tag.string)), |
| 265 | 254 | .support_trailing_commas = options.support_trailing_commas, |
| 266 | 255 | .maximum_depth = options.maximum_depth, |
| 267 | 256 | }; |
| 257 | comptime std.debug.assert(@intFromEnum(Value.zero) == 0); |
| 258 | try p.parser.data.ensureUnusedCapacity(allocator, 4096); |
| 259 | p.parser.data.appendAssumeCapacity(@intFromEnum(Value.Tag.zero)); |
| 260 | p.parser.data.appendAssumeCapacity(@intFromEnum(Value.Tag.null)); |
| 261 | p.parser.data.appendAssumeCapacity(@intFromEnum(Value.Tag.true)); |
| 262 | p.parser.data.appendAssumeCapacity(@intFromEnum(Value.Tag.false)); |
| 263 | _ = try p.addStr(allocator, ""); |
| 264 | std.debug.assert(try p.addArray(allocator, &.{}) == .empty_array); |
| 265 | std.debug.assert(try p.addObject(allocator, &ObjectHashMap{}) == .empty_object); |
| 266 | |
| 267 | return p; |
| 268 | } |
| 269 | |
| 270 | pub fn deinit(p: *Parser) void { |
| 271 | defer p.numbers_map.deinit(p.parser.allocator); |
| 272 | defer p.parser.deinit(); |
| 268 | 273 | } |
| 269 | 274 | |
| 270 | 275 | pub const Options = struct { |
| ... | ... | @@ -290,6 +295,17 @@ const Parser = struct { |
| 290 | 295 | return @enumFromInt(r); |
| 291 | 296 | } |
| 292 | 297 | |
| 298 | pub fn addObjectFromConst(p: *Parser, alloc: std.mem.Allocator, members: []const struct { StringIndex, ValueIndex }) !ValueIndex { |
| 299 | const t = tracer.trace(@src(), "({d})", .{members.len}); |
| 300 | defer t.end(); |
| 301 | |
| 302 | var map = ObjectHashMap{}; |
| 303 | defer map.deinit(alloc); |
| 304 | try map.ensureTotalCapacity(alloc, members.len); |
| 305 | for (members) |member| map.putAssumeCapacity(member[0], member[1]); |
| 306 | return p.addObject(alloc, &map); |
| 307 | } |
| 308 | |
| 293 | 309 | // tag(u8) + len(u32) + items(N * u32) |
| 294 | 310 | pub fn addArray(p: *Parser, alloc: std.mem.Allocator, items: []const ValueIndex) !ValueIndex { |
| 295 | 311 | const t = tracer.trace(@src(), "({d})", .{items.len}); |
| ... | ... | @@ -313,6 +329,11 @@ const Parser = struct { |
| 313 | 329 | return @enumFromInt(try p.parser.addStr(alloc, str)); |
| 314 | 330 | } |
| 315 | 331 | |
| 332 | // tag(u8) + len(u32) + bytes(N) |
| 333 | pub fn addStrV(p: *Parser, alloc: std.mem.Allocator, str: string) !ValueIndex { |
| 334 | return @enumFromInt(@intFromEnum(try p.addStr(alloc, str))); |
| 335 | } |
| 336 | |
| 316 | 337 | const Adapter = struct { |
| 317 | 338 | p: *const Parser, |
| 318 | 339 | |
| ... | ... | @@ -414,6 +435,7 @@ pub const ValueIndex = enum(u32) { |
| 414 | 435 | |
| 415 | 436 | pub fn v(this: ValueIndex) Value { |
| 416 | 437 | std.debug.assert(this != .zero); |
| 438 | std.debug.assert(doc != null); // make sure to call Document.acquire() |
| 417 | 439 | return switch (@as(Value.Tag, @enumFromInt(doc.?.extras[@intFromEnum(this)]))) { |
| 418 | 440 | .zero => .zero, |
| 419 | 441 | .null => .null, |