Current section

Files

Jump to
pears src pears@combinators.erl
Raw

src/pears@combinators.erl

-module(pears@combinators).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([map/2, map_error/2, labelled/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, do_choice/2, choice/1, sep_by0/2, sep_by1/2, maybe/1, unwrap/2, recognize/1]).
-spec consume_token(
pears@input:input(FNB),
fun((FNB) -> {ok, pears:parsed(FNB, FND)} | {error, pears:parse_error(FNB)})
) -> {ok, pears:parsed(FNB, FND)} | {error, pears:parse_error(FNB)}.
consume_token(In, F) ->
case pears@input:get(In) of
none ->
{error, {unexpected_end_of_input, In, [<<"any token"/utf8>>]}};
{some, Value} ->
F(Value)
end.
-spec map(
fun((pears@input:input(FNI)) -> {ok, pears:parsed(FNI, FNJ)} |
{error, pears:parse_error(FNI)}),
fun((FNJ) -> FNM)
) -> fun((pears@input:input(FNI)) -> {ok, pears:parsed(FNI, FNM)} |
{error, pears:parse_error(FNI)}).
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 map_error(
fun((pears@input:input(FNP)) -> {ok, pears:parsed(FNP, FNQ)} |
{error, pears:parse_error(FNP)}),
fun((pears:parse_error(FNP)) -> pears:parse_error(FNP))
) -> fun((pears@input:input(FNP)) -> {ok, pears:parsed(FNP, FNQ)} |
{error, pears:parse_error(FNP)}).
map_error(P, Fun) ->
fun(Input) -> _pipe = P(Input),
gleam@result:map_error(_pipe, Fun) end.
-spec labelled(
fun((pears@input:input(FNX)) -> {ok, pears:parsed(FNX, FNY)} |
{error, pears:parse_error(FNX)}),
binary()
) -> fun((pears@input:input(FNX)) -> {ok, pears:parsed(FNX, FNY)} |
{error, pears:parse_error(FNX)}).
labelled(Parser, Label) ->
fun(Input) -> _pipe = Parser(Input),
gleam@result:map_error(_pipe, fun(Err) -> case Err of
{unexpected_end_of_input, _, _} ->
Err;
{unexpected_token, In, _, Error} ->
{unexpected_token, In, [Label], Error}
end end) end.
-spec to(
fun((pears@input:input(FOD)) -> {ok, pears:parsed(FOD, any())} |
{error, pears:parse_error(FOD)}),
FOH
) -> fun((pears@input:input(FOD)) -> {ok, pears:parsed(FOD, FOH)} |
{error, pears:parse_error(FOD)}).
to(Parser, Value) ->
map(Parser, fun(_) -> Value end).
-spec alt(
fun((pears@input:input(FOK)) -> {ok, pears:parsed(FOK, FOL)} |
{error, pears:parse_error(FOK)}),
fun((pears@input:input(FOK)) -> {ok, pears:parsed(FOK, FOL)} |
{error, pears:parse_error(FOK)})
) -> fun((pears@input:input(FOK)) -> {ok, pears:parsed(FOK, FOL)} |
{error, pears:parse_error(FOK)}).
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((pears@input:input(FOS)) -> {ok, pears:parsed(FOS, FOS)} |
{error, pears:parse_error(FOS)}).
any() ->
fun(In) ->
consume_token(
In,
fun(Token) -> pears:ok(pears@input:next(In), Token) end
)
end.
-spec eof() -> fun((pears@input:input(FOV)) -> {ok, pears:parsed(FOV, nil)} |
{error, pears:parse_error(FOV)}).
eof() ->
fun(In) -> case pears@input:get(In) of
none ->
pears:ok(In, nil);
{some, Token} ->
{error, {unexpected_token, In, [<<"EOF"/utf8>>], Token}}
end end.
-spec satisfying(fun((FOY) -> boolean())) -> fun((pears@input:input(FOY)) -> {ok,
pears:parsed(FOY, FOY)} |
{error, pears:parse_error(FOY)}).
satisfying(F) ->
fun(In) -> case pears@input:get(In) of
none ->
{error,
{unexpected_end_of_input,
In,
[<<"satifying predicate"/utf8>>]}};
{some, Value} ->
case F(Value) of
true ->
pears:ok(pears@input:next(In), Value);
false ->
{error,
{unexpected_token,
In,
[<<"satisfying predicate"/utf8>>],
Value}}
end
end end.
-spec just(FPC) -> fun((pears@input:input(FPC)) -> {ok, pears:parsed(FPC, FPC)} |
{error, pears:parse_error(FPC)}).
just(Item) ->
fun(In) -> case pears@input:get(In) of
none ->
{error,
{unexpected_end_of_input, In, [gleam@string:inspect(Item)]}};
{some, Head} when Head =:= Item ->
{ok, {parsed, pears@input:next(In), Item}};
{some, Head@1} ->
{error,
{unexpected_token, In, [gleam@string:inspect(Item)], Head@1}}
end end.
-spec pair(
fun((pears@input:input(FPF)) -> {ok, pears:parsed(FPF, FPG)} |
{error, pears:parse_error(FPF)}),
fun((pears@input:input(FPF)) -> {ok, pears:parsed(FPF, FPJ)} |
{error, pears:parse_error(FPF)})
) -> fun((pears@input:input(FPF)) -> {ok, pears:parsed(FPF, {FPG, FPJ})} |
{error, pears:parse_error(FPF)}).
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((pears@input:input(FPW)) -> {ok, pears:parsed(FPW, FPX)} |
{error, pears:parse_error(FPW)})),
pears@input:input(FPW),
list(FPX)
) -> {ok, pears:parsed(FPW, list(FPX))} | {error, pears:parse_error(FPW)}.
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((pears@input:input(FPO)) -> {ok, pears:parsed(FPO, FPP)} |
{error, pears:parse_error(FPO)}))
) -> fun((pears@input:input(FPO)) -> {ok, pears:parsed(FPO, list(FPP))} |
{error, pears:parse_error(FPO)}).
seq(Parsers) ->
fun(Input) -> do_sequence(Parsers, Input, []) end.
-spec left(
fun((pears@input:input(FQG)) -> {ok, pears:parsed(FQG, FQH)} |
{error, pears:parse_error(FQG)}),
fun((pears@input:input(FQG)) -> {ok, pears:parsed(FQG, any())} |
{error, pears:parse_error(FQG)})
) -> fun((pears@input:input(FQG)) -> {ok, pears:parsed(FQG, FQH)} |
{error, pears:parse_error(FQG)}).
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((pears@input:input(FQP)) -> {ok, pears:parsed(FQP, any())} |
{error, pears:parse_error(FQP)}),
fun((pears@input:input(FQP)) -> {ok, pears:parsed(FQP, FQT)} |
{error, pears:parse_error(FQP)})
) -> fun((pears@input:input(FQP)) -> {ok, pears:parsed(FQP, FQT)} |
{error, pears:parse_error(FQP)}).
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((pears@input:input(FQY)) -> {ok, pears:parsed(FQY, FQZ)} |
{error, pears:parse_error(FQY)})
) -> fun((pears@input:input(FQY)) -> {ok, pears:parsed(FQY, list(FQZ))} |
{error, pears:parse_error(FQY)}).
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((pears@input:input(FRF)) -> {ok, pears:parsed(FRF, FRG)} |
{error, pears:parse_error(FRF)})
) -> fun((pears@input:input(FRF)) -> {ok, pears:parsed(FRF, list(FRG))} |
{error, pears:parse_error(FRF)}).
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((pears@input:input(FRM)) -> {ok, pears:parsed(FRM, FRN)} |
{error, pears:parse_error(FRM)}))
) -> fun((pears@input:input(FRM)) -> {ok, pears:parsed(FRM, FRN)} |
{error, pears:parse_error(FRM)}).
lazy(F) ->
fun(Input) -> (F())(Input) end.
-spec one_of(list(FRS)) -> fun((pears@input:input(FRS)) -> {ok,
pears:parsed(FRS, FRS)} |
{error, pears:parse_error(FRS)}).
one_of(Items) ->
_pipe = satisfying(fun(C) -> gleam@list:contains(Items, C) end),
map_error(
_pipe,
fun(Err) ->
Expected = gleam@list:map(Items, fun gleam@string:inspect/1),
case Err of
{unexpected_token, In, _, Token} ->
{unexpected_token, In, Expected, Token};
{unexpected_end_of_input, In@1, _} ->
{unexpected_end_of_input, In@1, Expected}
end
end
).
-spec none_of(list(FRW)) -> fun((pears@input:input(FRW)) -> {ok,
pears:parsed(FRW, FRW)} |
{error, pears:parse_error(FRW)}).
none_of(Items) ->
satisfying(fun(C) -> not gleam@list:contains(Items, C) end).
-spec between(
fun((pears@input:input(FSA)) -> {ok, pears:parsed(FSA, FSB)} |
{error, pears:parse_error(FSA)}),
fun((pears@input:input(FSA)) -> {ok, pears:parsed(FSA, any())} |
{error, pears:parse_error(FSA)}),
fun((pears@input:input(FSA)) -> {ok, pears:parsed(FSA, any())} |
{error, pears:parse_error(FSA)})
) -> fun((pears@input:input(FSA)) -> {ok, pears:parsed(FSA, FSB)} |
{error, pears:parse_error(FSA)}).
between(Parser, Open, Close) ->
_pipe = Open,
_pipe@1 = right(_pipe, Parser),
left(_pipe@1, Close).
-spec do_choice(
list(fun((pears@input:input(FST)) -> {ok, pears:parsed(FST, FSU)} |
{error, pears:parse_error(FST)})),
list(binary())
) -> fun((pears@input:input(FST)) -> {ok, pears:parsed(FST, FSU)} |
{error, pears:parse_error(FST)}).
do_choice(Parsers, Expected) ->
fun(In) -> case Parsers of
[] ->
case pears@input:get(In) of
none ->
{error, {unexpected_end_of_input, In, Expected}};
{some, Token} ->
{error, {unexpected_token, In, Expected, Token}}
end;
[Parser | Rest] ->
case Parser(In) of
{ok, Parsed} ->
{ok, Parsed};
{error, Err} ->
New_expected = case Err of
{unexpected_token, _, Expected@1, _} ->
Expected@1;
{unexpected_end_of_input, _, Expected@2} ->
Expected@2
end,
(do_choice(
Rest,
gleam@list:concat([Expected, New_expected])
))(In)
end
end end.
-spec choice(
list(fun((pears@input:input(FSM)) -> {ok, pears:parsed(FSM, FSN)} |
{error, pears:parse_error(FSM)}))
) -> fun((pears@input:input(FSM)) -> {ok, pears:parsed(FSM, FSN)} |
{error, pears:parse_error(FSM)}).
choice(Parsers) ->
do_choice(Parsers, []).
-spec sep_by0(
fun((pears@input:input(FTB)) -> {ok, pears:parsed(FTB, FTC)} |
{error, pears:parse_error(FTB)}),
fun((pears@input:input(FTB)) -> {ok, pears:parsed(FTB, any())} |
{error, pears:parse_error(FTB)})
) -> fun((pears@input:input(FTB)) -> {ok, pears:parsed(FTB, list(FTC))} |
{error, pears:parse_error(FTB)}).
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((pears@input:input(FTL)) -> {ok, pears:parsed(FTL, FTM)} |
{error, pears:parse_error(FTL)}),
fun((pears@input:input(FTL)) -> {ok, pears:parsed(FTL, any())} |
{error, pears:parse_error(FTL)})
) -> fun((pears@input:input(FTL)) -> {ok, pears:parsed(FTL, list(FTM))} |
{error, pears:parse_error(FTL)}).
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((pears@input:input(FTV)) -> {ok, pears:parsed(FTV, FTW)} |
{error, pears:parse_error(FTV)})
) -> fun((pears@input:input(FTV)) -> {ok,
pears:parsed(FTV, gleam@option:option(FTW))} |
{error, pears:parse_error(FTV)}).
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((pears@input:input(FUC)) -> {ok,
pears:parsed(FUC, gleam@option:option(FUD))} |
{error, pears:parse_error(FUC)}),
FUD
) -> fun((pears@input:input(FUC)) -> {ok, pears:parsed(FUC, FUD)} |
{error, pears:parse_error(FUC)}).
unwrap(Parser, Default) ->
_pipe = Parser,
map(_pipe, fun(Maybe_value) -> case Maybe_value of
none ->
Default;
{some, Value} ->
Value
end end).
-spec recognize(
fun((pears@input:input(FUJ)) -> {ok, pears:parsed(FUJ, any())} |
{error, pears:parse_error(FUJ)})
) -> fun((pears@input:input(FUJ)) -> {ok, pears:parsed(FUJ, list(FUJ))} |
{error, pears:parse_error(FUJ)}).
recognize(Parser) ->
fun(In) ->
gleam@result:'try'(
Parser(In),
fun(Parsed) ->
Start = erlang:element(3, In),
Parsed_length = erlang:element(3, erlang:element(2, Parsed)) - Start,
Consumed = begin
_pipe = erlang:element(2, In),
_pipe@1 = gleam@list:drop(_pipe, Start),
gleam@list:take(_pipe@1, Parsed_length)
end,
pears:ok(erlang:element(2, Parsed), Consumed)
end
)
end.