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:
alisdair sullivan 2010-05-27 06:42:58 -07:00
parent 06ded56939
commit 7e6124fc88
4 changed files with 32 additions and 40 deletions

View file

@ -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

View file

@ -25,8 +25,7 @@
comments = false,
escaped_unicode = ascii,
naked_values = false,
encoding = utf8,
explicit_termination = false
encoding = utf8
}).
%% whitespace

View file

@ -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) ->

View file

@ -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.