| ... | @@ -4,8 +4,8 @@ const extras = @import("extras"); | ... | @@ -4,8 +4,8 @@ const extras = @import("extras"); |
| 4 | const tracer = @import("tracer"); | 4 | const tracer = @import("tracer"); |
| 5 | const intrusive_parser = @import("intrusive-parser"); | 5 | const intrusive_parser = @import("intrusive-parser"); |
| 6 | | 6 | |
| 7 | const Error = error{ OutOfMemory, EndOfStream, MalformedJson }; | 7 | pub const Error = error{ OutOfMemory, EndOfStream, MalformedJson }; |
| 8 | const ObjectHashMap = std.AutoArrayHashMapUnmanaged(StringIndex, ValueIndex); | 8 | pub const ObjectHashMap = std.AutoArrayHashMapUnmanaged(StringIndex, ValueIndex); |
| 9 | | 9 | |
| 10 | pub fn parse(alloc: std.mem.Allocator, path: string, inreader: anytype, options: Parser.Options) (@TypeOf(inreader).Error || Error)!Document { | 10 | pub fn parse(alloc: std.mem.Allocator, path: string, inreader: anytype, options: Parser.Options) (@TypeOf(inreader).Error || Error)!Document { |
| 11 | const t = tracer.trace(@src(), "", .{}); | 11 | const t = tracer.trace(@src(), "", .{}); |
| ... | @@ -13,19 +13,8 @@ pub fn parse(alloc: std.mem.Allocator, path: string, inreader: anytype, options: | ... | @@ -13,19 +13,8 @@ pub fn parse(alloc: std.mem.Allocator, path: string, inreader: anytype, options: |
| 13 | | 13 | |
| 14 | _ = path; | 14 | _ = path; |
| 15 | | 15 | |
| 16 | var p = Parser.init(alloc, inreader.any(), options); | 16 | var p = try Parser.init(alloc, inreader.any(), options); |
| 17 | defer p.parser.deinit(); | 17 | defer p.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); | | |
| 29 | | 18 | |
| 30 | const root = try parseElementPrecise(alloc, &p, @TypeOf(inreader).Error || Error); | 19 | const root = try parseElementPrecise(alloc, &p, @TypeOf(inreader).Error || Error); |
| 31 | if (p.avail() > 0) return error.MalformedJson; | 20 | if (p.avail() > 0) return error.MalformedJson; |
| ... | @@ -251,7 +240,7 @@ fn parseWs(p: *Parser) !void { | ... | @@ -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 | parser: intrusive_parser.Parser, | 244 | parser: intrusive_parser.Parser, |
| 256 | numbers_map: std.StringArrayHashMapUnmanaged(NumberIndex) = .{}, | 245 | numbers_map: std.StringArrayHashMapUnmanaged(NumberIndex) = .{}, |
| 257 | depth: u16 = 0, | 246 | depth: u16 = 0, |
| ... | @@ -259,12 +248,28 @@ const Parser = struct { | ... | @@ -259,12 +248,28 @@ const Parser = struct { |
| 259 | support_trailing_commas: bool, | 248 | support_trailing_commas: bool, |
| 260 | maximum_depth: u16, | 249 | maximum_depth: u16, |
| 261 | | 250 | |
| 262 | pub fn init(allocator: std.mem.Allocator, any: std.io.AnyReader, options: Options) Parser { | 251 | pub fn init(allocator: std.mem.Allocator, any: std.io.AnyReader, options: Options) !Parser { |
| 263 | return .{ | 252 | var p: Parser = .{ |
| 264 | .parser = intrusive_parser.Parser.init(allocator, any, @intFromEnum(Value.Tag.string)), | 253 | .parser = intrusive_parser.Parser.init(allocator, any, @intFromEnum(Value.Tag.string)), |
| 265 | .support_trailing_commas = options.support_trailing_commas, | 254 | .support_trailing_commas = options.support_trailing_commas, |
| 266 | .maximum_depth = options.maximum_depth, | 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 | pub const Options = struct { | 275 | pub const Options = struct { |
| ... | @@ -290,6 +295,17 @@ const Parser = struct { | ... | @@ -290,6 +295,17 @@ const Parser = struct { |
| 290 | return @enumFromInt(r); | 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 | // tag(u8) + len(u32) + items(N * u32) | 309 | // tag(u8) + len(u32) + items(N * u32) |
| 294 | pub fn addArray(p: *Parser, alloc: std.mem.Allocator, items: []const ValueIndex) !ValueIndex { | 310 | pub fn addArray(p: *Parser, alloc: std.mem.Allocator, items: []const ValueIndex) !ValueIndex { |
| 295 | const t = tracer.trace(@src(), "({d})", .{items.len}); | 311 | const t = tracer.trace(@src(), "({d})", .{items.len}); |
| ... | @@ -313,6 +329,11 @@ const Parser = struct { | ... | @@ -313,6 +329,11 @@ const Parser = struct { |
| 313 | return @enumFromInt(try p.parser.addStr(alloc, str)); | 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 | const Adapter = struct { | 337 | const Adapter = struct { |
| 317 | p: *const Parser, | 338 | p: *const Parser, |
| 318 | | 339 | |
| ... | @@ -414,6 +435,7 @@ pub const ValueIndex = enum(u32) { | ... | @@ -414,6 +435,7 @@ pub const ValueIndex = enum(u32) { |
| 414 | | 435 | |
| 415 | pub fn v(this: ValueIndex) Value { | 436 | pub fn v(this: ValueIndex) Value { |
| 416 | std.debug.assert(this != .zero); | 437 | std.debug.assert(this != .zero); |
| | 438 | std.debug.assert(doc != null); // make sure to call Document.acquire() |
| 417 | return switch (@as(Value.Tag, @enumFromInt(doc.?.extras[@intFromEnum(this)]))) { | 439 | return switch (@as(Value.Tag, @enumFromInt(doc.?.extras[@intFromEnum(this)]))) { |
| 418 | .zero => .zero, | 440 | .zero => .zero, |
| 419 | .null => .null, | 441 | .null => .null, |