Browse Source

Support decodings proplists formatted object (format option is added)

Takeru Ohta 10 years ago
parent
commit
0234da7d17
4 changed files with 186 additions and 150 deletions
  1. 28 12
      src/jsone.erl
  2. 151 132
      src/jsone_decode.erl
  3. 2 3
      src/jsone_encode.erl
  4. 5 3
      test/jsone_decode_tests.erl

+ 28 - 12
src/jsone.erl

@@ -30,7 +30,8 @@
 %% Exported API
 %%--------------------------------------------------------------------------------
 -export([
-         decode/1, try_decode/1,
+         decode/1, decode/2,
+         try_decode/1, try_decode/2,
          encode/1, encode/2,
          try_encode/1, try_encode/2
         ]).
@@ -45,7 +46,8 @@
               json_object_key/0,
               json_boolean/0,
 
-              encode_option/0
+              encode_option/0,
+              decode_option/0
              ]).
 
 %%--------------------------------------------------------------------------------
@@ -65,49 +67,63 @@
 -type encode_option() :: native_utf8.
 %% native_utf8: Encodes UTF-8 characters as a human-readable(non-escaped) string
 
+-type decode_option() :: {format, eep18 | proplist}.
+%% TODO: doc
+
 -define(DEFAULT_ENCODE_OPTIONS, []).
+-define(DEFAULT_DECODE_OPTIONS, []).
 
 %%--------------------------------------------------------------------------------
 %% Exported Functions
 %%--------------------------------------------------------------------------------
+%% @equiv decode(Json, [])
+-spec decode(binary()) -> json_value().
+decode(Json) ->
+    decode(Json, ?DEFAULT_DECODE_OPTIONS).
+
 %% @doc Decodes an erlang term from json text (a utf8 encoded binary)
 %%
 %% Raises an error exception if input is not valid json
 %%
 %% ```
-%% > jsone:decode(<<"1">>).
+%% > jsone:decode(<<"1">>, []).
 %% 1
 %%
-%% > jsone:decode(<<"wrong json">>).
+%% > jsone:decode(<<"wrong json">>, []).
 %% ** exception error: bad argument
 %%     in function  jsone_decode:number_integer_part/4
 %%        called as jsone_decode:number_integer_part(<<"wrong json">>,1,[],<<>>)
 %%     in call from jsone:decode/1 (src/jsone.erl, line 71)
 %% '''
--spec decode(binary()) -> json_value().
-decode(Json) ->
+-spec decode(binary(), [decode_option()]) -> json_value().
+decode(Json, Options) ->
     try
-        {ok, Value, _} = try_decode(Json),
+        {ok, Value, _} = try_decode(Json, Options),
         Value
     catch
         error:{badmatch, {error, {Reason, [StackItem]}}} ->
             erlang:raise(error, Reason, [StackItem | erlang:get_stacktrace()])
     end.
 
+%% @equiv try_decode(Json, [])
+-spec try_decode(binary()) -> {ok, json_value(), Remainings::binary()} | {error, {Reason::term(), [erlang:stack_item()]}}.
+try_decode(Json) ->
+    try_decode(Json, ?DEFAULT_DECODE_OPTIONS).
+
 %% @doc Decodes an erlang term from json text (a utf8 encoded binary)
 %%
 %% ```
-%% > jsone:try_decode(<<"[1,2,3] \"next value\"">>).
+%% > jsone:try_decode(<<"[1,2,3] \"next value\"">>, []).
 %% {ok,[1,2,3],<<" \"next value\"">>}
 %%
