Current section

Files

Jump to
jasper src jasper.erl
Raw

src/jasper.erl

-module(jasper).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch]).
-export([parse_json/1, query_json/2]).
-export_type([json_value/0, json_parse_error/0, json_query/0, json_query_error/0]).
-type json_value() :: {object, gleam@dict:dict(binary(), json_value())} |
{array, list(json_value())} |
{string, binary()} |
{number, float()} |
{boolean, boolean()} |
null.
-type json_parse_error() :: {unexpected_token, binary()} |
unexpected_end_of_input.
-type json_query() :: root |
{key, json_query(), binary()} |
{index, json_query(), integer()}.
-type json_query_error() :: {unexpected_type, json_value()} |
{missing_object_key, json_value(), binary()} |
{index_out_of_bounds, json_value(), integer()}.
-spec whitespace0() -> fun((pears@input:input(binary())) -> {ok,
pears:parsed(binary(), list(binary()))} |
{error, pears:parse_error(binary())}).
whitespace0() ->
_pipe = pears@combinators:one_of(
[<<" "/utf8>>, <<"\n"/utf8>>, <<"\r"/utf8>>, <<"\t"/utf8>>]
),
pears@combinators:many0(_pipe).
-spec value_parser() -> fun((pears@input:input(binary())) -> {ok,
pears:parsed(binary(), json_value())} |
{error, pears:parse_error(binary())}).
value_parser() ->
Padded = fun(Parser) -> pears@combinators:left(Parser, whitespace0()) end,
Symbol = fun(S) -> Padded(pears@chars:string(S)) end,
Hex_digit = pears@combinators:one_of(
[<<"0"/utf8>>,
<<"1"/utf8>>,
<<"2"/utf8>>,
<<"3"/utf8>>,
<<"4"/utf8>>,
<<"5"/utf8>>,
<<"6"/utf8>>,
<<"7"/utf8>>,
<<"8"/utf8>>,
<<"9"/utf8>>,
<<"a"/utf8>>,
<<"b"/utf8>>,
<<"c"/utf8>>,
<<"d"/utf8>>,
<<"e"/utf8>>,
<<"f"/utf8>>,
<<"A"/utf8>>,
<<"B"/utf8>>,
<<"C"/utf8>>,
<<"D"/utf8>>,
<<"E"/utf8>>,
<<"F"/utf8>>]
),
Unicode_escape_digits = pears@combinators:recognize(
pears@combinators:seq([Hex_digit, Hex_digit, Hex_digit, Hex_digit])
),
Escape = begin
_pipe = pears@combinators:just(<<"\\"/utf8>>),
pears@combinators:right(
_pipe,
pears@combinators:choice(
[pears@combinators:just(<<"\\"/utf8>>),
pears@combinators:just(<<"/"/utf8>>),
pears@combinators:just(<<"\""/utf8>>),
pears@combinators:to(
pears@combinators:just(<<"b"/utf8>>),
<<"\x{0008}"/utf8>>
),
pears@combinators:to(
pears@combinators:just(<<"f"/utf8>>),
<<"\x{000C}"/utf8>>
),
pears@combinators:to(
pears@combinators:just(<<"n"/utf8>>),
<<"\n"/utf8>>
),
pears@combinators:to(
pears@combinators:just(<<"r"/utf8>>),
<<"\r"/utf8>>
),
pears@combinators:to(
pears@combinators:just(<<"t"/utf8>>),
<<"\t"/utf8>>
),
pears@combinators:map(
pears@combinators:right(
pears@combinators:just(<<"u"/utf8>>),
Unicode_escape_digits
),
fun(Value) ->
_assert_subject = gleam@int:base_parse(
gleam@string:concat(Value),
16
),
{ok, Number} = 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 => <<"jasper"/utf8>>,
function => <<"value_parser"/utf8>>,
line => 61})
end,
_assert_subject@1 = gleam@string:utf_codepoint(
Number
),
{ok, Codepoint} = case _assert_subject@1 of
{ok, _} -> _assert_subject@1;
_assert_fail@1 ->
erlang:error(#{gleam_error => let_assert,
message => <<"Assertion pattern match failed"/utf8>>,
value => _assert_fail@1,
module => <<"jasper"/utf8>>,
function => <<"value_parser"/utf8>>,
line => 62})
end,
gleam_stdlib:utf_codepoint_list_to_string(
[Codepoint]
)
end
)]
)
)
end,
Str = begin
_pipe@1 = pears@combinators:none_of([<<"\""/utf8>>]),
_pipe@2 = pears@combinators:alt(_pipe@1, Escape),
_pipe@3 = pears@combinators:many0(_pipe@2),
_pipe@4 = pears@combinators:map(_pipe@3, fun gleam@string:concat/1),
pears@combinators:between(
_pipe@4,
pears@combinators:just(<<"\""/utf8>>),
pears@combinators:just(<<"\""/utf8>>)
)
end,
Value@1 = pears@combinators:lazy(fun value_parser/0),
Num = begin
_pipe@5 = pears@combinators:maybe(pears@combinators:just(<<"-"/utf8>>)),
_pipe@7 = pears@combinators:pair(
_pipe@5,
begin
_pipe@6 = pears@combinators:alt(
pears@combinators:to(
pears@combinators:just(<<"0"/utf8>>),
[<<"0"/utf8>>]
),
pears@combinators:recognize(
pears@combinators:pair(
pears@combinators:one_of(
[<<"1"/utf8>>,
<<"2"/utf8>>,
<<"3"/utf8>>,
<<"4"/utf8>>,
<<"5"/utf8>>,
<<"6"/utf8>>,
<<"7"/utf8>>,
<<"8"/utf8>>,
<<"9"/utf8>>]
),
pears@combinators:many0(pears@chars:digit())
)
)
),
pears@combinators:map(_pipe@6, fun gleam@string:concat/1)
end
),
_pipe@10 = pears@combinators:pair(
_pipe@7,
pears@combinators:maybe(
begin
_pipe@8 = pears@combinators:just(<<"."/utf8>>),
_pipe@9 = pears@combinators:right(
_pipe@8,
pears@combinators:many1(pears@chars:digit())
),
pears@combinators:map(_pipe@9, fun gleam@string:concat/1)
end
)
),
_pipe@14 = pears@combinators:pair(
_pipe@10,
begin
_pipe@13 = pears@combinators:recognize(
pears@combinators:maybe(
begin
_pipe@11 = pears@combinators:alt(
pears@combinators:just(<<"e"/utf8>>),
pears@combinators:just(<<"E"/utf8>>)
),
_pipe@12 = pears@combinators:pair(
_pipe@11,
pears@combinators:maybe(
pears@combinators:one_of(
[<<"+"/utf8>>, <<"-"/utf8>>]
)
)
),
pears@combinators:pair(
_pipe@12,
pears@combinators:many1(pears@chars:digit())
)
end
)
),
pears@combinators:map(_pipe@13, fun gleam@string:concat/1)
end
),
pears@combinators:map(_pipe@14, fun(P) -> case P of
{{{Neg, Ns}, Ds}, Ex} ->
_pipe@15 = (<<<<<<<<(gleam@option:unwrap(
Neg,
<<""/utf8>>
))/binary,
Ns/binary>>/binary,
"."/utf8>>/binary,
(gleam@option:unwrap(Ds, <<"0"/utf8>>))/binary>>/binary,
Ex/binary>>),
_pipe@16 = gleam@float:parse(_pipe@15),
_pipe@17 = gleam@result:unwrap(_pipe@16, case Neg of
{some, _} ->
-1.7976931348623158e308;
none ->
1.7976931348623158e308
end),
{number, _pipe@17}
end end)
end,
Bool = pears@combinators:alt(
pears@combinators:to(
pears@chars:string(<<"true"/utf8>>),
{boolean, true}
),
pears@combinators:to(
pears@chars:string(<<"false"/utf8>>),
{boolean, false}
)
),
Null = pears@combinators:to(pears@chars:string(<<"null"/utf8>>), null),
Array = begin
_pipe@18 = pears@combinators:sep_by0(Value@1, Symbol(<<","/utf8>>)),
_pipe@19 = pears@combinators:between(
_pipe@18,
Symbol(<<"["/utf8>>),
Symbol(<<"]"/utf8>>)
),
pears@combinators:map(_pipe@19, fun(Field@0) -> {array, Field@0} end)
end,
Obj = begin
_pipe@20 = Str,
_pipe@21 = pears@combinators:left(_pipe@20, Symbol(<<":"/utf8>>)),
_pipe@22 = pears@combinators:pair(_pipe@21, Value@1),
_pipe@23 = pears@combinators:sep_by0(_pipe@22, Symbol(<<","/utf8>>)),
_pipe@24 = pears@combinators:map(_pipe@23, fun maps:from_list/1),
_pipe@25 = pears@combinators:between(
_pipe@24,
Symbol(<<"{"/utf8>>),
Symbol(<<"}"/utf8>>)
),
pears@combinators:map(_pipe@25, fun(Field@0) -> {object, Field@0} end)
end,
_pipe@26 = pears@combinators:choice(
[Num,
Bool,
Null,
pears@combinators:map(Str, fun(Field@0) -> {string, Field@0} end),
Array,
Obj]
),
Padded(_pipe@26).
-spec json_parser() -> fun((pears@input:input(binary())) -> {ok,
pears:parsed(binary(), json_value())} |
{error, pears:parse_error(binary())}).
json_parser() ->
_pipe = value_parser(),
pears@combinators:between(_pipe, whitespace0(), pears@combinators:eof()).
-spec parse_json(binary()) -> {ok, json_value()} | {error, json_parse_error()}.
parse_json(Value) ->
case (json_parser())(pears@chars:input(Value)) of
{ok, {parsed, _, J}} ->
{ok, J};
{error, E} ->
{error, case E of
{unexpected_token, _, _, F} ->
{unexpected_token, F};
{unexpected_end_of_input, _, _} ->
unexpected_end_of_input
end}
end.
-spec query_json(json_value(), json_query()) -> {ok, json_value()} |
{error, json_query_error()}.
query_json(Json, Query) ->
case Query of
root ->
{ok, Json};
{key, Q, K} ->
case query_json(Json, Q) of
{ok, {object, O} = J} ->
_pipe = gleam@dict:get(O, K),
gleam@result:replace_error(
_pipe,
{missing_object_key, J, K}
);
{ok, J@1} ->
{error, {unexpected_type, J@1}};
X ->
X
end;
{index, Q@1, I} ->
case query_json(Json, Q@1) of
{ok, {array, A} = J@2} ->
_pipe@1 = gleam@list:at(A, I),
gleam@result:replace_error(
_pipe@1,
{index_out_of_bounds, J@2, I}
);
{ok, J@3} ->
{error, {unexpected_type, J@3}};
X@1 ->
X@1
end
end.