-module(bliss@static_path_parser). -compile(no_auto_import). -export([parse/2, yield0/0, yield1/0, yield2/0, yield3/0, seg/2, int/1, str/1]). -export_type([parser/1, error/0, response/1]). -opaque parser(HGS) :: {parser, fun((list(binary())) -> {ok, {HGS, list(binary())}} | {error, error()})}. -type error() :: not_enough_segments | {expected, binary()}. -type response(HGT) :: {exact_match, HGT} | {partial_match, HGT, list(binary())}. -spec then(parser(HGW), fun((HGW) -> parser(HGY))) -> parser(HGY). then(Parser, F) -> P = fun(Input) -> _pipe = use_parser(Parser, Input), gleam@result:then( _pipe, fun(Result) -> {Value, Rest} = Result, use_parser(F(Value), Rest) end ) end, {parser, P}. -spec map(parser(HHB), fun((HHB) -> HHD)) -> parser(HHD). map(Parser, F) -> then( Parser, fun(A) -> _pipe = F(A), initial(_pipe) end ). -spec map2(parser(HHF), parser(HHH), fun((HHF, HHH) -> HHJ)) -> parser(HHJ). map2(Parser_a, Parser_b, F) -> then(Parser_a, fun(A) -> map(Parser_b, fun(B) -> F(A, B) end) end). -spec parse(binary(), parser(HHL)) -> {ok, response(HHL)} | {error, error()}. parse(Input, Parser) -> Segments = bliss@utils:segments(Input), case use_parser(Parser, Segments) of {error, _try} -> {error, _try}; {ok, Res} -> {Parsed, Left_over} = Res, case Left_over of [] -> {ok, {exact_match, Parsed}}; _@1 -> {ok, {partial_match, Parsed, Left_over}} end end. -spec use_parser(parser(HHQ), list(binary())) -> {ok, {HHQ, list(binary())}} | {error, error()}. use_parser(Parser, Segments) -> {parser, P} = Parser, P(Segments). -spec tuple1(HHU) -> {HHU}. tuple1(A) -> {A}. -spec tuple2(HHW) -> fun((HKT) -> {HHW, HKT}). tuple2(A) -> fun(B) -> {A, B} end. -spec tuple3(HIB) -> fun((HHZ) -> fun((HIA) -> {HIB, HHZ, HIA})). tuple3(A) -> fun(B) -> fun(C) -> {A, B, C} end end. -spec initial(HIC) -> parser(HIC). initial(Constructor) -> P = fun(Input) -> {ok, {Constructor, Input}} end, {parser, P}. -spec yield0() -> parser({}). yield0() -> initial({}). -spec yield1() -> parser(fun((HIF) -> {HIF})). yield1() -> initial(fun tuple1/1). -spec yield2() -> parser(fun((HIH) -> fun((HII) -> {HIH, HII}))). yield2() -> initial(fun tuple2/1). -spec yield3() -> parser(fun((HIK) -> fun((HIL) -> fun((HIM) -> {HIK, HIL, HIM})))). yield3() -> initial(fun tuple3/1). -spec check_int(binary()) -> {ok, integer()} | {error, error()}. check_int(Input) -> case gleam@int:parse(Input) of {ok, N} -> {ok, N}; {error, _@1} -> {error, {expected, <<"Expected a number"/utf8>>}} end. -spec check_str(binary()) -> {ok, binary()} | {error, any()}. check_str(Input) -> {ok, Input}. -spec check_segment(binary()) -> fun((binary()) -> {ok, binary()} | {error, error()}). check_segment(Wanted) -> fun(Input) -> Expected = gleam@string:concat( [<<"Expected "/utf8>>, Wanted, <<", given "/utf8>>, Input, <<""/utf8>>] ), case Input =:= Wanted of true -> {ok, Input}; false -> {error, {expected, Expected}} end end. -spec make_parser(fun((binary()) -> {ok, HIR} | {error, error()})) -> parser(HIR). make_parser(Check) -> {parser, fun(Segments) -> case Segments of [] -> {error, not_enough_segments}; [First | Rest] -> case Check(First) of {ok, Value} -> {ok, {Value, Rest}}; {error, E} -> {error, E} end end end}. -spec segment_parser(binary()) -> parser(binary()). segment_parser(Wanted) -> make_parser(check_segment(Wanted)). -spec str_parser() -> parser(binary()). str_parser() -> make_parser(fun check_str/1). -spec int_parser() -> parser(integer()). int_parser() -> make_parser(fun check_int/1). -spec discard(parser(HIY), parser(any())) -> parser(HIY). discard(Keeper, Ignorer) -> map2(Keeper, Ignorer, fun(A, _) -> A end). -spec keep(parser(fun((HJD) -> HJE)), parser(HJD)) -> parser(HJE). keep(Mapper, Parser) -> map2(Mapper, Parser, fun(F, A) -> F(A) end). -spec seg(parser(HNB), binary()) -> parser(HNB). seg(Previous, Wanted) -> discard(Previous, segment_parser(Wanted)). -spec int(parser(fun((integer()) -> HNE))) -> parser(HNE). int(Previous) -> keep(Previous, int_parser()). -spec str(parser(fun((binary()) -> HNG))) -> parser(HNG). str(Previous) -> keep(Previous, str_parser()).