-module(pears). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]). -export([map/2, to/2, alt/2, any/0, eof/0, satisfying/1, then/2, item/1, pair/2, left/2, right/2, many0/1, many1/1, lazy/1, char/1, string/1, parse/2, one_of/1, digit/0, number/0, between/3, whitespace/0, whitespace0/0, whitespace1/0]). -export_type([parsed/2, parse_error/1]). -type parsed(FKC, FKD) :: {parsed, list(FKC), FKD}. -type parse_error(FKE) :: {parse_error, list(FKE), list(binary())}. -spec ok(list(FKX), FKZ) -> {ok, parsed(FKX, FKZ)} | {error, parse_error(FKX)}. ok(Input, Value) -> {ok, {parsed, Input, Value}}. -spec map( fun((list(FLC)) -> {ok, parsed(FLC, FLD)} | {error, parse_error(FLC)}), fun((FLD) -> FLG) ) -> fun((list(FLC)) -> {ok, parsed(FLC, FLG)} | {error, parse_error(FLC)}). map(P, Fun) -> fun(Input) -> _pipe = P(Input), gleam@result:map( _pipe, fun(Parsed) -> {parsed, erlang:element(2, Parsed), Fun(erlang:element(3, Parsed))} end ) end. -spec to( fun((list(FLJ)) -> {ok, parsed(FLJ, any())} | {error, parse_error(FLJ)}), FLN ) -> fun((list(FLJ)) -> {ok, parsed(FLJ, FLN)} | {error, parse_error(FLJ)}). to(Parser, Value) -> map(Parser, fun(_) -> Value end). -spec alt( fun((list(FLQ)) -> {ok, parsed(FLQ, FLR)} | {error, parse_error(FLQ)}), fun((list(FLQ)) -> {ok, parsed(FLQ, FLR)} | {error, parse_error(FLQ)}) ) -> fun((list(FLQ)) -> {ok, parsed(FLQ, FLR)} | {error, parse_error(FLQ)}). alt(Parser_1, Parser_2) -> fun(Input) -> case Parser_1(Input) of {ok, Result} -> {ok, Result}; {error, _} -> Parser_2(Input) end end. -spec any() -> fun((list(FLY)) -> {ok, parsed(FLY, FLY)} | {error, parse_error(FLY)}). any() -> fun(In) -> case pears@input:get(In) of none -> {error, {parse_error, In, [<<"any"/utf8>>]}}; {some, {Value, Next}} -> ok(Next, Value) end end. -spec eof() -> fun((list(FMB)) -> {ok, parsed(FMB, nil)} | {error, parse_error(FMB)}). eof() -> fun(Input) -> case Input of [] -> ok(Input, nil); _ -> {error, {parse_error, Input, [<<"EOF"/utf8>>]}} end end. -spec satisfying(fun((FME) -> boolean())) -> fun((list(FME)) -> {ok, parsed(FME, FME)} | {error, parse_error(FME)}). satisfying(F) -> fun(In) -> case pears@input:get(In) of none -> {error, {parse_error, In, [<<"satisfying"/utf8>>]}}; {some, {Value, Next}} -> case F(Value) of true -> ok(Next, Value); false -> {error, {parse_error, In, [<<"satisfying"/utf8>>]}} end end end. -spec then( fun((list(FMI)) -> {ok, parsed(FMI, any())} | {error, parse_error(FMI)}), fun((list(FMI)) -> {ok, parsed(FMI, FMM)} | {error, parse_error(FMI)}) ) -> fun((list(FMI)) -> {ok, parsed(FMI, FMM)} | {error, parse_error(FMI)}). then(Parser_a, Parser_b) -> fun(Input) -> case Parser_a(Input) of {ok, Parsed} -> Parser_b(erlang:element(2, Parsed)); {error, Err} -> {error, Err} end end. -spec item(FMR) -> fun((list(FMR)) -> {ok, parsed(FMR, FMR)} | {error, parse_error(FMR)}). item(Item) -> fun(Input) -> case Input of [Head | Next] when Head =:= Item -> ok(Next, Head); _ -> {error, {parse_error, Input, [<<"item"/utf8>>]}} end end. -spec pair( fun((list(FMU)) -> {ok, parsed(FMU, FMV)} | {error, parse_error(FMU)}), fun((list(FMU)) -> {ok, parsed(FMU, FMY)} | {error, parse_error(FMU)}) ) -> fun((list(FMU)) -> {ok, parsed(FMU, {FMV, FMY})} | {error, parse_error(FMU)}). pair(P1, P2) -> fun(In) -> gleam@result:'try'( P1(In), fun(Parsed_1) -> gleam@result:'try'( P2(erlang:element(2, Parsed_1)), fun(Parsed_2) -> ok( erlang:element(2, Parsed_2), {erlang:element(3, Parsed_1), erlang:element(3, Parsed_2)} ) end ) end ) end. -spec left( fun((list(FND)) -> {ok, parsed(FND, FNE)} | {error, parse_error(FND)}), fun((list(FND)) -> {ok, parsed(FND, any())} | {error, parse_error(FND)}) ) -> fun((list(FND)) -> {ok, parsed(FND, FNE)} | {error, parse_error(FND)}). left(P1, P2) -> fun(In) -> gleam@result:'try'( P1(In), fun(Parsed_1) -> gleam@result:'try'( P2(erlang:element(2, Parsed_1)), fun(Parsed_2) -> ok( erlang:element(2, Parsed_2), erlang:element(3, Parsed_1) ) end ) end ) end. -spec right( fun((list(FNM)) -> {ok, parsed(FNM, any())} | {error, parse_error(FNM)}), fun((list(FNM)) -> {ok, parsed(FNM, FNQ)} | {error, parse_error(FNM)}) ) -> fun((list(FNM)) -> {ok, parsed(FNM, FNQ)} | {error, parse_error(FNM)}). right(P1, P2) -> fun(In) -> gleam@result:'try'( P1(In), fun(Parsed_1) -> gleam@result:'try'( P2(erlang:element(2, Parsed_1)), fun(Parsed_2) -> ok( erlang:element(2, Parsed_2), erlang:element(3, Parsed_2) ) end ) end ) end. -spec many0( fun((list(FNV)) -> {ok, parsed(FNV, FNW)} | {error, parse_error(FNV)}) ) -> fun((list(FNV)) -> {ok, parsed(FNV, list(FNW))} | {error, parse_error(FNV)}). many0(Parser) -> fun(In) -> case Parser(In) of {ok, Parsed} -> gleam@result:'try'( (many0(Parser))(erlang:element(2, Parsed)), fun(Next) -> ok( erlang:element(2, Next), [erlang:element(3, Parsed) | erlang:element(3, Next)] ) end ); {error, _} -> ok(In, []) end end. -spec many1( fun((list(FOC)) -> {ok, parsed(FOC, FOD)} | {error, parse_error(FOC)}) ) -> fun((list(FOC)) -> {ok, parsed(FOC, list(FOD))} | {error, parse_error(FOC)}). many1(Parser) -> fun(In) -> gleam@result:'try'( Parser(In), fun(Parsed) -> gleam@result:'try'( (many0(Parser))(erlang:element(2, Parsed)), fun(Rest) -> ok( erlang:element(2, Rest), [erlang:element(3, Parsed) | erlang:element(3, Rest)] ) end ) end ) end. -spec lazy( fun(() -> fun((list(FOJ)) -> {ok, parsed(FOJ, FOK)} | {error, parse_error(FOJ)})) ) -> fun((list(FOJ)) -> {ok, parsed(FOJ, FOK)} | {error, parse_error(FOJ)}). lazy(F) -> fun(Input) -> (F())(Input) end. -spec char(binary()) -> fun((list(binary())) -> {ok, parsed(binary(), binary())} | {error, parse_error(binary())}). char(C) -> item(C). -spec string(binary()) -> fun((list(binary())) -> {ok, parsed(binary(), binary())} | {error, parse_error(binary())}). string(Str) -> fun(Input) -> S = gleam@string:to_graphemes(Str), Length = gleam@list:length(S), case gleam@list:length(Input) >= Length of true -> Candidate = gleam@list:take(Input, Length), case Candidate =:= S of true -> ok(gleam@list:drop(Input, Length), Str); false -> {error, {parse_error, Input, [Str]}} end; false -> {error, {parse_error, Input, [Str]}} end end. -spec parse( fun((list(binary())) -> {ok, parsed(binary(), FKS)} | {error, parse_error(binary())}), binary() ) -> {ok, parsed(binary(), FKS)} | {error, parse_error(binary())}. parse(Parser, Input) -> Parser(gleam@string:to_graphemes(Input)). -spec one_of(list(FOT)) -> fun((list(FOT)) -> {ok, parsed(FOT, FOT)} | {error, parse_error(FOT)}). one_of(Items) -> satisfying(fun(C) -> gleam@list:contains(Items, C) end). -spec digit() -> fun((list(binary())) -> {ok, parsed(binary(), binary())} | {error, parse_error(binary())}). digit() -> one_of( [<<"0"/utf8>>, <<"1"/utf8>>, <<"2"/utf8>>, <<"3"/utf8>>, <<"4"/utf8>>, <<"5"/utf8>>, <<"6"/utf8>>, <<"7"/utf8>>, <<"8"/utf8>>, <<"9"/utf8>>] ). -spec number() -> fun((list(binary())) -> {ok, parsed(binary(), integer())} | {error, parse_error(binary())}). number() -> _pipe = many1(digit()), map( _pipe, fun(Digits) -> gleam@list:fold( Digits, 0, fun(Acc, Digit) -> _assert_subject = gleam@int:parse(Digit), {ok, Digit@1} = case _assert_subject of {ok, _} -> _assert_subject; _assert_fail -> erlang:error(#{gleam_error => let_assert, message => <<"Assertion pattern match failed"/utf8>>, value => _assert_fail, module => <<"pears"/utf8>>, function => <<"number"/utf8>>, line => 199}) end, (Acc * 10) + Digit@1 end ) end ). -spec between( fun((list(FPB)) -> {ok, parsed(FPB, any())} | {error, parse_error(FPB)}), fun((list(FPB)) -> {ok, parsed(FPB, any())} | {error, parse_error(FPB)}), fun((list(FPB)) -> {ok, parsed(FPB, FPI)} | {error, parse_error(FPB)}) ) -> fun((list(FPB)) -> {ok, parsed(FPB, FPI)} | {error, parse_error(FPB)}). between(Open, Close, Parser) -> _pipe = Open, _pipe@1 = right(_pipe, Parser), left(_pipe@1, Close). -spec whitespace() -> fun((list(binary())) -> {ok, parsed(binary(), binary())} | {error, parse_error(binary())}). whitespace() -> satisfying(fun(C) -> gleam@string:trim(C) =:= <<""/utf8>> end). -spec whitespace0() -> fun((list(binary())) -> {ok, parsed(binary(), list(binary()))} | {error, parse_error(binary())}). whitespace0() -> many0(whitespace()). -spec whitespace1() -> fun((list(binary())) -> {ok, parsed(binary(), list(binary()))} | {error, parse_error(binary())}). whitespace1() -> many1(whitespace()).