Current section
Files
Jump to
Current section
Files
src/bliss@static_path_parser.erl
-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()).