Current section

Files

Jump to
pears src pears.erl
Raw

src/pears.erl

-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()).