From 7e6124fc88bd605c9c1604c7ca88abb448a32a86 Mon Sep 17 00:00:00 2001 From: alisdair sullivan Date: Thu, 27 May 2010 06:42:58 -0700 Subject: [PATCH] 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. --- src/jsx.erl | 7 ++----- src/jsx_common.hrl | 3 +-- src/jsx_decoder.erl | 44 ++++++++++++++++++-------------------------- test/jsx_test.erl | 18 +++++++++++------- 4 files changed, 32 insertions(+), 40 deletions(-) diff --git a/src/jsx.erl b/src/jsx.erl index a8ddf8f..8478358 100644 --- a/src/jsx.erl +++ b/src/jsx.erl @@ -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 diff --git a/src/jsx_common.hrl b/src/jsx_common.hrl index 3700b03..4bf1673 100644 --- a/src/jsx_common.hrl +++ b/src/jsx_common.hrl @@ -25,8 +25,7 @@ comments = false, escaped_unicode = ascii, naked_values = false, - encoding = utf8, - explicit_termination = false + encoding = utf8 }). %% whitespace diff --git a/src/jsx_decoder.erl b/src/jsx_decoder.erl index f5be509..3533c7c 100644 --- a/src/jsx_decoder.erl +++ b/src/jsx_decoder.erl @@ -59,10 +59,16 @@ start(<>, Stack, Callbacks, Opts) when ?is_nonzero(S), Opts#opts integer(Rest, Stack, Callbacks, Opts, [S]); start(<>, 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(<>, [], Callbacks, _Opts) -> + {fold(completed_parse, Callbacks), Rest}; maybe_done(<>, Stack, Callbacks, Opts) when ?is_whitespace(S) -> maybe_done(Rest, Stack, Callbacks, Opts); maybe_done(<>, [object|Stack], Callbacks, Opts) -> @@ -75,12 +81,6 @@ maybe_done(<>, [array|_] = Stack, Callbacks, Opts) -> value(Rest, Stack, Callbacks, Opts); maybe_done(<>, 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(<>, [], 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(<>, Stack, Callbacks, Opts, Acc) when ?is_whitespace(S) -> maybe_done(Rest, Stack, fold({number, lists:reverse(Acc)}, Callbacks), Opts); zero(<>, Stack, Callbacks, Opts, Acc) when Opts#opts.comments == true -> maybe_comment(Rest, fun(Resume) -> zero(Resume, Stack, Callbacks, Opts, Acc) end); -zero(<>, [], 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(<>, Stack, Callbacks, Opts, Acc) when ?is_nonzero(S) -> @@ -294,12 +292,10 @@ integer(<>, Stack, Callbacks, Opts, Acc) when ?is_whitespace(S) maybe_done(Rest, Stack, fold({number, lists:reverse(Acc)}, Callbacks), Opts); integer(<>, 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(<>, Stack, Callbacks, Opts, Acc) when ?is_nonzero(S) -> fraction(Rest, Stack, Callbacks, Opts, [S] ++ Acc); @@ -321,12 +317,10 @@ fraction(<>, Stack, Callbacks, Opts, Acc) when ?is_whitespace(S) maybe_done(Rest, Stack, fold({number, lists:reverse(Acc)}, Callbacks), Opts); fraction(<>, Stack, Callbacks, Opts, Acc) when Opts#opts.comments == true -> maybe_comment(Rest, fun(Resume) -> fraction(Resume, Stack, Callbacks, Opts, Acc) end); -fraction(<>, [], 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(<>, Stack, Callbacks, Opts, Acc) when S =:= ?zero; ?is_nonzero(S) -> @@ -359,12 +353,10 @@ exp(<>, Stack, Callbacks, Opts, Acc) when Opts#opts.comme maybe_comment(Rest, fun(Resume) -> exp(Resume, Stack, Callbacks, Opts, Acc) end); exp(<>, Stack, Callbacks, Opts, Acc) when ?is_whitespace(S) -> maybe_done(Rest, Stack, fold({number, lists:reverse(Acc)}, Callbacks), Opts); -exp(<>, [], 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) -> diff --git a/test/jsx_test.erl b/test/jsx_test.erl index b51b3d3..a1b7b91 100644 --- a/test/jsx_test.erl +++ b/test/jsx_test.erl @@ -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, <>) -> case F(<>) 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. \ No newline at end of file