Current section
Files
Jump to
Current section
Files
src/parser.erl
-module(parser).
-export([parse/1]).
-include("types.hrl").
-spec(parse([json_token(), ...]) -> map() | list()).
% base case
parse(_Tokens = []) ->
#{};
parse(Tokens = [begin_object| _T ]) ->
parse(Tokens, #{});
parse(Tokens = [begin_array| _T ]) ->
{Array, _} = parse_array(Tokens, []),
Array.
% base case
parse([], Acc) ->
Acc;
% begin_object
parse(Tokens = [begin_object| _T ], Acc) ->
{Object, T} = parse_object(Tokens, #{}),
Acc1 = maps:merge(Acc, Object),
parse(T, Acc1).
% empty object case
parse_object([begin_object, end_object | T ], #{}) ->
{#{}, T};
% start of the object
parse_object([begin_object| T ], #{}) ->
{Key, T1} = parse_key(T),
{_Colon, T2} = parse_colon(T1),
{Value, T3} = parse_value(T2),
Acc = #{Key => Value},
parse_object(T3, Acc);
% end of the object
parse_object([end_object| T ], Acc) ->
{Acc, T};
% @todo remove duplication in case of comma dn beginning of object
%next element in the object (delimited with comma)
parse_object([comma| T ], Acc) ->
{Key, T1} = parse_key(T),
{_Colon, T2} = parse_colon(T1),
{Value, T3} = parse_value(T2),
Acc1 = maps:merge(Acc,#{Key => Value}),
parse_object(T3, Acc1).
% start of the array
parse_array([begin_array | T], []) ->
parse_array(T, []);
% end of the array
parse_array([end_array | T], Acc) ->
{Acc, T};
% if comma found go to the next value
parse_array([comma | T], Acc) ->
parse_array(T,Acc);
% parsing value in the array
parse_array(Tokens, Acc) ->
{Value, T} = parse_value(Tokens),
Acc1 = Acc ++ [Value],
parse_array(T, Acc1).
% find colon
parse_colon([colon | T ]) ->
{colon, T}.
%% parsing value based on its type %%
% value is string
parse_value([{string, Value} | T ]) ->
{Value, T};
% value is number
parse_value([{number, Value} | T ]) ->
{parse_number(Value), T};
% value is literal name
parse_value([Value | T ]) when (Value =:= false) orelse
(Value =:= true) orelse
(Value =:= null) ->
{Value, T};
% value is array
parse_value(Tokens = [begin_array | _T ]) ->
{Array, T} = parse_array(Tokens, []),
{Array, T};
% value is object
parse_value(Tokens = [begin_object | _T ]) ->
{Value, T} = parse_object(Tokens, #{}),
{Value, T}.
% parse key. keys can be binary strings only
parse_key([{string, Key } | T ]) ->
{Key, T}.
parse_number(Value) ->
case length(binary:matches(Value, [<<".">>])) of
0 -> binary_to_integer(Value); % integer
1 -> binary_to_float(Value); % float
_ -> throw({"number is not invalid", Value})
end.