-module(pears@combinators). -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, just/1, pair/2, seq/1, left/2, right/2, many0/1, many1/1, lazy/1, one_of/1, none_of/1, between/3, choice/1, sep_by0/2, sep_by1/2, maybe/1, unwrap/2, recognize/1]). -spec map( fun((list(FLZ)) -> {ok, pears:parsed(FLZ, FMA)} | {error, pears:parse_error(FLZ)}), fun((FMA) -> FMD) ) -> fun((list(FLZ)) -> {ok, pears:parsed(FLZ, FMD)} | {error, pears:parse_error(FLZ)}). 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(FMG)) -> {ok, pears:parsed(FMG, any())} | {error, pears:parse_error(FMG)}), FMK ) -> fun((list(FMG)) -> {ok, pears:parsed(FMG, FMK)} | {error, pears:parse_error(FMG)}). to(Parser, Value) -> map(Parser, fun(_) -> Value end). -spec alt( fun((list(FMN)) -> {ok, pears:parsed(FMN, FMO)} | {error, pears:parse_error(FMN)}), fun((list(FMN)) -> {ok, pears:parsed(FMN, FMO)} | {error, pears:parse_error(FMN)}) ) -> fun((list(FMN)) -> {ok, pears:parsed(FMN, FMO)} | {error, pears:parse_error(FMN)}). 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(FMV)) -> {ok, pears:parsed(FMV, FMV)} | {error, pears:parse_error(FMV)}). any() -> fun(In) -> case pears@input:get(In) of none -> {error, {parse_error, In, [<<"any"/utf8>>]}}; {some, {Value, Next}} -> pears:ok(Next, Value) end end. -spec eof() -> fun((list(FMY)) -> {ok, pears:parsed(FMY, nil)} | {error, pears:parse_error(FMY)}). eof() -> fun(In) -> case pears@input:at_end(In) of true -> pears:ok(In, nil); false -> {error, {parse_error, In, [<<"EOF"/utf8>>]}} end end. -spec satisfying(fun((FNB) -> boolean())) -> fun((list(FNB)) -> {ok, pears:parsed(FNB, FNB)} | {error, pears:parse_error(FNB)}). 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 -> pears:ok(Next, Value); false -> {error, {parse_error, In, [<<"satisfying"/utf8>>]}} end end end. -spec just(FNF) -> fun((list(FNF)) -> {ok, pears:parsed(FNF, FNF)} | {error, pears:parse_error(FNF)}). just(Item) -> fun(Input) -> case Input of [Head | Next] when Head =:= Item -> pears:ok(Next, Head); _ -> {error, {parse_error, Input, [gleam@string:inspect(Item)]}} end end. -spec pair( fun((list(FNI)) -> {ok, pears:parsed(FNI, FNJ)} | {error, pears:parse_error(FNI)}), fun((list(FNI)) -> {ok, pears:parsed(FNI, FNM)} | {error, pears:parse_error(FNI)}) ) -> fun((list(FNI)) -> {ok, pears:parsed(FNI, {FNJ, FNM})} | {error, pears:parse_error(FNI)}). 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) -> pears:ok( erlang:element(2, Parsed_2), {erlang:element(3, Parsed_1), erlang:element(3, Parsed_2)} ) end ) end ) end. -spec do_sequence( list(fun((list(FNZ)) -> {ok, pears:parsed(FNZ, FOA)} | {error, pears:parse_error(FNZ)})), list(FNZ), list(FOA) ) -> {ok, pears:parsed(FNZ, list(FOA))} | {error, pears:parse_error(FNZ)}. do_sequence(Parsers, Input, Acc) -> case Parsers of [] -> pears:ok(Input, gleam@list:reverse(Acc)); [Parser | Rest] -> gleam@result:'try'( Parser(Input), fun(Parsed) -> do_sequence( Rest, erlang:element(2, Parsed), [erlang:element(3, Parsed) | Acc] ) end ) end. -spec seq( list(fun((list(FNR)) -> {ok, pears:parsed(FNR, FNS)} | {error, pears:parse_error(FNR)})) ) -> fun((list(FNR)) -> {ok, pears:parsed(FNR, list(FNS))} | {error, pears:parse_error(FNR)}). seq(Parsers) -> fun(Input) -> do_sequence(Parsers, Input, []) end. -spec left( fun((list(FOJ)) -> {ok, pears:parsed(FOJ, FOK)} | {error, pears:parse_error(FOJ)}), fun((list(FOJ)) -> {ok, pears:parsed(FOJ, any())} | {error, pears:parse_error(FOJ)}) ) -> fun((list(FOJ)) -> {ok, pears:parsed(FOJ, FOK)} | {error, pears:parse_error(FOJ)}). 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) -> pears:ok( erlang:element(2, Parsed_2), erlang:element(3, Parsed_1) ) end ) end ) end. -spec right( fun((list(FOS)) -> {ok, pears:parsed(FOS, any())} | {error, pears:parse_error(FOS)}), fun((list(FOS)) -> {ok, pears:parsed(FOS, FOW)} | {error, pears:parse_error(FOS)}) ) -> fun((list(FOS)) -> {ok, pears:parsed(FOS, FOW)} | {error, pears:parse_error(FOS)}). 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) -> pears:ok( erlang:element(2, Parsed_2), erlang:element(3, Parsed_2) ) end ) end ) end. -spec many0( fun((list(FPB)) -> {ok, pears:parsed(FPB, FPC)} | {error, pears:parse_error(FPB)}) ) -> fun((list(FPB)) -> {ok, pears:parsed(FPB, list(FPC))} | {error, pears:parse_error(FPB)}). many0(Parser) -> fun(In) -> case Parser(In) of {ok, Parsed} -> gleam@result:'try'( (many0(Parser))(erlang:element(2, Parsed)), fun(Next) -> pears:ok( erlang:element(2, Next), [erlang:element(3, Parsed) | erlang:element(3, Next)] ) end ); {error, _} -> pears:ok(In, []) end end. -spec many1( fun((list(FPI)) -> {ok, pears:parsed(FPI, FPJ)} | {error, pears:parse_error(FPI)}) ) -> fun((list(FPI)) -> {ok, pears:parsed(FPI, list(FPJ))} | {error, pears:parse_error(FPI)}). many1(Parser) -> fun(In) -> gleam@result:'try'( Parser(In), fun(Parsed) -> gleam@result:'try'( (many0(Parser))(erlang:element(2, Parsed)), fun(Rest) -> pears:ok( erlang:element(2, Rest), [erlang:element(3, Parsed) | erlang:element(3, Rest)] ) end ) end ) end. -spec lazy( fun(() -> fun((list(FPP)) -> {ok, pears:parsed(FPP, FPQ)} | {error, pears:parse_error(FPP)})) ) -> fun((list(FPP)) -> {ok, pears:parsed(FPP, FPQ)} | {error, pears:parse_error(FPP)}). lazy(F) -> fun(Input) -> (F())(Input) end. -spec one_of(list(FPV)) -> fun((list(FPV)) -> {ok, pears:parsed(FPV, FPV)} | {error, pears:parse_error(FPV)}). one_of(Items) -> satisfying(fun(C) -> gleam@list:contains(Items, C) end). -spec none_of(list(FPZ)) -> fun((list(FPZ)) -> {ok, pears:parsed(FPZ, FPZ)} | {error, pears:parse_error(FPZ)}). none_of(Items) -> satisfying(fun(C) -> not gleam@list:contains(Items, C) end). -spec between( fun((list(FQD)) -> {ok, pears:parsed(FQD, FQE)} | {error, pears:parse_error(FQD)}), fun((list(FQD)) -> {ok, pears:parsed(FQD, any())} | {error, pears:parse_error(FQD)}), fun((list(FQD)) -> {ok, pears:parsed(FQD, any())} | {error, pears:parse_error(FQD)}) ) -> fun((list(FQD)) -> {ok, pears:parsed(FQD, FQE)} | {error, pears:parse_error(FQD)}). between(Parser, Open, Close) -> _pipe = Open, _pipe@1 = right(_pipe, Parser), left(_pipe@1, Close). -spec choice( list(fun((list(FQP)) -> {ok, pears:parsed(FQP, FQQ)} | {error, pears:parse_error(FQP)})) ) -> fun((list(FQP)) -> {ok, pears:parsed(FQP, FQQ)} | {error, pears:parse_error(FQP)}). choice(Parsers) -> fun(Input) -> case Parsers of [] -> {error, {parse_error, Input, [<<"choice"/utf8>>]}}; [Parser | Rest] -> case Parser(Input) of {ok, Parsed} -> {ok, Parsed}; {error, _} -> (choice(Rest))(Input) end end end. -spec sep_by0( fun((list(FQW)) -> {ok, pears:parsed(FQW, FQX)} | {error, pears:parse_error(FQW)}), fun((list(FQW)) -> {ok, pears:parsed(FQW, any())} | {error, pears:parse_error(FQW)}) ) -> fun((list(FQW)) -> {ok, pears:parsed(FQW, list(FQX))} | {error, pears:parse_error(FQW)}). sep_by0(Parser, Separator) -> fun(In) -> case Parser(In) of {ok, Parsed} -> gleam@result:'try'( (many0(right(Separator, Parser)))(erlang:element(2, Parsed)), fun(Rest) -> pears:ok( erlang:element(2, Rest), [erlang:element(3, Parsed) | erlang:element(3, Rest)] ) end ); {error, _} -> pears:ok(In, []) end end. -spec sep_by1( fun((list(FRG)) -> {ok, pears:parsed(FRG, FRH)} | {error, pears:parse_error(FRG)}), fun((list(FRG)) -> {ok, pears:parsed(FRG, any())} | {error, pears:parse_error(FRG)}) ) -> fun((list(FRG)) -> {ok, pears:parsed(FRG, list(FRH))} | {error, pears:parse_error(FRG)}). sep_by1(Parser, Separator) -> fun(Input) -> gleam@result:'try'( Parser(Input), fun(Parsed) -> gleam@result:'try'( (many0( begin _pipe = Separator, right(_pipe, Parser) end ))(erlang:element(2, Parsed)), fun(Rest) -> pears:ok( erlang:element(2, Rest), [erlang:element(3, Parsed) | erlang:element(3, Rest)] ) end ) end ) end. -spec maybe( fun((list(FRQ)) -> {ok, pears:parsed(FRQ, FRR)} | {error, pears:parse_error(FRQ)}) ) -> fun((list(FRQ)) -> {ok, pears:parsed(FRQ, gleam@option:option(FRR))} | {error, pears:parse_error(FRQ)}). maybe(Parser) -> fun(In) -> case Parser(In) of {ok, Parsed} -> pears:ok( erlang:element(2, Parsed), {some, erlang:element(3, Parsed)} ); {error, _} -> pears:ok(In, none) end end. -spec unwrap( fun((list(FRX)) -> {ok, pears:parsed(FRX, gleam@option:option(FRY))} | {error, pears:parse_error(FRX)}), FRY ) -> fun((list(FRX)) -> {ok, pears:parsed(FRX, FRY)} | {error, pears:parse_error(FRX)}). unwrap(Parser, Default) -> _pipe = Parser, map(_pipe, fun(Maybe_value) -> case Maybe_value of none -> Default; {some, Value} -> Value end end). -spec recognize( fun((list(FSE)) -> {ok, pears:parsed(FSE, any())} | {error, pears:parse_error(FSE)}) ) -> fun((list(FSE)) -> {ok, pears:parsed(FSE, list(FSE))} | {error, pears:parse_error(FSE)}). recognize(Parser) -> fun(In) -> gleam@result:'try'( Parser(In), fun(Parsed) -> Original_length = gleam@list:length(In), Parsed_length = gleam@list:length(erlang:element(2, Parsed)), Consumed = gleam@list:take(In, Original_length - Parsed_length), pears:ok(erlang:element(2, Parsed), Consumed) end ) end.