-module(bitty). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/bitty.gleam"). -export([make_parser/1, run_parser/2, success/1, fail/1, from_result/1, map/2, then/2, one_of/1, attempt/1, cut/1, label/2, context/2, many/1, many1/1, repeat/2, optional/1, location/0, align/0, 'end'/0, advance_bits/3, read_uint/4, stop_expected/2, within_bytes/2, read_n_bytes/2, effective_byte_offset/1, within_bytes_partial/2, run/2, run_partial/2, run_with_location/2]). -export_type([location/0, bitty_error/0, parser/1, state/0, step/1]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " Zero-copy binary parser combinators for Gleam, targeting both BEAM and\n" " JavaScript. Build parsers by composing primitives from `bitty/bytes`,\n" " `bitty/bits`, and `bitty/num` with the combinators in this module.\n" " Parsers are designed for Gleam's `use` syntax.\n" ). -type location() :: {location, integer(), integer()}. -type bitty_error() :: {bitty_error, location(), list(binary()), list(binary()), gleam@option:option(binary())}. -opaque parser(OZP) :: {parser, fun((state()) -> step(OZP))}. -type state() :: {state, bitstring(), integer(), integer(), boolean()}. -type step(OZQ) :: {continue, OZQ, state(), boolean()} | {stop, bitty_error(), boolean(), boolean()}. -file("src/bitty.gleam", 51). ?DOC(false). -spec make_parser(fun((state()) -> step(OZR))) -> parser(OZR). make_parser(F) -> {parser, F}. -file("src/bitty.gleam", 56). ?DOC(false). -spec run_parser(parser(OZU), state()) -> step(OZU). run_parser(Parser, State) -> (erlang:element(2, Parser))(State). -file("src/bitty.gleam", 62). ?DOC( " Create a parser that always succeeds with the given value without\n" " consuming any input.\n" ). -spec success(OZX) -> parser(OZX). success(Value) -> {parser, fun(State) -> {continue, Value, State, false} end}. -file("src/bitty.gleam", 68). ?DOC( " Create a parser that always fails with the given message without\n" " consuming any input.\n" ). -spec fail(binary()) -> parser(any()). fail(Message) -> {parser, fun(State) -> {stop, {bitty_error, {location, erlang:element(3, State), erlang:element(4, State)}, [], [], {some, Message}}, false, erlang:element(5, State)} end}. -file("src/bitty.gleam", 87). ?DOC( " Convert a `Result(a, e)` into a parser: `Ok(value)` succeeds with the\n" " value, `Error(e)` fails with the inspected error as the message.\n" " Useful for lifting fallible conversions (e.g. `bit_array.to_string`)\n" " into a parser pipeline with `use` syntax.\n" ). -spec from_result({ok, PAB} | {error, any()}) -> parser(PAB). from_result(Result) -> case Result of {ok, Value} -> success(Value); {error, E} -> fail(gleam@string:inspect(E)) end. -file("src/bitty.gleam", 154). ?DOC(" Transform the result of a parser by applying `f` to the parsed value.\n"). -spec map(parser(PAW), fun((PAW) -> PAY)) -> parser(PAY). map(Parser, F) -> {parser, fun(State) -> case (erlang:element(2, Parser))(State) of {continue, Value, State1, Consumed} -> {continue, F(Value), State1, Consumed}; {stop, Error, Consumed@1, Committed} -> {stop, Error, Consumed@1, Committed} end end}. -file("src/bitty.gleam", 171). ?DOC( " Sequence two parsers: run `parser`, then pass its result to `next` to\n" " get the second parser. Designed for Gleam's `use` syntax:\n" "\n" " ```gleam\n" " use length <- bitty.then(num.u8())\n" " use data <- bitty.then(bytes.take(length))\n" " bitty.success(data)\n" " ```\n" ). -spec then(parser(PBA), fun((PBA) -> parser(PBC))) -> parser(PBC). then(Parser, Next) -> {parser, fun(State) -> case (erlang:element(2, Parser))(State) of {continue, Value, State1, Consumed1} -> case (erlang:element(2, (Next(Value))))(State1) of {continue, Value2, State2, Consumed2} -> {continue, Value2, State2, Consumed1 orelse Consumed2}; {stop, Error, Consumed2@1, Committed2} -> {stop, Error, Consumed1 orelse Consumed2@1, Committed2 orelse erlang:element(5, State1)} end; {stop, Error@1, Consumed, Committed} -> {stop, Error@1, Consumed, Committed} end end}. -file("src/bitty.gleam", 232). -spec merge_errors(bitty_error(), bitty_error()) -> bitty_error(). merge_errors(E1, E2) -> Loc1 = (erlang:element(2, erlang:element(2, E1)) * 8) + erlang:element( 3, erlang:element(2, E1) ), Loc2 = (erlang:element(2, erlang:element(2, E2)) * 8) + erlang:element( 3, erlang:element(2, E2) ), case gleam@int:compare(Loc1, Loc2) of gt -> E1; lt -> E2; eq -> {bitty_error, erlang:element(2, E1), lists:append(erlang:element(3, E1), erlang:element(3, E2)), erlang:element(4, E1), erlang:element(5, E1)} end. -file("src/bitty.gleam", 213). -spec try_parsers(list(parser(PBJ)), state(), bitty_error()) -> step(PBJ). try_parsers(Parsers, State, Last_error) -> case Parsers of [] -> {stop, Last_error, false, false}; [Parser | Rest] -> case (erlang:element(2, Parser))(State) of {continue, _, _, _} = Success -> Success; {stop, Error, Consumed, Committed} -> case Consumed orelse Committed of true -> {stop, Error, Consumed, Committed}; false -> try_parsers( Rest, State, merge_errors(Last_error, Error) ) end end end. -file("src/bitty.gleam", 198). ?DOC( " Try each parser in order, returning the first success. A parser that\n" " consumes input before failing will **not** backtrack — wrap alternatives\n" " in `attempt` if backtracking is needed. Errors from non-consuming\n" " failures at the same position are merged.\n" "\n" " ```gleam\n" " let parser = bitty.one_of([\n" " bitty.attempt(bytes.tag(<<0x01>>) |> bitty.map(fn(_) { \"one\" })),\n" " bytes.tag(<<0x02>>) |> bitty.map(fn(_) { \"two\" }),\n" " ])\n" " let assert Ok(\"two\") = bitty.run(parser, on: <<0x02>>)\n" " ```\n" ). -spec one_of(list(parser(PBF))) -> parser(PBF). one_of(Parsers) -> {parser, fun(State) -> try_parsers( Parsers, State, {bitty_error, {location, erlang:element(3, State), erlang:element(4, State)}, [], [], none} ) end}. -file("src/bitty.gleam", 254). ?DOC( " Wrap a parser to allow backtracking on failure. If the inner parser\n" " fails after consuming input, `attempt` resets the consumed flag so\n" " that `one_of` can try the next alternative.\n" "\n" " ```gleam\n" " let parser = bitty.one_of([\n" " bitty.attempt(bytes.tag(<<0xCA, 0xFE>>)),\n" " bytes.tag(<<0xCA, 0x11>>),\n" " ])\n" " let assert Ok(Nil) = bitty.run(parser, on: <<0xCA, 0x11>>)\n" " ```\n" ). -spec attempt(parser(PBN)) -> parser(PBN). attempt(Parser) -> {parser, fun(State) -> case (erlang:element(2, Parser))(State) of {continue, _, _, _} = Success -> Success; {stop, Error, _, Committed} -> {stop, Error, false, Committed} end end}. -file("src/bitty.gleam", 272). ?DOC( " Commit to the current parse path on success. After `cut`, a later\n" " failure will not backtrack past this point, producing better error\n" " messages. Typically used after matching a tag or discriminator.\n" "\n" " ```gleam\n" " use _ <- bitty.then(bitty.cut(bytes.tag(<<0x01>>)))\n" " use value <- bitty.then(num.u8())\n" " bitty.success(value)\n" " ```\n" ). -spec cut(parser(PBQ)) -> parser(PBQ). cut(Parser) -> {parser, fun(State) -> case (erlang:element(2, Parser))(State) of {continue, Value, State1, Consumed} -> {continue, Value, {state, erlang:element(2, State1), erlang:element(3, State1), erlang:element(4, State1), true}, Consumed}; {stop, Error, Consumed@1, Committed} -> {stop, Error, Consumed@1, Committed} end end}. -file("src/bitty.gleam", 290). ?DOC( " Replace the `expected` list in a parse error with `name`.\n" " Useful for giving user-friendly names to complex parsers.\n" "\n" " ```gleam\n" " let parser = num.u8() |> bitty.label(named: \"message type\")\n" " let assert Error(e) = bitty.run(parser, on: <<>>)\n" " assert e.expected == [\"message type\"]\n" " ```\n" ). -spec label(parser(PBT), binary()) -> parser(PBT). label(Parser, Name) -> {parser, fun(State) -> case (erlang:element(2, Parser))(State) of {continue, _, _, _} = Success -> Success; {stop, Error, Consumed, Committed} -> {stop, {bitty_error, erlang:element(2, Error), [Name], erlang:element(4, Error), erlang:element(5, Error)}, Consumed, Committed} end end}. -file("src/bitty.gleam", 308). ?DOC( " Push `name` onto the error context stack on failure, creating a\n" " breadcrumb trail (e.g. `[\"TLS record\", \"handshake\", \"certificate\"]`).\n" "\n" " ```gleam\n" " let parser = num.u8() |> bitty.context(in: \"header\")\n" " let assert Error(e) = bitty.run(parser, on: <<>>)\n" " assert e.context == [\"header\"]\n" " ```\n" ). -spec context(parser(PBW), binary()) -> parser(PBW). context(Parser, Name) -> {parser, fun(State) -> case (erlang:element(2, Parser))(State) of {continue, _, _, _} = Success -> Success; {stop, Error, Consumed, Committed} -> {stop, {bitty_error, erlang:element(2, Error), erlang:element(3, Error), [Name | erlang:element(4, Error)], erlang:element(5, Error)}, Consumed, Committed} end end}. -file("src/bitty.gleam", 336). -spec many_loop(parser(PCD), state(), list(PCD), boolean()) -> step(list(PCD)). many_loop(Parser, State, Acc, Any_consumed) -> case (erlang:element(2, Parser))( {state, erlang:element(2, State), erlang:element(3, State), erlang:element(4, State), false} ) of {continue, Value, State1, true} -> many_loop( Parser, {state, erlang:element(2, State1), erlang:element(3, State1), erlang:element(4, State1), erlang:element(5, State1) orelse erlang:element(5, State)}, [Value | Acc], true ); {continue, _, _, false} -> {stop, {bitty_error, {location, erlang:element(3, State), erlang:element(4, State)}, [<<"consuming parser in many"/utf8>>], [], none}, Any_consumed, erlang:element(5, State)}; {stop, _, false, false} -> {continue, lists:reverse(Acc), State, Any_consumed}; {stop, Error, Consumed, Committed} -> {stop, Error, Any_consumed orelse Consumed, Committed orelse erlang:element(5, State)} end. -file("src/bitty.gleam", 332). ?DOC( " Repeat a parser zero or more times, collecting results into a list.\n" " The inner parser **must** consume input on each iteration; a\n" " non-consuming parser causes an immediate error to prevent infinite loops.\n" " Stops when the parser fails without consuming input.\n" "\n" " ```gleam\n" " let assert Ok(values) =\n" " bitty.run(bitty.many(num.u8()), on: <<1, 2, 3>>)\n" " assert values == [1, 2, 3]\n" " ```\n" ). -spec many(parser(PBZ)) -> parser(list(PBZ)). many(Parser) -> {parser, fun(State) -> many_loop(Parser, State, [], false) end}. -file("src/bitty.gleam", 369). ?DOC(" Like `many`, but requires at least one successful match.\n"). -spec many1(parser(PCI)) -> parser(list(PCI)). many1(Parser) -> _pipe = Parser, then(_pipe, fun(First) -> _pipe@1 = many(Parser), map(_pipe@1, fun(Rest) -> [First | Rest] end) end). -file("src/bitty.gleam", 379). -spec repeat_loop(parser(PCQ), state(), list(PCQ), integer(), boolean()) -> step(list(PCQ)). repeat_loop(Parser, State, Acc, Remaining, Any_consumed) -> case Remaining =< 0 of true -> {continue, lists:reverse(Acc), State, Any_consumed}; false -> case (erlang:element(2, Parser))(State) of {continue, Value, State1, Consumed} -> repeat_loop( Parser, State1, [Value | Acc], Remaining - 1, Any_consumed orelse Consumed ); {stop, Error, Consumed@1, Committed} -> {stop, Error, Any_consumed orelse Consumed@1, Committed} end end. -file("src/bitty.gleam", 375). ?DOC(" Run a parser exactly `count` times, collecting results into a list.\n"). -spec repeat(parser(PCM), integer()) -> parser(list(PCM)). repeat(Parser, Count) -> {parser, fun(State) -> repeat_loop(Parser, State, [], Count, false) end}. -file("src/bitty.gleam", 406). ?DOC( " Try a parser, returning `Some(value)` on success or `None` if it fails\n" " without consuming input. A consuming failure still propagates.\n" ). -spec optional(parser(PCV)) -> parser(gleam@option:option(PCV)). optional(Parser) -> {parser, fun(State) -> case (erlang:element(2, Parser))(State) of {continue, Value, State1, Consumed} -> {continue, {some, Value}, State1, Consumed}; {stop, _, false, false} -> {continue, none, State, false}; {stop, Error, Consumed@1, Committed} -> {stop, Error, Consumed@1, Committed} end end}. -file("src/bitty.gleam", 418). ?DOC(" Return the current `Location` in the input without consuming anything.\n"). -spec location() -> parser(location()). location() -> {parser, fun(State) -> {continue, {location, erlang:element(3, State), erlang:element(4, State)}, State, false} end}. -file("src/bitty.gleam", 431). ?DOC( " Skip remaining bits in the current byte to reach the next byte boundary.\n" " If already aligned, this is a no-op. Use after bit-level parsing to\n" " resume byte-aligned operations.\n" ). -spec align() -> parser(nil). align() -> {parser, fun(State) -> case erlang:element(4, State) =:= 0 of true -> {continue, nil, State, false}; false -> {continue, nil, {state, erlang:element(2, State), erlang:element(3, State) + 1, 0, erlang:element(5, State)}, true} end end}. -file("src/bitty.gleam", 447). ?DOC( " Succeed only if all input has been consumed. Fails with\n" " `\"end of input\"` expected if bytes remain.\n" ). -spec 'end'() -> parser(nil). 'end'() -> {parser, fun(State) -> Remaining = erlang:byte_size(erlang:element(2, State)) - erlang:element( 3, State ), case (Remaining =:= 0) andalso (erlang:element(4, State) =:= 0) of true -> {continue, nil, State, false}; false -> {stop, {bitty_error, {location, erlang:element(3, State), erlang:element(4, State)}, [<<"end of input"/utf8>>], [], none}, false, erlang:element(5, State)} end end}. -file("src/bitty.gleam", 527). -spec within_bytes_check(state(), integer(), PDO, state()) -> step(PDO). within_bytes_check(State, Byte_len, Value, Inner_end) -> case (erlang:element(3, Inner_end) =:= Byte_len) andalso (erlang:element( 4, Inner_end ) =:= 0) of true -> {continue, Value, {state, erlang:element(2, State), erlang:element(3, State) + Byte_len, erlang:element(4, State), erlang:element(5, State)}, Byte_len > 0}; false -> {stop, {bitty_error, {location, erlang:element(3, State) + erlang:element(3, Inner_end), erlang:element(4, Inner_end)}, [<<<<"complete consumption of "/utf8, (erlang:integer_to_binary(Byte_len))/binary>>/binary, "-byte window"/utf8>>], [], none}, true, erlang:element(5, State)} end. -file("src/bitty.gleam", 583). -spec within_bytes_stop(state(), bitty_error(), boolean(), boolean()) -> step(any()). within_bytes_stop(State, Error, Consumed, Committed) -> {stop, {bitty_error, {location, erlang:element(3, State) + erlang:element( 2, erlang:element(2, Error) ), erlang:element(3, erlang:element(2, Error))}, erlang:element(3, Error), erlang:element(4, Error), erlang:element(5, Error)}, Consumed, Committed orelse erlang:element(5, State)}. -file("src/bitty.gleam", 675). ?DOC(false). -spec advance_bits(integer(), integer(), integer()) -> {integer(), integer()}. advance_bits(Byte_offset, Bit_offset, Count) -> Total_bits = Bit_offset + Count, {Byte_offset + (Total_bits div 8), Total_bits rem 8}. -file("src/bitty.gleam", 634). ?DOC(false). -spec read_uint(state(), integer(), integer(), boolean()) -> step(integer()). read_uint(State, Remaining, Acc, Consumed) -> case Remaining =< 0 of true -> {continue, Acc, State, Consumed}; false -> case gleam_stdlib:bit_array_slice( erlang:element(2, State), erlang:element(3, State), 1 ) of {ok, <>} -> Available = 8 - erlang:element(4, State), To_read = gleam@int:min(Available, Remaining), Shift = Available - To_read, Mask = erlang:'bsl'(1, To_read) - 1, Bits_val = erlang:'band'(erlang:'bsr'(Byte, Shift), Mask), New_acc = erlang:'bor'(erlang:'bsl'(Acc, To_read), Bits_val), {New_byte, New_bit} = advance_bits( erlang:element(3, State), erlang:element(4, State), To_read ), New_state = {state, erlang:element(2, State), New_byte, New_bit, erlang:element(5, State)}, read_uint(New_state, Remaining - To_read, New_acc, Consumed); _ -> {stop, {bitty_error, {location, erlang:element(3, State), erlang:element(4, State)}, [<<(erlang:integer_to_binary(Remaining))/binary, " more bits"/utf8>>], [], none}, Consumed, erlang:element(5, State)} end end. -file("src/bitty.gleam", 709). -spec read_n_bytes_unaligned(state(), integer(), bitstring(), boolean()) -> step(bitstring()). read_n_bytes_unaligned(State, Remaining, Acc, Consumed) -> case Remaining =< 0 of true -> {continue, Acc, State, Consumed}; false -> case read_uint(State, 8, 0, Consumed) of {continue, Byte_val, New_state, _} -> read_n_bytes_unaligned( New_state, Remaining - 1, <>, Consumed ); {stop, Error, Consumed2, Committed} -> {stop, Error, Consumed2, Committed} end end. -file("src/bitty.gleam", 732). ?DOC(false). -spec stop_expected(state(), binary()) -> step(any()). stop_expected(State, Expected) -> {stop, {bitty_error, {location, erlang:element(3, State), erlang:element(4, State)}, [Expected], [], none}, false, erlang:element(5, State)}. -file("src/bitty.gleam", 489). -spec within_bytes_setup( state(), integer(), parser(PDF), fun((state(), bitstring(), step(PDF)) -> step(PDI)) ) -> step(PDI). within_bytes_setup(State, Byte_len, Inner, On_window) -> Remaining = erlang:byte_size(erlang:element(2, State)) - erlang:element( 3, State ), case Remaining < Byte_len of true -> stop_expected( State, <<<<"at least "/utf8, (erlang:integer_to_binary(Byte_len))/binary>>/binary, " bytes"/utf8>> ); false -> case gleam_stdlib:bit_array_slice( erlang:element(2, State), erlang:element(3, State), Byte_len ) of {ok, Window} -> Inner_state = {state, Window, 0, 0, false}, On_window( State, Window, (erlang:element(2, Inner))(Inner_state) ); _ -> stop_expected(State, <<"valid slice"/utf8>>) end end. -file("src/bitty.gleam", 516). -spec within_bytes_run(state(), integer(), parser(PDL)) -> step(PDL). within_bytes_run(State, Byte_len, Inner) -> within_bytes_setup( State, Byte_len, Inner, fun(St, _, Result) -> case Result of {continue, Value, Inner_end, _} -> within_bytes_check(St, Byte_len, Value, Inner_end); {stop, Error, Consumed, Committed} -> within_bytes_stop(St, Error, Consumed, Committed) end end ). -file("src/bitty.gleam", 476). ?DOC( " Run `inner` on a zero-copy window of exactly `byte_len` bytes.\n" " The inner parser must consume the entire window or the parse fails.\n" " Requires byte alignment.\n" "\n" " ```gleam\n" " use length <- bitty.then(num.u8())\n" " use value <- bitty.then(bitty.within_bytes(length, run: bytes.rest()))\n" " bitty.success(value)\n" " ```\n" ). -spec within_bytes(integer(), parser(PDC)) -> parser(PDC). within_bytes(Byte_len, Inner) -> {parser, fun(State) -> gleam@bool:guard( Byte_len < 0, stop_expected(State, <<"non-negative byte length"/utf8>>), fun() -> case erlang:element(4, State) /= 0 of true -> stop_expected(State, <<"byte alignment"/utf8>>); false -> within_bytes_run(State, Byte_len, Inner) end end ) end}. -file("src/bitty.gleam", 697). -spec read_n_bytes_aligned(state(), integer()) -> step(bitstring()). read_n_bytes_aligned(State, Count) -> case gleam_stdlib:bit_array_slice( erlang:element(2, State), erlang:element(3, State), Count ) of {ok, Bytes} -> {continue, Bytes, {state, erlang:element(2, State), erlang:element(3, State) + Count, erlang:element(4, State), erlang:element(5, State)}, Count > 0}; _ -> stop_expected( State, <<(erlang:integer_to_binary(Count))/binary, " bytes"/utf8>> ) end. -file("src/bitty.gleam", 685). ?DOC(false). -spec read_n_bytes(state(), integer()) -> step(bitstring()). read_n_bytes(State, Count) -> gleam@bool:guard( Count < 0, stop_expected(State, <<"non-negative byte count"/utf8>>), fun() -> case erlang:element(4, State) =:= 0 of true -> read_n_bytes_aligned(State, Count); false -> read_n_bytes_unaligned(State, Count, <<>>, Count > 0) end end ). -file("src/bitty.gleam", 746). ?DOC(false). -spec effective_byte_offset(state()) -> integer(). effective_byte_offset(State) -> case erlang:element(4, State) /= 0 of true -> erlang:element(3, State) + 1; false -> erlang:element(3, State) end. -file("src/bitty.gleam", 561). -spec within_bytes_partial_check(state(), integer(), PDQ, state(), bitstring()) -> step({PDQ, bitstring()}). within_bytes_partial_check(State, Byte_len, Value, Inner_end, Window) -> Effective_inner_offset = effective_byte_offset(Inner_end), Unconsumed = Byte_len - Effective_inner_offset, Leftover = case gleam_stdlib:bit_array_slice( Window, Effective_inner_offset, Unconsumed ) of {ok, Rest} -> Rest; _ -> <<>> end, {continue, {Value, Leftover}, {state, erlang:element(2, State), erlang:element(3, State) + Byte_len, erlang:element(4, State), erlang:element(5, State)}, Byte_len > 0}. -file("src/bitty.gleam", 618). -spec within_bytes_partial_run(state(), integer(), parser(PDX)) -> step({PDX, bitstring()}). within_bytes_partial_run(State, Byte_len, Inner) -> within_bytes_setup( State, Byte_len, Inner, fun(St, Window, Result) -> case Result of {continue, Value, Inner_end, _} -> within_bytes_partial_check( St, Byte_len, Value, Inner_end, Window ); {stop, Error, Consumed, Committed} -> within_bytes_stop(St, Error, Consumed, Committed) end end ). -file("src/bitty.gleam", 602). ?DOC( " Like `within_bytes`, but the inner parser may stop early. Returns the\n" " parsed value and any unconsumed bytes from the window as a tuple.\n" " Requires byte alignment.\n" ). -spec within_bytes_partial(integer(), parser(PDU)) -> parser({PDU, bitstring()}). within_bytes_partial(Byte_len, Inner) -> {parser, fun(State) -> gleam@bool:guard( Byte_len < 0, stop_expected(State, <<"non-negative byte length"/utf8>>), fun() -> case erlang:element(4, State) /= 0 of true -> stop_expected(State, <<"byte alignment"/utf8>>); false -> within_bytes_partial_run(State, Byte_len, Inner) end end ) end}. -file("src/bitty.gleam", 753). -spec remaining_slice(state()) -> bitstring(). remaining_slice(State) -> Offset = effective_byte_offset(State), Remaining = erlang:byte_size(erlang:element(2, State)) - Offset, case gleam_stdlib:bit_array_slice( erlang:element(2, State), Offset, Remaining ) of {ok, Rest} -> Rest; _ -> <<>> end. -file("src/bitty.gleam", 762). -spec new_state(bitstring()) -> state(). new_state(Input) -> {state, Input, 0, 0, false}. -file("src/bitty.gleam", 145). -spec do_run(parser(PAS), bitstring()) -> {ok, {PAS, state()}} | {error, bitty_error()}. do_run(Parser, Input) -> State = new_state(Input), case (erlang:element(2, Parser))(State) of {continue, Value, Final_state, _} -> {ok, {Value, Final_state}}; {stop, Error, _, _} -> {error, Error} end. -file("src/bitty.gleam", 101). ?DOC( " Run a parser on the given input, requiring it to consume all bytes.\n" " Returns `Error` if parsing fails or if unconsumed input remains.\n" "\n" " ```gleam\n" " let assert Ok(byte) = bitty.run(num.u8(), on: <<0xFF>>)\n" " assert byte == 255\n" " ```\n" ). -spec run(parser(PAG), bitstring()) -> {ok, PAG} | {error, bitty_error()}. run(Parser, Input) -> gleam@result:'try'( do_run(Parser, Input), fun(_use0) -> {Value, Final_state} = _use0, Remaining = erlang:byte_size(erlang:element(2, Final_state)) - erlang:element( 3, Final_state ), case (Remaining =:= 0) andalso (erlang:element(4, Final_state) =:= 0) of true -> {ok, Value}; false -> {error, {bitty_error, {location, erlang:element(3, Final_state), erlang:element(4, Final_state)}, [<<"end of input"/utf8>>], [], none}} end end ). -file("src/bitty.gleam", 126). ?DOC( " Run a parser on the given input, returning the parsed value and any\n" " unconsumed bytes. Does not require all input to be consumed.\n" "\n" " ```gleam\n" " let assert Ok(#(byte, rest)) =\n" " bitty.run_partial(num.u8(), on: <<0xAA, 0xBB>>)\n" " assert byte == 0xAA\n" " assert rest == <<0xBB>>\n" " ```\n" ). -spec run_partial(parser(PAK), bitstring()) -> {ok, {PAK, bitstring()}} | {error, bitty_error()}. run_partial(Parser, Input) -> gleam@result:'try'( do_run(Parser, Input), fun(_use0) -> {Value, Final_state} = _use0, {ok, {Value, remaining_slice(Final_state)}} end ). -file("src/bitty.gleam", 136). ?DOC( " Like `run_partial`, but also returns the `Location` where the parser\n" " stopped. Useful for incremental or streaming parsing.\n" ). -spec run_with_location(parser(PAO), bitstring()) -> {ok, {PAO, location(), bitstring()}} | {error, bitty_error()}. run_with_location(Parser, Input) -> gleam@result:'try'( do_run(Parser, Input), fun(_use0) -> {Value, Final_state} = _use0, Loc = {location, erlang:element(3, Final_state), erlang:element(4, Final_state)}, {ok, {Value, Loc, remaining_slice(Final_state)}} end ).