const builtin = @import("builtin"); const std = @import("std"); const value = @import("../value.zig"); const Parser = @import("Parser.zig"); const Value = value.Value; const is_test = builtin.is_test; const is_debug = builtin.mode == .Debug; // In debug, we want to see if we leak, so very small numbers. const def_init_stack_mem = (if (is_debug) 2 else 32) * @sizeOf(Parser.Context); const def_init_chars_mem = (if (is_debug) 2 else 2048); pub const DefaultStackSfa = std.heap.StackFallbackAllocator(def_init_stack_mem); pub const DefaultCharsSfa = std.heap.StackFallbackAllocator(def_init_chars_mem); pub fn default( fb_alloc: *std.mem.Allocator, stack_sfa: *DefaultStackSfa, chars_sfa: *DefaultCharsSfa, ) !Parser { if (!is_test and is_debug) { fb_alloc.* = std.heap.DebugAllocator(.{}).init; } const alloc = if (is_test) std.testing.allocator else if (is_debug) fb_alloc.allocator() else std.heap.smp_allocator; stack_sfa.* = std.heap.stackFallback(def_init_stack_mem, alloc); chars_sfa.* = std.heap.stackFallback(def_init_chars_mem, alloc); return Parser.init( stack_sfa.get(), chars_sfa.get(), def_init_stack_mem, def_init_chars_mem, ); } pub fn deinit(fb_alloc: *std.mem.Allocator) void { if (!is_test and is_debug) { if (fb_alloc.?.deinit() == .leak) { @panic("parser leaked"); } } } pub fn parse(input: std.io.AnyReader) Value { var fb_alloc: std.mem.Allocator = undefined; var stack_sfa: DefaultStackSfa = undefined; var chars_sfa: DefaultCharsSfa = undefined; var p = default(&fb_alloc, &stack_sfa, &chars_sfa) catch @panic("OOM"); defer p.deinit(); return p.run(input) catch { if (p.unread_char) |c| { std.debug.panic( "Parse error: {s}, unread_char: 0x{x}\n", .{ p.err_msg, c }, ); } else { std.debug.panic("Parse error: {s}\n", .{p.err_msg}); } }; } pub fn _parse(input: std.io.AnyReader) !Value { var fb_alloc: std.mem.Allocator = undefined; var stack_sfa: DefaultStackSfa = undefined; var chars_sfa: DefaultCharsSfa = undefined; var p = try default(&fb_alloc, &stack_sfa, &chars_sfa); defer p.deinit(); return p.run(input); }