-%% > jsone:try_decode(<<"wrong json">>).
+%% > jsone:try_decode(<<"wrong json">>, []).
 %% {error,{badarg,[{jsone_decode,number_integer_part,
 %%                               [<<"wrong json">>,1,[],<<>>],
 %%                               [{line,208}]}]}}
 %% '''
--spec try_decode(binary()) -> {ok, json_value(), Remainings::binary()} | {error, {Reason::term(), [erlang:stack_item()]}}.
-try_decode(Json) ->
-    jsone_decode:decode(Json).
+-spec try_decode(binary(), [decode_option()]) -> {ok, json_value(), Remainings::binary()} | {error, {Reason::term(), [erlang:stack_item()]}}.
+try_decode(Json, Options) ->
+    jsone_decode:decode(Json, Options).
 
 %% @equiv encode(JsonValue, [])
 -spec encode(json_value()) -> binary().

+ 151 - 132
src/jsone_decode.erl

@@ -30,10 +30,10 @@
 %%--------------------------------------------------------------------------------
 %% Exported API
 %%--------------------------------------------------------------------------------
--export([decode/1]).
+-export([decode/1, decode/2]).
 
 %%--------------------------------------------------------------------------------
-%% Macros & Types
+%% Macros & Records & Types
 %%--------------------------------------------------------------------------------
 -define(ERROR(Function, Args), {error, {badarg, [{?MODULE, Function, Args, [{line, ?LINE}]}]}}).
 
@@ -51,110 +51,120 @@
 
 -type decode_result() :: {ok, jsone:json_value(), Rest::binary()} | {error, {Reason::term(), [erlang:stack_item()]}}.
 
+-record(decode_opt_v1, { format=eep18 :: eep18 | proplist}).
+-define(OPT, #decode_opt_v1).
+-type opt() :: #decode_opt_v1{}.
+
 %%--------------------------------------------------------------------------------
 %% Exported Functions
 %%--------------------------------------------------------------------------------
-%% @doc Decodes an erlang term from json text (a utf8 encoded binary)
 -spec decode(binary()) -> decode_result().
-decode(<<Json/binary>>) ->
-    whitespace(Json, value, [], <<"">>).
+decode(Json) ->
+    decode(Json, []).
+
+-spec decode(binary(), [jsone:decode_option()]) -> decode_result().
+decode(<<Json/binary>>, Options) ->
+    Opt = parse_options(Options),
+    whitespace(Json, value, [], <<"">>, Opt).
 
 %%--------------------------------------------------------------------------------
 %% Internal Functions
 %%--------------------------------------------------------------------------------
--spec next(binary(), jsone:json_value(), [next()], binary()) -> decode_result().
-next(<<Bin/binary>>, Value, [], _Buf) ->
+-spec next(binary(), jsone:json_value(), [next()], binary(), opt()) -> decode_result().
+next(<<Bin/binary>>, Value, [], _Buf, _Opt) ->
     {ok, Value, Bin};
-next(<<Bin/binary>>, Value, [Next | Nexts], Buf) ->
+next(<<Bin/binary>>, Value, [Next | Nexts], Buf, Opt) ->
     case Next of
-        {array_next, Values}        -> whitespace(Bin, {array_next, [Value | Values]}, Nexts, Buf);
-        {object_value, Members}     -> whitespace(Bin, {object_value, Value, Members}, Nexts, Buf);
-        {object_next, Key, Members} -> whitespace(Bin, {object_next, [{Key, Value} | Members]}, Nexts, Buf)
+        {array_next, Values}        -> whitespace(Bin, {array_next, [Value | Values]}, Nexts, Buf, Opt);
+        {object_value, Members}     -> whitespace(Bin, {object_value, Value, Members}, Nexts, Buf, Opt);
+        {object_next, Key, Members} -> whitespace(Bin, {object_next, [{Key, Value} | Members]}, Nexts, Buf, Opt)
     end.
 
--spec whitespace(binary(), whitespace_next(), [next()], binary()) -> decode_result().
-whitespace(<<$  , Bin/binary>>, Next, Nexts, Buf) -> whitespace(Bin, Next, Nexts, Buf);
-whitespace(<<$\t, Bin/binary>>, Next, Nexts, Buf) -> whitespace(Bin, Next, Nexts, Buf);
-whitespace(<<$\r, Bin/binary>>, Next, Nexts, Buf) -> whitespace(Bin, Next, Nexts, Buf);
-whitespace(<<$\n, Bin/binary>>, Next, Nexts, Buf) -> whitespace(Bin, Next, Nexts, Buf);
-whitespace(<<Bin/binary>>,      Next, Nexts, Buf) ->
+-spec whitespace(binary(), whitespace_next(), [next()], binary(), opt()) -> decode_result().
+whitespace(<<$  , Bin/binary>>, Next, Nexts, Buf, Opt) -> whitespace(Bin, Next, Nexts, Buf, Opt);
+whitespace(<<$\t, Bin/binary>>, Next, Nexts, Buf, Opt) -> whitespace(Bin, Next, Nexts, Buf, Opt);
+whitespace(<<$\r, Bin/binary>>, Next, Nexts, Buf, Opt) -> whitespace(Bin, Next, Nexts, Buf, Opt);
+whitespace(<<$\n, Bin/binary>>, Next, Nexts, Buf, Opt) -> whitespace(Bin, Next, Nexts, Buf, Opt);
+whitespace(<<Bin/binary>>,      Next, Nexts, Buf, Opt) ->
     case Next of
-        value  -> value(Bin, Nexts, Buf);
-        array  -> array(Bin, Nexts, Buf);
-        object -> object(Bin, Nexts, Buf);
-        {object_key, Members}        -> object_key(Bin, Members, Nexts, Buf);
-        {array_next, Values}         -> array_next(Bin, Values, Nexts, Buf);
-        {object_value, Key, Members} -> object_value(Bin, Key, Members, Nexts, Buf);
-        {object_next, Members}       -> object_next(Bin, Members, Nexts, Buf)
+        value  -> value(Bin, Nexts, Buf, Opt);
+        array  -> array(Bin, Nexts, Buf, Opt);
+        object -> object(Bin, Nexts, Buf, Opt);
+        {object_key, Members}        -> object_key(Bin, Members, Nexts, Buf, Opt);
+        {array_next, Values}         -> array_next(Bin, Values, Nexts, Buf, Opt);
+        {object_value, Key, Members} -> object_value(Bin, Key, Members, Nexts, Buf, Opt);
+        {object_next, Members}       -> object_next(Bin, Members, Nexts, Buf, Opt)
     end.
 
--spec value(binary(), [next()], binary()) -> decode_result().
-value(<<"false", Bin/binary>>, Nexts, Buf) -> next(Bin, false, Nexts, Buf);
-value(<<"true", Bin/binary>>, Nexts, Buf)  -> next(Bin, true, Nexts, Buf);
-value(<<"null", Bin/binary>>, Nexts, Buf)  -> next(Bin, null, Nexts, Buf);
-value(<<$[, Bin/binary>>, Nexts, Buf)      -> whitespace(Bin, array, Nexts, Buf);
-value(<<${, Bin/binary>>, Nexts, Buf)      -> whitespace(Bin, object, Nexts, Buf);
-value(<<$", Bin/binary>>, Nexts, Buf)      -> string(Bin, byte_size(Buf), Nexts, Buf);
-value(<<Bin/binary>>, Nexts, Buf)          -> number(Bin, Nexts, Buf).
+-spec value(binary(), [next()], binary(), opt()) -> decode_result().
+value(<<"false", Bin/binary>>, Nexts, Buf, Opt) -> next(Bin, false, Nexts, Buf, Opt);
+value(<<"true", Bin/binary>>, Nexts, Buf, Opt)  -> next(Bin, true, Nexts, Buf, Opt);
+value(<<"null", Bin/binary>>, Nexts, Buf, Opt)  -> next(Bin, null, Nexts, Buf, Opt);
+value(<<$[, Bin/binary>>, Nexts, Buf, Opt)      -> whitespace(Bin, array, Nexts, Buf, Opt);
+value(<<${, Bin/binary>>, Nexts, Buf, Opt)      -> whitespace(Bin, object, Nexts, Buf, Opt);
+value(<<$", Bin/binary>>, Nexts, Buf, Opt)      -> string(Bin, byte_size(Buf), Nexts, Buf, Opt);
+value(<<Bin/binary>>, Nexts, Buf, Opt)          -> number(Bin, Nexts, Buf, Opt).
 
--spec array(binary(), [next()], binary()) -> decode_result().
-array(<<$], Bin/binary>>, Nexts, Buf) -> next(Bin, [], Nexts, Buf);
-array(<<Bin/binary>>, Nexts, Buf)     -> value(Bin, [{array_next, []} | Nexts], Buf).
+-spec array(binary(), [next()], binary(), opt()) -> decode_result().
+array(<<$], Bin/binary>>, Nexts, Buf, Opt) -> next(Bin, [], Nexts, Buf, Opt);
+array(<<Bin/binary>>, Nexts, Buf, Opt)     -> value(Bin, [{array_next, []} | Nexts], Buf, Opt).
 
--spec array_next(binary(), [jsone:json_value()], [next()], binary()) -> decode_result().
-array_next(<<$], Bin/binary>>, Values, Nexts, Buf) -> next(Bin, lists:reverse(Values), Nexts, Buf);
-array_next(<<$,, Bin/binary>>, Values, Nexts, Buf) -> whitespace(Bin, value, [{array_next, Values} | Nexts], Buf);
-array_next(Bin,                Values, Nexts, Buf) -> ?ERROR(array_next, [Bin, Values, Nexts, Buf]).
+-spec array_next(binary(), [jsone:json_value()], [next()], binary(), opt()) -> decode_result().
+array_next(<<$], Bin/binary>>, Values, Nexts, Buf, Opt) -> next(Bin, lists:reverse(Values), Nexts, Buf, Opt);
+array_next(<<$,, Bin/binary>>, Values, Nexts, Buf, Opt) -> whitespace(Bin, value, [{array_next, Values} | Nexts], Buf, Opt);
+array_next(Bin,                Values, Nexts, Buf, Opt) -> ?ERROR(array_next, [Bin, Values, Nexts, Buf, Opt]).
 
--spec object(binary(), [next()], binary()) -> decode_result().
-object(<<$}, Bin/binary>>, Nexts, Buf) -> next(Bin, {[]}, Nexts, Buf);
-object(<<Bin/binary>>, Nexts, Buf)     -> object_key(Bin, [], Nexts, Buf).
+-spec object(binary(), [next()], binary(), opt()) -> decode_result().
+object(<<$}, Bin/binary>>, Nexts, Buf, Opt = ?OPT{format = proplist}) -> next(Bin, [{}], Nexts, Buf, Opt);
+object(<<$}, Bin/binary>>, Nexts, Buf, Opt) -> next(Bin, {[]}, Nexts, Buf, Opt);
+object(<<Bin/binary>>, Nexts, Buf, Opt)     -> object_key(Bin, [], Nexts, Buf, Opt).
 
--spec object_key(binary(), jsone:json_object_members(), [next()], binary()) -> decode_result().
-object_key(<<$", Bin/binary>>, Members, Nexts, Buf) -> string(Bin, byte_size(Buf), [{object_value, Members} | Nexts], Buf);
-object_key(<<Bin/binary>>, Members, Nexts, Buf)     -> ?ERROR(object_key, [Bin, Members, Nexts, Buf]).
+-spec object_key(binary(), jsone:json_object_members(), [next()], binary(), opt()) -> decode_result().
+object_key(<<$", Bin/binary>>, Members, Nexts, Buf, Opt) -> string(Bin, byte_size(Buf), [{object_value, Members} | Nexts], Buf, Opt);
+object_key(<<Bin/binary>>, Members, Nexts, Buf, Opt)     -> ?ERROR(object_key, [Bin, Members, Nexts, Buf, Opt]).
 
--spec object_value(binary(), jsone:json_string(), jsone:json_object_members(), [next()], binary()) -> decode_result().
-object_value(<<$:, Bin/binary>>, Key, Members, Nexts, Buf) -> whitespace(Bin, value, [{object_next, Key, Members} | Nexts], Buf);
-object_value(Bin,                Key, Members, Nexts, Buf) -> ?ERROR(object_value, [Bin, Key, Members, Nexts, Buf]).
+-spec object_value(binary(), jsone:json_string(), jsone:json_object_members(), [next()], binary(), opt()) -> decode_result().
+object_value(<<$:, Bin/binary>>, Key, Members, Nexts, Buf, Opt) -> whitespace(Bin, value, [{object_next, Key, Members} | Nexts], Buf, Opt);
+object_value(Bin,                Key, Members, Nexts, Buf, Opt) -> ?ERROR(object_value, [Bin, Key, Members, Nexts, Buf, Opt]).
 
--spec object_next(binary(), jsone:json_object_members(), [next()], binary()) -> decode_result().
-object_next(<<$}, Bin/binary>>, Members, Nexts, Buf) -> next(Bin, {Members}, Nexts, Buf);
-object_next(<<$,, Bin/binary>>, Members, Nexts, Buf) -> whitespace(Bin, {object_key, Members}, Nexts, Buf);
-object_next(Bin,                Members, Nexts, Buf) -> ?ERROR(object_next, [Bin, Members, Nexts, Buf]).
+-spec object_next(binary(), jsone:json_object_members(), [next()], binary(), opt()) -> decode_result().
+object_next(<<$}, Bin/binary>>, Members, Nexts, Buf, Opt = ?OPT{format = proplist}) -> next(Bin, Members, Nexts, Buf, Opt);
+object_next(<<$}, Bin/binary>>, Members, Nexts, Buf, Opt) -> next(Bin, {Members}, Nexts, Buf, Opt);
+object_next(<<$,, Bin/binary>>, Members, Nexts, Buf, Opt) -> whitespace(Bin, {object_key, Members}, Nexts, Buf, Opt);
+object_next(Bin,                Members, Nexts, Buf, Opt) -> ?ERROR(object_next, [Bin, Members, Nexts, Buf, Opt]).
 
--spec string(binary(), non_neg_integer(), [next()], binary()) -> decode_result().
-string(<<Bin/binary>>, Start, Nexts, Buf) ->
-    string(Bin, Bin, Start, Nexts, Buf).
+-spec string(binary(), non_neg_integer(), [next()], binary(), opt()) -> decode_result().
+string(<<Bin/binary>>, Start, Nexts, Buf, Opt) ->
+    string(Bin, Bin, Start, Nexts, Buf, Opt).
 
--spec string(binary(), binary(), non_neg_integer(), [next()], binary()) -> decode_result().
-string(<<$", Bin/binary>>, Base, Start, Nexts, Buf) ->
+-spec string(binary(), binary(), non_neg_integer(), [next()], binary(), opt()) -> decode_result().
+string(<<$", Bin/binary>>, Base, Start, Nexts, Buf, Opt) ->
     Prefix = binary:part(Base, 0, byte_size(Base) - byte_size(Bin) - 1),
     case Start =:= byte_size(Buf) of
-        true  -> next(Bin, Prefix, Nexts, Buf);
+        true  -> next(Bin, Prefix, Nexts, Buf, Opt);
         false ->
             Buf2 = <<Buf/binary, Prefix/binary>>,
-            next(Bin, binary:part(Buf2, Start, byte_size(Buf2) - Start), Nexts, Buf2)
+            next(Bin, binary:part(Buf2, Start, byte_size(Buf2) - Start), Nexts, Buf2, Opt)
     end;
-string(<<$\\, B/binary>>, Base, Start, Nexts, Buf) ->
+string(<<$\\, B/binary>>, Base, Start, Nexts, Buf, Opt) ->
     Prefix = binary:part(Base, 0, byte_size(Base) - byte_size(B) - 1),
     case B of
-        <<$", Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $">>);
-        <<$/, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $/>>);
-        <<$\\,Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\\>>);
-        <<$b, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\b>>);
-        <<$f, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\f>>);
-        <<$n, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\n>>);
-        <<$r, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\r>>);
-        <<$t, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\t>>);
-        <<$u, Bin/binary>> -> unicode_string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary>>);
-        _                  -> ?ERROR(string, [<<$\\, B/binary>>, Base, Start, Nexts, Buf])
+        <<$", Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $">>, Opt);
+        <<$/, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $/>>, Opt);
+        <<$\\,Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\\>>, Opt);
+        <<$b, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\b>>, Opt);
+        <<$f, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\f>>, Opt);
+        <<$n, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\n>>, Opt);
+        <<$r, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\r>>, Opt);
+        <<$t, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\t>>, Opt);
+        <<$u, Bin/binary>> -> unicode_string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary>>, Opt);
+        _                  -> ?ERROR(string, [<<$\\, B/binary>>, Base, Start, Nexts, Buf, Opt])
     end;
-string(<<C, Bin/binary>>, Base, Start, Nexts, Buf) when 16#20 =< C ->
-    string(Bin, Base, Start, Nexts, Buf).
+string(<<C, Bin/binary>>, Base, Start, Nexts, Buf, Opt) when 16#20 =< C ->
+    string(Bin, Base, Start, Nexts, Buf, Opt).
 
--spec unicode_string(binary(), non_neg_integer(), [next()], binary()) -> decode_result().
-unicode_string(<<N:4/binary, Bin/binary>>, Start, Nexts, Buf) ->
+-spec unicode_string(binary(), non_neg_integer(), [next()], binary(), opt()) -> decode_result().
+unicode_string(<<N:4/binary, Bin/binary>>, Start, Nexts, Buf, Opt) ->
     case binary_to_integer(N, 16) of
         High when 16#D800 =< High, High =< 16#DBFF ->
             %% surrogate pair
@@ -163,18 +173,18 @@ unicode_string(<<N:4/binary, Bin/binary>>, Start, Nexts, Buf) ->
                     case binary_to_integer(N2, 16) of
                         Low when 16#DC00 =< Low, Low =< 16#DFFF ->
                             Unicode = 16#10000 + (High - 16#D800) * 16#400 + (Low - 16#DC00),
-                            string(Bin2, Start, Nexts, unicode_to_utf8(Unicode, Buf));
-                        _ -> ?ERROR(unicode_string, [<<N/binary, Bin/binary>>, Start, Nexts, Buf])
+                            string(Bin2, Start, Nexts, unicode_to_utf8(Unicode, Buf), Opt);
+                        _ -> ?ERROR(unicode_string, [<<N/binary, Bin/binary>>, Start, Nexts, Buf, Opt])
                     end;
-                _ -> ?ERROR(unicode_string, [<<N/binary, Bin/binary>>, Start, Nexts, Buf])
+                _ -> ?ERROR(unicode_string, [<<N/binary, Bin/binary>>, Start, Nexts, Buf, Opt])
             end;
         Unicode when 16#DC00 =< Unicode, Unicode =< 16#DFFF ->  % second part of surrogate pair (without first part)
-            ?ERROR(unicode_string, [<<N/binary, Bin/binary>>, Start, Nexts, Buf]);
-        Unicode -> 
-            string(Bin, Start, Nexts, unicode_to_utf8(Unicode, Buf))
+            ?ERROR(unicode_string, [<<N/binary, Bin/binary>>, Start, Nexts, Buf, Opt]);
+        Unicode ->
+            string(Bin, Start, Nexts, unicode_to_utf8(Unicode, Buf), Opt)
     end;
-unicode_string(Bin, Start, Nexts, Buf) ->
-    ?ERROR(unicode_string, [Bin, Start, Nexts, Buf]).
+unicode_string(Bin, Start, Nexts, Buf, Opt) ->
+    ?ERROR(unicode_string, [Bin, Start, Nexts, Buf, Opt]).
 
 -spec unicode_to_utf8(0..1114111, binary()) -> binary().
 unicode_to_utf8(Code, Buf) when Code < 16#80 ->
@@ -195,62 +205,71 @@ unicode_to_utf8(Code, Buf) ->
     D = 2#10000000 bor (Code band 2#111111),
     <<Buf/binary, A, B, C, D>>.
 
--spec number(binary(), [next()], binary()) -> decode_result().
-number(<<$-, Bin/binary>>, Nexts, Buf) -> number_integer_part(Bin, -1, Nexts, Buf);
-number(<<Bin/binary>>,     Nexts, Buf) -> number_integer_part(Bin,  1, Nexts, Buf).
+-spec number(binary(), [next()], binary(), opt()) -> decode_result().
+number(<<$-, Bin/binary>>, Nexts, Buf, Opt) -> number_integer_part(Bin, -1, Nexts, Buf, Opt);
+number(<<Bin/binary>>,     Nexts, Buf, Opt) -> number_integer_part(Bin,  1, Nexts, Buf, Opt).
 
--spec number_integer_part(binary(), 1|-1, [next()], binary()) -> decode_result().
-number_integer_part(<<$0, Bin/binary>>, Sign, Nexts, Buf) ->
-    number_fraction_part(Bin, Sign, 0, Nexts, Buf);
-number_integer_part(<<C, Bin/binary>>, Sign, Nexts, Buf) when $1 =< C, C =< $9 ->
-    number_integer_part_rest(Bin, C - $0, Sign, Nexts, Buf);
-number_integer_part(Bin, Sign, Nexts, Buf) ->
-    ?ERROR(number_integer_part, [Bin, Sign, Nexts, Buf]).
+-spec number_integer_part(binary(), 1|-1, [next()], binary(), opt()) -> decode_result().
+number_integer_part(<<$0, Bin/binary>>, Sign, Nexts, Buf, Opt) ->
+    number_fraction_part(Bin, Sign, 0, Nexts, Buf, Opt);
+number_integer_part(<<C, Bin/binary>>, Sign, Nexts, Buf, Opt) when $1 =< C, C =< $9 ->
+    number_integer_part_rest(Bin, C - $0, Sign, Nexts, Buf, Opt);
+number_integer_part(Bin, Sign, Nexts, Buf, Opt) ->
+    ?ERROR(number_integer_part, [Bin, Sign, Nexts, Buf, Opt]).
 
--spec number_integer_part_rest(binary(), non_neg_integer(), 1|-1, [next()], binary()) -> decode_result().
-number_integer_part_rest(<<C, Bin/binary>>, N, Sign, Nexts, Buf) when $0 =< C, C =< $9 ->
-    number_integer_part_rest(Bin, N * 10 + C - $0, Sign, Nexts, Buf);
-number_integer_part_rest(<<Bin/binary>>, N, Sign, Nexts, Buf) ->
-    number_fraction_part(Bin, Sign, N, Nexts, Buf).
+-spec number_integer_part_rest(binary(), non_neg_integer(), 1|-1, [next()], binary(), opt()) -> decode_result().
+number_integer_part_rest(<<C, Bin/binary>>, N, Sign, Nexts, Buf, Opt) when $0 =< C, C =< $9 ->
+    number_integer_part_rest(Bin, N * 10 + C - $0, Sign, Nexts, Buf, Opt);
+number_integer_part_rest(<<Bin/binary>>, N, Sign, Nexts, Buf, Opt) ->
+    number_fraction_part(Bin, Sign, N, Nexts, Buf, Opt).
 
--spec number_fraction_part(binary(), 1|-1, non_neg_integer(), [next()], binary()) -> decode_result().
-number_fraction_part(<<$., Bin/binary>>, Sign, Int, Nexts, Buf) ->
-    number_fraction_part_rest(Bin, Sign, Int, 0, Nexts, Buf);
-number_fraction_part(<<Bin/binary>>, Sign, Int, Nexts, Buf) ->
-    number_exponation_part(Bin, Sign * Int, 0, Nexts, Buf).
+-spec number_fraction_part(binary(), 1|-1, non_neg_integer(), [next()], binary(), opt()) -> decode_result().
+number_fraction_part(<<$., Bin/binary>>, Sign, Int, Nexts, Buf, Opt) ->
+    number_fraction_part_rest(Bin, Sign, Int, 0, Nexts, Buf, Opt);
+number_fraction_part(<<Bin/binary>>, Sign, Int, Nexts, Buf, Opt) ->
+    number_exponation_part(Bin, Sign * Int, 0, Nexts, Buf, Opt).
 
--spec number_fraction_part_rest(binary(), 1|-1, non_neg_integer(), non_neg_integer(), [next()], binary()) -> decode_result().
-number_fraction_part_rest(<<C, Bin/binary>>, Sign, N, DecimalOffset, Nexts, Buf) when $0 =< C, C =< $9 ->
-    number_fraction_part_rest(Bin, Sign, N * 10 + C - $0, DecimalOffset + 1, Nexts, Buf);
-number_fraction_part_rest(<<Bin/binary>>, Sign, N, DecimalOffset, Nexts, Buf) when DecimalOffset > 0 ->
-    number_exponation_part(Bin, Sign * N, DecimalOffset, Nexts, Buf);
-number_fraction_part_rest(Bin, Sign, N, DecimalOffset, Nexts, Buf) ->
-    ?ERROR(number_fraction_part_rest, [Bin, Sign, N, DecimalOffset, Nexts, Buf]).
+-spec number_fraction_part_rest(binary(), 1|-1, non_neg_integer(), non_neg_integer(), [next()], binary(), opt()) -> decode_result().
+number_fraction_part_rest(<<C, Bin/binary>>, Sign, N, DecimalOffset, Nexts, Buf, Opt) when $0 =< C, C =< $9 ->
+    number_fraction_part_rest(Bin, Sign, N * 10 + C - $0, DecimalOffset + 1, Nexts, Buf, Opt);
+number_fraction_part_rest(<<Bin/binary>>, Sign, N, DecimalOffset, Nexts, Buf, Opt) when DecimalOffset > 0 ->
+    number_exponation_part(Bin, Sign * N, DecimalOffset, Nexts, Buf, Opt);
+number_fraction_part_rest(Bin, Sign, N, DecimalOffset, Nexts, Buf, Opt) ->
+    ?ERROR(number_fraction_part_rest, [Bin, Sign, N, DecimalOffset, Nexts, Buf, Opt]).
 
--spec number_exponation_part(binary(), integer(), non_neg_integer(), [next()], binary()) -> decode_result().
-number_exponation_part(<<$e, $+, Bin/binary>>, N, DecimalOffset, Nexts, Buf) ->
-    number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts, Buf);
-number_exponation_part(<<$E, $+, Bin/binary>>, N, DecimalOffset, Nexts, Buf) ->
-    number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts, Buf);
-number_exponation_part(<<$e, $-, Bin/binary>>, N, DecimalOffset, Nexts, Buf) ->
-    number_exponation_part(Bin, N, DecimalOffset, -1, 0, true, Nexts, Buf);
-number_exponation_part(<<$E, $-, Bin/binary>>, N, DecimalOffset, Nexts, Buf) ->
-    number_exponation_part(Bin, N, DecimalOffset, -1, 0, true, Nexts, Buf);
-number_exponation_part(<<$e, Bin/binary>>, N, DecimalOffset, Nexts, Buf) ->
-    number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts, Buf);
-number_exponation_part(<<$E, Bin/binary>>, N, DecimalOffset, Nexts, Buf) ->
-    number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts, Buf);
-number_exponation_part(<<Bin/binary>>, N, DecimalOffset, Nexts, Buf) ->
+-spec number_exponation_part(binary(), integer(), non_neg_integer(), [next()], binary(), opt()) -> decode_result().
+number_exponation_part(<<$e, $+, Bin/binary>>, N, DecimalOffset, Nexts, Buf, Opt) ->
+    number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts, Buf, Opt);
+number_exponation_part(<<$E, $+, Bin/binary>>, N, DecimalOffset, Nexts, Buf, Opt) ->
+    number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts, Buf, Opt);
+number_exponation_part(<<$e, $-, Bin/binary>>, N, DecimalOffset, Nexts, Buf, Opt) ->
+    number_exponation_part(Bin, N, DecimalOffset, -1, 0, true, Nexts, Buf, Opt);
+number_exponation_part(<<$E, $-, Bin/binary>>, N, DecimalOffset, Nexts, Buf, Opt) ->
+    number_exponation_part(Bin, N, DecimalOffset, -1, 0, true, Nexts, Buf, Opt);
+number_exponation_part(<<$e, Bin/binary>>, N, DecimalOffset, Nexts, Buf, Opt) ->
+    number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts, Buf, Opt);
+number_exponation_part(<<$E, Bin/binary>>, N, DecimalOffset, Nexts, Buf, Opt) ->
+    number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts, Buf, Opt);
+number_exponation_part(<<Bin/binary>>, N, DecimalOffset, Nexts, Buf, Opt) ->
     case DecimalOffset of
-        0 -> next(Bin, N, Nexts, Buf);
-        _ -> next(Bin, N / math:pow(10, DecimalOffset), Nexts, Buf)
+        0 -> next(Bin, N, Nexts, Buf, Opt);
+        _ -> next(Bin, N / math:pow(10, DecimalOffset), Nexts, Buf, Opt)
     end.
 
--spec number_exponation_part(binary(), integer(), non_neg_integer(), 1|-1, non_neg_integer(), boolean(), [next()], binary()) -> decode_result().
-number_exponation_part(<<C, Bin/binary>>, N, DecimalOffset, ExpSign, Exp, _, Nexts, Buf) when $0 =< C, C =< $9 ->
-    number_exponation_part(Bin, N, DecimalOffset, ExpSign, Exp * 10 + C - $0, false, Nexts, Buf);
-number_exponation_part(<<Bin/binary>>, N, DecimalOffset, ExpSign, Exp, false, Nexts, Buf) ->
+-spec number_exponation_part(binary(), integer(), non_neg_integer(), 1|-1, non_neg_integer(), boolean(), [next()], binary(), opt()) -> decode_result().
+number_exponation_part(<<C, Bin/binary>>, N, DecimalOffset, ExpSign, Exp, _, Nexts, Buf, Opt) when $0 =< C, C =< $9 ->
+    number_exponation_part(Bin, N, DecimalOffset, ExpSign, Exp * 10 + C - $0, false, Nexts, Buf, Opt);
+number_exponation_part(<<Bin/binary>>, N, DecimalOffset, ExpSign, Exp, false, Nexts, Buf, Opt) ->
     Pos = ExpSign * Exp - DecimalOffset,
-    next(Bin, N * math:pow(10, Pos), Nexts, Buf);
-number_exponation_part(Bin, N, DecimalOffset, ExpSign, Exp, IsFirst, Nexts, Buf) ->
-    ?ERROR(number_exponation_part, [Bin, N, DecimalOffset, ExpSign, Exp, IsFirst, Nexts, Buf]).
+    next(Bin, N * math:pow(10, Pos), Nexts, Buf, Opt);
+number_exponation_part(Bin, N, DecimalOffset, ExpSign, Exp, IsFirst, Nexts, Buf, Opt) ->
+    ?ERROR(number_exponation_part, [Bin, N, DecimalOffset, ExpSign, Exp, IsFirst, Nexts, Buf, Opt]).
+
+-spec parse_options([jsone:decode_option()]) -> opt().
+parse_options(Options) ->
+    parse_option(Options, ?OPT{}).
+
+-spec parse_option([jsone:decode_option()], opt()) -> opt().
+parse_option([], Opt) -> Opt;
+parse_option([{format,F}|T], Opt) ->
+    parse_option(T, Opt?OPT{format=F}).

+ 2 - 3
src/jsone_encode.erl

@@ -33,7 +33,7 @@
 -export([encode/1, encode/2]).
 
 %%--------------------------------------------------------------------------------
-%% Macros & Types
+%% Macros & Records & Types
 %%--------------------------------------------------------------------------------
 -define(ERROR(Function, Args), {error, {badarg, [{?MODULE, Function, Args, [{line, ?LINE}]}]}}).
 -define(IS_REDUNDANT_UTF8(B1, B2, FirstBitN), (B1 =:= 0 andalso B2 < (1 bsl (FirstBitN + 1)))).
@@ -52,10 +52,9 @@
 %%--------------------------------------------------------------------------------
 %% Exported Functions
 %%--------------------------------------------------------------------------------
-%% @doc Encodes an erlang term into json text (a utf8 encoded binary)
 -spec encode(jsone:json_value()) -> encode_result().
 encode(Value) ->
-    jsone:try_encode(Value).
+    encode(Value, []).
 
 -spec encode(jsone:json_value(), [jsone:encode_option()]) -> encode_result().
 encode(Value, Options) ->

+ 5 - 3
test/jsone_decode_tests.erl

@@ -75,7 +75,7 @@ decode_test_() ->
               ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"0.1e--1">>)), % duplicated sign
               ?assertEqual({ok, 0.1, <<".2">>}, jsone_decode:decode(<<"0.1.2">>))     % duplicated '.': interpreted as individual tokens
       end},
-     
+
      %% Strings
      {"simple string",
       fun () ->
@@ -163,7 +163,8 @@ decode_test_() ->
       fun () ->
               Input    = <<"{\"1\":2,\"key\":\"value\"}">>,
               Expected = {[{<<"key">>, <<"value">>}, {<<"1">>, 2}]},
-              ?assertEqual({ok, Expected, <<"">>}, jsone_decode:decode(Input))
+              ?assertEqual({ok, Expected, <<"">>}, jsone_decode:decode(Input)),
+              ?assertEqual({ok, element(1, Expected), <<"">>}, jsone_decode:decode(Input, [{format, proplist}]))
       end},
      {"object: contains whitespaces",
       fun () ->
@@ -174,7 +175,8 @@ decode_test_() ->
      {"empty object",
       fun () ->
               ?assertEqual({ok, {[]}, <<"">>}, jsone_decode:decode(<<"{}">>)),
-              ?assertEqual({ok, {[]}, <<"">>}, jsone_decode:decode(<<"{ \t\r\n}">>))
+              ?assertEqual({ok, {[]}, <<"">>}, jsone_decode:decode(<<"{ \t\r\n}">>)),
+              ?assertEqual({ok, [{}], <<"">>}, jsone_decode:decode(<<"{}">>, [{format, proplist}]))
       end},
      {"object: trailing comma is disallowed",
       fun () ->