Packages

A JSON parser that decodes JSON into a flat (non recursive) data structure.

Current section

Files

Jump to
julienne src julienne.erl
Raw

src/julienne.erl

-module(julienne).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/julienne.gleam").
-export([parse_bits/1, parse/1]).
-export_type([term_/0, sign/0, stack/0, reason/0]).
-type term_() :: {boolean, boolean()} |
null |
{string, binary()} |
{integer, integer()} |
{number, sign(), integer(), {integer(), integer()}, integer()} |
array |
object |
{field, binary()}.
-type sign() :: positive | negative.
-type stack() :: array_item | object_field.
-type reason() :: unexpected_end |
{unexpected_token, bitstring()} |
missing_digits |
{invalid_string, bitstring()}.
-file("src/julienne.gleam", 133).
-spec string(bitstring(), gleam@bytes_tree:bytes_tree()) -> {ok,
{binary(), bitstring()}} |
{error, reason()}.
string(Buffer, Acc) ->
case Buffer of
<<"\""/utf8, Rest/bitstring>> ->
Bytes = erlang:list_to_bitstring(Acc),
case gleam@bit_array:to_string(Bytes) of
{ok, Value} ->
{ok, {Value, Rest}};
{error, nil} ->
{error, {invalid_string, Bytes}}
end;
<<"\\\""/utf8, Rest@1/bitstring>> ->
string(Rest@1, gleam@bytes_tree:append(Acc, <<"\""/utf8>>));
<<"\\\\"/utf8, Rest@2/bitstring>> ->
string(Rest@2, gleam@bytes_tree:append(Acc, <<"\\"/utf8>>));
<<"\\/"/utf8, Rest@3/bitstring>> ->
string(Rest@3, gleam@bytes_tree:append(Acc, <<"/"/utf8>>));
<<"\\b"/utf8, Rest@4/bitstring>> ->
string(Rest@4, gleam@bytes_tree:append(Acc, <<8>>));
<<"\\f"/utf8, Rest@5/bitstring>> ->
string(Rest@5, gleam@bytes_tree:append(Acc, <<"\f"/utf8>>));
<<"\\n"/utf8, Rest@6/bitstring>> ->
string(Rest@6, gleam@bytes_tree:append(Acc, <<"\n"/utf8>>));
<<"\\r"/utf8, Rest@7/bitstring>> ->
string(Rest@7, gleam@bytes_tree:append(Acc, <<"\r"/utf8>>));
<<"\\t"/utf8, Rest@8/bitstring>> ->
string(Rest@8, gleam@bytes_tree:append(Acc, <<"\t"/utf8>>));
<<"\\u"/utf8, _/bitstring>> ->
{error, {unexpected_token, Buffer}};
<<"\\"/utf8, _/bitstring>> ->
{error, {unexpected_token, Buffer}};
<<B, Rest@9/bitstring>> ->
string(Rest@9, gleam@bytes_tree:append(Acc, <<B>>));
<<>> ->
{error, unexpected_end};
_ ->
{error, {unexpected_token, Buffer}}
end.
-file("src/julienne.gleam", 213).
-spec digits(bitstring(), integer(), integer()) -> {integer(),
integer(),
bitstring()}.
digits(Buffer, N, Size) ->
case Buffer of
<<"1"/utf8, Rest/bitstring>> ->
digits(Rest, (N * 10) + 1, Size + 1);
<<"2"/utf8, Rest@1/bitstring>> ->
digits(Rest@1, (N * 10) + 2, Size + 1);
<<"3"/utf8, Rest@2/bitstring>> ->
digits(Rest@2, (N * 10) + 3, Size + 1);
<<"4"/utf8, Rest@3/bitstring>> ->
digits(Rest@3, (N * 10) + 4, Size + 1);
<<"5"/utf8, Rest@4/bitstring>> ->
digits(Rest@4, (N * 10) + 5, Size + 1);
<<"6"/utf8, Rest@5/bitstring>> ->
digits(Rest@5, (N * 10) + 6, Size + 1);
<<"7"/utf8, Rest@6/bitstring>> ->
digits(Rest@6, (N * 10) + 7, Size + 1);
<<"8"/utf8, Rest@7/bitstring>> ->
digits(Rest@7, (N * 10) + 8, Size + 1);
<<"9"/utf8, Rest@8/bitstring>> ->
digits(Rest@8, (N * 10) + 9, Size + 1);
<<"0"/utf8, Rest@9/bitstring>> ->
digits(Rest@9, (N * 10) + 0, Size + 1);
_ ->
{N, Size, Buffer}
end.
-file("src/julienne.gleam", 121).
-spec separator(bitstring(), list(stack()), list({term_(), integer()})) -> {ok,
list({term_(), integer()})} |
{error, reason()}.
separator(Buffer, Stack, Acc) ->
case Buffer of
<<"\r"/utf8, Rest/bitstring>> ->
separator(Rest, Stack, Acc);
<<"\n"/utf8, Rest/bitstring>> ->
separator(Rest, Stack, Acc);
<<" "/utf8, Rest/bitstring>> ->
separator(Rest, Stack, Acc);
<<"\t"/utf8, Rest/bitstring>> ->
separator(Rest, Stack, Acc);
<<":"/utf8, Rest@1/bitstring>> ->
value(Rest@1, Stack, Acc);
<<>> ->
{error, unexpected_end};
_ ->
{error, {unexpected_token, Buffer}}
end.
-file("src/julienne.gleam", 44).
-spec value(bitstring(), list(stack()), list({term_(), integer()})) -> {ok,
list({term_(), integer()})} |
{error, reason()}.
value(Buffer, Stack, Acc) ->
Depth = erlang:length(Stack),
case {Buffer, Stack} of
{<<"\r"/utf8, Rest/bitstring>>, _} ->
value(Rest, Stack, Acc);
{<<"\n"/utf8, Rest/bitstring>>, _} ->
value(Rest, Stack, Acc);
{<<" "/utf8, Rest/bitstring>>, _} ->
value(Rest, Stack, Acc);
{<<"\t"/utf8, Rest/bitstring>>, _} ->
value(Rest, Stack, Acc);
{<<"true"/utf8, Rest@1/bitstring>>, _} ->
continue(Rest@1, Stack, [{{boolean, true}, Depth} | Acc]);
{<<"false"/utf8, Rest@2/bitstring>>, _} ->
continue(Rest@2, Stack, [{{boolean, false}, Depth} | Acc]);
{<<"null"/utf8, Rest@3/bitstring>>, _} ->
continue(Rest@3, Stack, [{null, Depth} | Acc]);
{<<"["/utf8, Rest@4/bitstring>>, _} ->
value(Rest@4, [array_item | Stack], [{array, Depth} | Acc]);
{<<"{"/utf8, Rest@5/bitstring>>, _} ->
Acc@1 = [{object, Depth} | Acc],
Stack@1 = [object_field | Stack],
key(Rest@5, Stack@1, Acc@1);
{<<"]"/utf8, Rest@6/bitstring>>, [array_item | Stack@2]} ->
continue(Rest@6, Stack@2, Acc);
{<<"\""/utf8, Rest@7/bitstring>>, _} ->
gleam@result:'try'(
string(Rest@7, gleam@bytes_tree:new()),
fun(_use0) ->
{Extracted, Rest@8} = _use0,
continue(
Rest@8,
Stack,
[{{string, Extracted}, Depth} | Acc]
)
end
);
{<<"0."/utf8, Rest@9/bitstring>>, _} ->
start_decimal(positive, 0, Rest@9, Stack, Acc);
{<<"-0."/utf8, Rest@10/bitstring>>, _} ->
start_decimal(negative, 0, Rest@10, Stack, Acc);
{<<"0e"/utf8, Rest@11/bitstring>>, _} ->
start_exponent(positive, 0, {0, 0}, Rest@11, Stack, Acc);
{<<"0E"/utf8, Rest@11/bitstring>>, _} ->
start_exponent(positive, 0, {0, 0}, Rest@11, Stack, Acc);
{<<"-0e"/utf8, Rest@12/bitstring>>, _} ->
start_exponent(negative, 0, {0, 0}, Rest@12, Stack, Acc);
{<<"-0E"/utf8, Rest@12/bitstring>>, _} ->
start_exponent(negative, 0, {0, 0}, Rest@12, Stack, Acc);
{<<"0"/utf8, Rest@13/bitstring>>, _} ->
continue(Rest@13, Stack, [{{integer, 0}, Depth} | Acc]);
{<<"-0"/utf8, Rest@13/bitstring>>, _} ->
continue(Rest@13, Stack, [{{integer, 0}, Depth} | Acc]);
{<<"1"/utf8, Rest@14/bitstring>>, _} ->
start_number(positive, 1, Rest@14, Stack, Acc);
{<<"2"/utf8, Rest@15/bitstring>>, _} ->
start_number(positive, 2, Rest@15, Stack, Acc);
{<<"3"/utf8, Rest@16/bitstring>>, _} ->
start_number(positive, 3, Rest@16, Stack, Acc);
{<<"4"/utf8, Rest@17/bitstring>>, _} ->
start_number(positive, 4, Rest@17, Stack, Acc);
{<<"5"/utf8, Rest@18/bitstring>>, _} ->
start_number(positive, 5, Rest@18, Stack, Acc);
{<<"6"/utf8, Rest@19/bitstring>>, _} ->
start_number(positive, 6, Rest@19, Stack, Acc);
{<<"7"/utf8, Rest@20/bitstring>>, _} ->
start_number(positive, 7, Rest@20, Stack, Acc);
{<<"8"/utf8, Rest@21/bitstring>>, _} ->
start_number(positive, 8, Rest@21, Stack, Acc);
{<<"9"/utf8, Rest@22/bitstring>>, _} ->
start_number(positive, 9, Rest@22, Stack, Acc);
{<<"-1"/utf8, Rest@23/bitstring>>, _} ->
start_number(negative, 1, Rest@23, Stack, Acc);
{<<"-2"/utf8, Rest@24/bitstring>>, _} ->
start_number(negative, 2, Rest@24, Stack, Acc);
{<<"-3"/utf8, Rest@25/bitstring>>, _} ->
start_number(negative, 3, Rest@25, Stack, Acc);
{<<"-4"/utf8, Rest@26/bitstring>>, _} ->
start_number(negative, 4, Rest@26, Stack, Acc);
{<<"-5"/utf8, Rest@27/bitstring>>, _} ->
start_number(negative, 5, Rest@27, Stack, Acc);
{<<"-6"/utf8, Rest@28/bitstring>>, _} ->
start_number(negative, 6, Rest@28, Stack, Acc);
{<<"-7"/utf8, Rest@29/bitstring>>, _} ->
start_number(negative, 7, Rest@29, Stack, Acc);
{<<"-8"/utf8, Rest@30/bitstring>>, _} ->
start_number(negative, 8, Rest@30, Stack, Acc);
{<<"-9"/utf8, Rest@31/bitstring>>, _} ->
start_number(negative, 9, Rest@31, Stack, Acc);
{<<>>, _} ->
{error, unexpected_end};
{_, _} ->
{error, {unexpected_token, Buffer}}
end.
-file("src/julienne.gleam", 159).
-spec start_number(
sign(),
integer(),
bitstring(),
list(stack()),
list({term_(), integer()})
) -> {ok, list({term_(), integer()})} | {error, reason()}.
start_number(Sign, First, Rest, Stack, Acc) ->
{N, _, Rest@1} = digits(Rest, First, 1),
case Rest@1 of
<<"."/utf8, Rest@2/bitstring>> ->
start_decimal(Sign, N, Rest@2, Stack, Acc);
<<"e"/utf8, Rest@3/bitstring>> ->
start_exponent(Sign, N, {0, 0}, Rest@3, Stack, Acc);
<<"E"/utf8, Rest@3/bitstring>> ->
start_exponent(Sign, N, {0, 0}, Rest@3, Stack, Acc);
_ ->
N@1 = case Sign of
positive ->
N;
negative ->
- N
end,
continue(
Rest@1,
Stack,
[{{integer, N@1}, erlang:length(Stack)} | Acc]
)
end.
-file("src/julienne.gleam", 176).
-spec start_decimal(
sign(),
integer(),
bitstring(),
list(stack()),
list({term_(), integer()})
) -> {ok, list({term_(), integer()})} | {error, reason()}.
start_decimal(Sign, Integer, Rest, Stack, Acc) ->
{Decimal, Size, Rest@1} = digits(Rest, 0, 0),
case Size of
0 ->
{error, missing_digits};
_ ->
case Rest@1 of
<<"e"/utf8, Rest@2/bitstring>> ->
start_exponent(
Sign,
Integer,
{Decimal, Size},
Rest@2,
Stack,
Acc
);
<<"E"/utf8, Rest@2/bitstring>> ->
start_exponent(
Sign,
Integer,
{Decimal, Size},
Rest@2,
Stack,
Acc
);
_ ->
Term = {number, Sign, Integer, {Decimal, Size}, 0},
continue(
Rest@1,
Stack,
[{Term, erlang:length(Stack)} | Acc]
)
end
end.
-file("src/julienne.gleam", 193).
-spec start_exponent(
sign(),
integer(),
{integer(), integer()},
bitstring(),
list(stack()),
list({term_(), integer()})
) -> {ok, list({term_(), integer()})} | {error, reason()}.
start_exponent(Sign, Integer, Decimal, Rest, Stack, Acc) ->
{Exp_sign, Rest@3} = case Rest of
<<"+"/utf8, Rest@1/bitstring>> ->
{positive, Rest@1};
<<"-"/utf8, Rest@2/bitstring>> ->
{negative, Rest@2};
_ ->
{positive, Rest}
end,
{Exponent, Size, Rest@4} = digits(Rest@3, 0, 0),
case Size of
0 ->
{error, missing_digits};
_ ->
Exponent@1 = case Exp_sign of
positive ->
Exponent;
negative ->
- Exponent
end,
Term = {number, Sign, Integer, Decimal, Exponent@1},
continue(Rest@4, Stack, [{Term, erlang:length(Stack)} | Acc])
end.
-file("src/julienne.gleam", 229).
-spec continue(bitstring(), list(stack()), list({term_(), integer()})) -> {ok,
list({term_(), integer()})} |
{error, reason()}.
continue(Buffer, Stack, Acc) ->
case {Buffer, Stack} of
{<<"\r"/utf8, Rest/bitstring>>, _} ->
continue(Rest, Stack, Acc);
{<<"\n"/utf8, Rest/bitstring>>, _} ->
continue(Rest, Stack, Acc);
{<<" "/utf8, Rest/bitstring>>, _} ->
continue(Rest, Stack, Acc);
{<<"\t"/utf8, Rest/bitstring>>, _} ->
continue(Rest, Stack, Acc);
{_, []} ->
{ok, lists:reverse(Acc)};
{<<"]"/utf8, Rest@1/bitstring>>, [array_item | Stack@1]} ->
continue(Rest@1, Stack@1, Acc);
{<<","/utf8, Rest@2/bitstring>>, [array_item | _]} ->
value(Rest@2, Stack, Acc);
{<<"}"/utf8, Rest@3/bitstring>>, [object_field | Stack@2]} ->
continue(Rest@3, Stack@2, Acc);
{<<","/utf8, Rest@4/bitstring>>, [object_field | _]} ->
key(Rest@4, Stack, Acc);
{<<>>, _} ->
{error, unexpected_end};
{_, _} ->
{error, {unexpected_token, Buffer}}
end.
-file("src/julienne.gleam", 101).
-spec key(bitstring(), list(stack()), list({term_(), integer()})) -> {ok,
list({term_(), integer()})} |
{error, reason()}.
key(Buffer, Stack, Acc) ->
Depth = erlang:length(Stack),
case Buffer of
<<"\r"/utf8, Rest/bitstring>> ->
key(Rest, Stack, Acc);
<<"\n"/utf8, Rest/bitstring>> ->
key(Rest, Stack, Acc);
<<" "/utf8, Rest/bitstring>> ->
key(Rest, Stack, Acc);
<<"\t"/utf8, Rest/bitstring>> ->
key(Rest, Stack, Acc);
<<"\""/utf8, Rest@1/bitstring>> ->
gleam@result:'try'(
string(Rest@1, gleam@bytes_tree:new()),
fun(_use0) ->
{Extracted, Rest@2} = _use0,
separator(
Rest@2,
Stack,
[{{field, Extracted}, Depth} | Acc]
)
end
);
<<"}"/utf8, Rest@3/bitstring>> ->
Stack@2 = case Stack of
[object_field | Stack@1] -> Stack@1;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"julienne"/utf8>>,
function => <<"key"/utf8>>,
line => 113,
value => _assert_fail,
start => 4056,
'end' => 4097,
pattern_start => 4067,
pattern_end => 4089})
end,
continue(Rest@3, Stack@2, Acc);
<<>> ->
{error, unexpected_end};
_ ->
{error, {unexpected_token, Buffer}}
end.
-file("src/julienne.gleam", 10).
-spec parse_bits(bitstring()) -> {ok, list({term_(), integer()})} |
{error, reason()}.
parse_bits(Buffer) ->
value(Buffer, [], []).
-file("src/julienne.gleam", 6).
-spec parse(binary()) -> {ok, list({term_(), integer()})} | {error, reason()}.
parse(Buffer) ->
parse_bits(<<Buffer/binary>>).