explicit termination is no longer an option. the decoder now terminates whenever it reaches the end of an unambiguous json term and returns a function that accepts either more input to continue decoding or the empty binary to force termination.
examples are currently broken, but the test suite has been updated to reflect the new api.
This commit is contained in:
parent
06ded56939
commit
7e6124fc88
4 changed files with 32 additions and 40 deletions
|
@ -62,13 +62,10 @@ parse_opts([{escaped_unicode, Value}|Rest], Opts) ->
|
|||
parse_opts(Rest, Opts#opts{escaped_unicode = Value});
|
||||
parse_opts([{naked_values, Value}|Rest], Opts) ->
|
||||
true = lists:member(Value, [true, false]),
|
||||
parse_opts(Rest, Opts#opts{naked_values = Value, explicit_termination = true});
|
||||
parse_opts(Rest, Opts#opts{naked_values = Value});
|
||||
parse_opts([{encoding, Value}|Rest], Opts) ->
|
||||
true = lists:member(Value, [utf8]),
|
||||
parse_opts(Rest, Opts#opts{encoding = Value});
|
||||
parse_opts([{explicit_termination, Value}|Rest], Opts) ->
|
||||
true = lists:member(Value, [true, false]),
|
||||
parse_opts(Rest, Opts#opts{explicit_termination = Value}).
|
||||
parse_opts(Rest, Opts#opts{encoding = Value}).
|
||||
|
||||
|
||||
%% ensures there's no invalid characters left in the stream upon completion of parsing
|
||||
|
|
|
@ -25,8 +25,7 @@
|
|||
comments = false,
|
||||
escaped_unicode = ascii,
|
||||
naked_values = false,
|
||||
encoding = utf8,
|
||||
explicit_termination = false
|
||||
encoding = utf8
|
||||
}).
|
||||
|
||||
%% whitespace
|
||||
|
|
|
@ -59,10 +59,16 @@ start(<<S, Rest/binary>>, Stack, Callbacks, Opts) when ?is_nonzero(S), Opts#opts
|
|||
integer(Rest, Stack, Callbacks, Opts, [S]);
|
||||
start(<<?solidus, Rest/binary>>, Stack, Callbacks, Opts) when Opts#opts.comments == true ->
|
||||
maybe_comment(Rest, fun(Resume) -> start(Resume, Stack, Callbacks, Opts) end);
|
||||
start(<<>>, [], Callbacks, Opts) ->
|
||||
fun(<<>>) -> {fold(completed_parse, Callbacks), <<>>}
|
||||
; (Stream) -> start(Stream, [], Callbacks, Opts)
|
||||
end;
|
||||
start(<<>>, Stack, Callbacks, Opts) ->
|
||||
fun(Stream) -> start(Stream, Stack, Callbacks, Opts) end.
|
||||
|
||||
|
||||
maybe_done(<<Rest/binary>>, [], Callbacks, _Opts) ->
|
||||
{fold(completed_parse, Callbacks), Rest};
|
||||
maybe_done(<<S, Rest/binary>>, Stack, Callbacks, Opts) when ?is_whitespace(S) ->
|
||||
maybe_done(Rest, Stack, Callbacks, Opts);
|
||||
maybe_done(<<?end_object, Rest/binary>>, [object|Stack], Callbacks, Opts) ->
|
||||
|
@ -75,12 +81,6 @@ maybe_done(<<?comma, Rest/binary>>, [array|_] = Stack, Callbacks, Opts) ->
|
|||
value(Rest, Stack, Callbacks, Opts);
|
||||
maybe_done(<<?solidus, Rest/binary>>, Stack, Callbacks, Opts) when Opts#opts.comments == true ->
|
||||
maybe_comment(Rest, fun(Resume) -> maybe_done(Resume, Stack, Callbacks, Opts) end);
|
||||
maybe_done(<<>>, [], Callbacks, Opts) when Opts#opts.explicit_termination == true ->
|
||||
fun(<<>>) -> {fold(completed_parse, Callbacks), <<>>}
|
||||
;(Stream) -> maybe_done(Stream, [], Callbacks, Opts)
|
||||
end;
|
||||
maybe_done(<<Rest/binary>>, [], Callbacks, _Opts) ->
|
||||
{fold(completed_parse, Callbacks), Rest};
|
||||
maybe_done(<<>>, Stack, Callbacks, Opts) ->
|
||||
fun(Stream) -> maybe_done(Stream, Stack, Callbacks, Opts) end.
|
||||
|
||||
|
@ -264,12 +264,10 @@ zero(<<S, Rest/binary>>, Stack, Callbacks, Opts, Acc) when ?is_whitespace(S) ->
|
|||
maybe_done(Rest, Stack, fold({number, lists:reverse(Acc)}, Callbacks), Opts);
|
||||
zero(<<?solidus, Rest/binary>>, Stack, Callbacks, Opts, Acc) when Opts#opts.comments == true ->
|
||||
maybe_comment(Rest, fun(Resume) -> zero(Resume, Stack, Callbacks, Opts, Acc) end);
|
||||
zero(<<Rest/binary>>, [], Callbacks, Opts, Acc) when Opts#opts.explicit_termination == true ->
|
||||
fun(<<>>) -> {fold(completed_parse, fold({number, lists:reverse(Acc)}, Callbacks)), Rest}
|
||||
;(Stream) -> zero(Stream, [], Callbacks, Opts, Acc)
|
||||
end;
|
||||
zero(<<>>, Stack, Callbacks, Opts, Acc) ->
|
||||
fun(Stream) -> zero(Stream, Stack, Callbacks, Opts, Acc) end.
|
||||
fun(<<>>) -> maybe_done(<<>>, Stack, fold({number, lists:reverse(Acc)}, Callbacks), Opts)
|
||||
; (Stream) -> zero(Stream, Stack, Callbacks, Opts, Acc)
|
||||
end.
|
||||
|
||||
|
||||
integer(<<S, Rest/binary>>, Stack, Callbacks, Opts, Acc) when ?is_nonzero(S) ->
|
||||
|
@ -294,12 +292,10 @@ integer(<<S, Rest/binary>>, Stack, Callbacks, Opts, Acc) when ?is_whitespace(S)
|
|||
maybe_done(Rest, Stack, fold({number, lists:reverse(Acc)}, Callbacks), Opts);
|
||||
integer(<<?solidus, Rest/binary>>, Stack, Callbacks, Opts, Acc) when Opts#opts.comments == true ->
|
||||
maybe_comment(Rest, fun(Resume) -> integer(Resume, Stack, Callbacks, Opts, Acc) end);
|
||||
integer(<<>> = Rest, [], Callbacks, Opts, Acc) when Opts#opts.explicit_termination == true ->
|
||||
fun(<<>>) -> {fold(completed_parse, fold({number, lists:reverse(Acc)}, Callbacks)), Rest}
|
||||
;(Stream) -> integer(Stream, [], Callbacks, Opts, Acc)
|
||||
end;
|
||||
integer(<<>>, Stack, Callbacks, Opts, Acc) ->
|
||||
fun(Stream) -> integer(Stream, Stack, Callbacks, Opts, Acc) end.
|
||||
fun(<<>>) -> maybe_done(<<>>, Stack, fold({number, lists:reverse(Acc)}, Callbacks), Opts)
|
||||
; (Stream) -> integer(Stream, Stack, Callbacks, Opts, Acc)
|
||||
end.
|
||||
|
||||
fraction(<<S, Rest/binary>>, Stack, Callbacks, Opts, Acc) when ?is_nonzero(S) ->
|
||||
fraction(Rest, Stack, Callbacks, Opts, [S] ++ Acc);
|
||||
|
@ -321,12 +317,10 @@ fraction(<<S, Rest/binary>>, Stack, Callbacks, Opts, Acc) when ?is_whitespace(S)
|
|||
maybe_done(Rest, Stack, fold({number, lists:reverse(Acc)}, Callbacks), Opts);
|
||||
fraction(<<?solidus, Rest/binary>>, Stack, Callbacks, Opts, Acc) when Opts#opts.comments == true ->
|
||||
maybe_comment(Rest, fun(Resume) -> fraction(Resume, Stack, Callbacks, Opts, Acc) end);
|
||||
fraction(<<Rest/binary>>, [], Callbacks, Opts, Acc) when Opts#opts.explicit_termination == true ->
|
||||
fun(<<>>) -> {fold(completed_parse, fold({number, lists:reverse(Acc)}, Callbacks)), Rest}
|
||||
;(Stream) -> fraction(Stream, [], Callbacks, Opts, Acc)
|
||||
end;
|
||||
fraction(<<>>, Stack, Callbacks, Opts, Acc) ->
|
||||
fun(Stream) -> fraction(Stream, Stack, Callbacks, Opts, Acc) end.
|
||||
fun(<<>>) -> maybe_done(<<>>, Stack, fold({number, lists:reverse(Acc)}, Callbacks), Opts)
|
||||
; (Stream) -> fraction(Stream, Stack, Callbacks, Opts, Acc)
|
||||
end.
|
||||
|
||||
|
||||
e(<<S, Rest/binary>>, Stack, Callbacks, Opts, Acc) when S =:= ?zero; ?is_nonzero(S) ->
|
||||
|
@ -359,12 +353,10 @@ exp(<<?solidus, Rest/binary>>, Stack, Callbacks, Opts, Acc) when Opts#opts.comme
|
|||
maybe_comment(Rest, fun(Resume) -> exp(Resume, Stack, Callbacks, Opts, Acc) end);
|
||||
exp(<<S, Rest/binary>>, Stack, Callbacks, Opts, Acc) when ?is_whitespace(S) ->
|
||||
maybe_done(Rest, Stack, fold({number, lists:reverse(Acc)}, Callbacks), Opts);
|
||||
exp(<<Rest/binary>>, [], Callbacks, Opts, Acc) when Opts#opts.explicit_termination == true ->
|
||||
fun(<<>>) -> {fold(completed_parse, fold({number, lists:reverse(Acc)}, Callbacks)), Rest}
|
||||
;(Stream) -> exp(Stream, [], Callbacks, Opts, Acc)
|
||||
end;
|
||||
exp(<<>>, Stack, Callbacks, Opts, Acc) ->
|
||||
fun(Stream) -> exp(Stream, Stack, Callbacks, Opts, Acc) end.
|
||||
fun(<<>>) -> maybe_done(<<>>, Stack, fold({number, lists:reverse(Acc)}, Callbacks), Opts)
|
||||
; (Stream) -> exp(Stream, Stack, Callbacks, Opts, Acc)
|
||||
end.
|
||||
|
||||
|
||||
tr(<<$r, Rest/binary>>, Stack, Callbacks, Opts) ->
|
||||
|
|
|
@ -50,24 +50,28 @@ test_body(TestSpec, Dir) ->
|
|||
case file:consult(Dir ++ "/" ++ TestSpec) of
|
||||
{ok, [Events]} ->
|
||||
Decoder = jsx:decoder(),
|
||||
[{TestName, ?_assertEqual(incremental_decode(Decoder, JSON), Events)}] ++
|
||||
[{TestName ++ "_incremental", ?_assertEqual(incremental_decode(Decoder, JSON), Events)}] ++
|
||||
[{TestName, ?_assertEqual(decode(Decoder, JSON), Events)}]
|
||||
; {ok, [Events, Flags]} ->
|
||||
Decoder = jsx:decoder(Flags),
|
||||
[{TestName, ?_assertEqual(incremental_decode(Decoder, JSON), Events)}] ++
|
||||
[{TestName ++ "_incremental", ?_assertEqual(incremental_decode(Decoder, JSON), Events)}] ++
|
||||
[{TestName, ?_assertEqual(decode(Decoder, JSON), Events)}]
|
||||
end
|
||||
catch _:_ -> []
|
||||
end.
|
||||
|
||||
incremental_decode(F, <<>>) ->
|
||||
{Result, Rest} = F(<<>>),
|
||||
true = jsx:tail_clean(Rest),
|
||||
Result;
|
||||
case F(<<>>) of
|
||||
G when is_function(G) ->
|
||||
{Result, <<>>} = G(<<>>),
|
||||
Result
|
||||
; {Result, Rest} ->
|
||||
Result
|
||||
end;
|
||||
incremental_decode(F, <<A/utf8, Rest/binary>>) ->
|
||||
case F(<<A/utf8>>) of
|
||||
G when is_function(G) ->
|
||||
decode(G, Rest)
|
||||
incremental_decode(G, Rest)
|
||||
; {Result, _} ->
|
||||
Result
|
||||
end.
|
||||
|
@ -78,7 +82,7 @@ decode(F, JSON) ->
|
|||
{Result, <<>>} = G(<<>>),
|
||||
Result
|
||||
; {Result, Rest} ->
|
||||
true = jsx:tail_clean(Rest),
|
||||
{_, <<>>} = (F(Rest))(<<>>),
|
||||
Result
|
||||
end.
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue