diff --git a/include/jsx_scanner.hrl b/include/jsx_scanner.hrl index b1728c9..7e06bb1 100644 --- a/include/jsx_scanner.hrl +++ b/include/jsx_scanner.hrl @@ -60,144 +60,144 @@ -ifndef(incomplete). --define(incomplete(State, Rest, T, Stack, Opts), - {ok, lists:reverse(T), fun(Stream) when is_binary(Stream) -> +-define(incomplete(State, Rest, Out, Stack, Opts), + {ok, lists:reverse(Out), fun(Stream) when is_binary(Stream) -> State(<>, [], Stack, Opts) end } ). --define(incomplete(State, Rest, T, Stack, Opts, Acc), - {ok, lists:reverse(T), fun(Stream) when is_binary(Stream) -> - State(<>, [], Stack, Opts, Acc) - end - } -). -endif. -ifndef(event). --define(event(Event, State, Rest, T, Stack, Opts), - State(Rest, Event ++ T, Stack, Opts) +-define(event(Event, State, Rest, Out, Stack, Opts), + State(Rest, Event ++ Out, Stack, Opts) ). -endif. +-define(new_seq(), []). +-define(new_seq(C), [C]). -start(<>, T, Stack, Opts) -> - ?event([start_object], object, Rest, T, [key|Stack], Opts); -start(<>, T, Stack, Opts) -> - ?event([start_array], array, Rest, T, [array|Stack], Opts); -start(<>, T, Stack, Opts) -> - string(Rest, T, Stack, Opts, []); -start(<<$t, Rest/binary>>, T, Stack, Opts) -> - tr(Rest, T, Stack, Opts); -start(<<$f, Rest/binary>>, T, Stack, Opts) -> - fa(Rest, T, Stack, Opts); -start(<<$n, Rest/binary>>, T, Stack, Opts) -> - nu(Rest, T, Stack, Opts); -start(<>, T, Stack, Opts) -> - negative(Rest, T, Stack, Opts, "-"); -start(<>, T, Stack, Opts) -> - zero(Rest, T, Stack, Opts, "0"); -start(<>, T, Stack, Opts) when ?is_nonzero(S) -> - integer(Rest, T, Stack, Opts, [S]); -start(<>, T, Stack, Opts) when ?is_whitespace(S) -> - start(Rest, T, Stack, Opts); -start(<<>>, T, Stack, Opts) -> - ?incomplete(start, <<>>, T, Stack, Opts); -start(Bin, T, Stack, Opts) -> - ?error([Bin, T, Stack, Opts]). +-define(acc_seq(Seq, C), [C] ++ Seq). + +-define(end_seq(Seq), lists:reverse(Seq)). -object(<>, T, Stack, Opts) -> - string(Rest, T, Stack, Opts, []); -object(<>, T, [key|Stack], Opts) -> - ?event([end_object], maybe_done, Rest, T, Stack, Opts); -object(<>, T, Stack, Opts) when ?is_whitespace(S) -> - object(Rest, T, Stack, Opts); -object(<<>>, T, Stack, Opts) -> - ?incomplete(object, <<>>, T, Stack, Opts); -object(Bin, T, Stack, Opts) -> - ?error([Bin, T, Stack, Opts]). +start(<>, Out, Stack, Opts) -> + ?event([start_object], object, Rest, Out, [key|Stack], Opts); +start(<>, Out, Stack, Opts) -> + ?event([start_array], array, Rest, Out, [array|Stack], Opts); +start(<>, Out, Stack, Opts) -> + string(Rest, Out, [?new_seq()|Stack], Opts); +start(<<$t, Rest/binary>>, Out, Stack, Opts) -> + tr(Rest, Out, Stack, Opts); +start(<<$f, Rest/binary>>, Out, Stack, Opts) -> + fa(Rest, Out, Stack, Opts); +start(<<$n, Rest/binary>>, Out, Stack, Opts) -> + nu(Rest, Out, Stack, Opts); +start(<>, Out, Stack, Opts) -> + negative(Rest, Out, [?new_seq($-)|Stack], Opts); +start(<>, Out, Stack, Opts) -> + zero(Rest, Out, [?new_seq($0)|Stack], Opts); +start(<>, Out, Stack, Opts) when ?is_nonzero(S) -> + integer(Rest, Out, [?new_seq(S)|Stack], Opts); +start(<>, Out, Stack, Opts) when ?is_whitespace(S) -> + start(Rest, Out, Stack, Opts); +start(<<>>, Out, Stack, Opts) -> + ?incomplete(start, <<>>, Out, Stack, Opts); +start(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). + + +object(<>, Out, Stack, Opts) -> + string(Rest, Out, [?new_seq()|Stack], Opts); +object(<>, Out, [key|Stack], Opts) -> + ?event([end_object], maybe_done, Rest, Out, Stack, Opts); +object(<>, Out, Stack, Opts) when ?is_whitespace(S) -> + object(Rest, Out, Stack, Opts); +object(<<>>, Out, Stack, Opts) -> + ?incomplete(object, <<>>, Out, Stack, Opts); +object(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -array(<>, T, Stack, Opts) -> - string(Rest, T, Stack, Opts, []); -array(<<$t, Rest/binary>>, T, Stack, Opts) -> - tr(Rest, T, Stack, Opts); -array(<<$f, Rest/binary>>, T, Stack, Opts) -> - fa(Rest, T, Stack, Opts); -array(<<$n, Rest/binary>>, T, Stack, Opts) -> - nu(Rest, T, Stack, Opts); -array(<>, T, Stack, Opts) -> - negative(Rest, T, Stack, Opts, "-"); -array(<>, T, Stack, Opts) -> - zero(Rest, T, Stack, Opts, "0"); -array(<>, T, Stack, Opts) when ?is_nonzero(S) -> - integer(Rest, T, Stack, Opts, [S]); -array(<>, T, Stack, Opts) -> - ?event([start_object], object, Rest, T, [key|Stack], Opts); -array(<>, T, Stack, Opts) -> - ?event([start_array], array, Rest, T, [array|Stack], Opts); -array(<>, T, [array|Stack], Opts) -> - maybe_done(Rest, [end_array] ++ T, Stack, Opts); -array(<>, T, Stack, Opts) when ?is_whitespace(S) -> - array(Rest, T, Stack, Opts); -array(<<>>, T, Stack, Opts) -> - ?incomplete(array, <<>>, T, Stack, Opts); -array(Bin, T, Stack, Opts) -> - ?error([Bin, T, Stack, Opts]). +array(<>, Out, Stack, Opts) -> + string(Rest, Out, [?new_seq()|Stack], Opts); +array(<<$t, Rest/binary>>, Out, Stack, Opts) -> + tr(Rest, Out, Stack, Opts); +array(<<$f, Rest/binary>>, Out, Stack, Opts) -> + fa(Rest, Out, Stack, Opts); +array(<<$n, Rest/binary>>, Out, Stack, Opts) -> + nu(Rest, Out, Stack, Opts); +array(<>, Out, Stack, Opts) -> + negative(Rest, Out, [?new_seq($-)|Stack], Opts); +array(<>, Out, Stack, Opts) -> + zero(Rest, Out, [?new_seq($0)|Stack], Opts); +array(<>, Out, Stack, Opts) when ?is_nonzero(S) -> + integer(Rest, Out, [?new_seq(S)|Stack], Opts); +array(<>, Out, Stack, Opts) -> + ?event([start_object], object, Rest, Out, [key|Stack], Opts); +array(<>, Out, Stack, Opts) -> + ?event([start_array], array, Rest, Out, [array|Stack], Opts); +array(<>, Out, [array|Stack], Opts) -> + maybe_done(Rest, [end_array] ++ Out, Stack, Opts); +array(<>, Out, Stack, Opts) when ?is_whitespace(S) -> + array(Rest, Out, Stack, Opts); +array(<<>>, Out, Stack, Opts) -> + ?incomplete(array, <<>>, Out, Stack, Opts); +array(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -value(<>, T, Stack, Opts) -> - string(Rest, T, Stack, Opts, []); -value(<<$t, Rest/binary>>, T, Stack, Opts) -> - tr(Rest, T, Stack, Opts); -value(<<$f, Rest/binary>>, T, Stack, Opts) -> - fa(Rest, T, Stack, Opts); -value(<<$n, Rest/binary>>, T, Stack, Opts) -> - nu(Rest, T, Stack, Opts); -value(<>, T, Stack, Opts) -> - negative(Rest, T, Stack, Opts, "-"); -value(<>, T, Stack, Opts) -> - zero(Rest, T, Stack, Opts, "0"); -value(<>, T, Stack, Opts) when ?is_nonzero(S) -> - integer(Rest, T, Stack, Opts, [S]); -value(<>, T, Stack, Opts) -> - ?event([start_object], object, Rest, T, [key|Stack], Opts); -value(<>, T, Stack, Opts) -> - ?event([start_array], array, Rest, T, [array|Stack], Opts); -value(<>, T, Stack, Opts) when ?is_whitespace(S) -> - value(Rest, T, Stack, Opts); -value(<<>>, T, Stack, Opts) -> - ?incomplete(value, <<>>, T, Stack, Opts); -value(Bin, T, Stack, Opts) -> - ?error([Bin, T, Stack, Opts]). +value(<>, Out, Stack, Opts) -> + string(Rest, Out, [?new_seq()|Stack], Opts); +value(<<$t, Rest/binary>>, Out, Stack, Opts) -> + tr(Rest, Out, Stack, Opts); +value(<<$f, Rest/binary>>, Out, Stack, Opts) -> + fa(Rest, Out, Stack, Opts); +value(<<$n, Rest/binary>>, Out, Stack, Opts) -> + nu(Rest, Out, Stack, Opts); +value(<>, Out, Stack, Opts) -> + negative(Rest, Out, [?new_seq($-)|Stack], Opts); +value(<>, Out, Stack, Opts) -> + zero(Rest, Out, [?new_seq($0)|Stack], Opts); +value(<>, Out, Stack, Opts) when ?is_nonzero(S) -> + integer(Rest, Out, [?new_seq(S)|Stack], Opts); +value(<>, Out, Stack, Opts) -> + ?event([start_object], object, Rest, Out, [key|Stack], Opts); +value(<>, Out, Stack, Opts) -> + ?event([start_array], array, Rest, Out, [array|Stack], Opts); +value(<>, Out, Stack, Opts) when ?is_whitespace(S) -> + value(Rest, Out, Stack, Opts); +value(<<>>, Out, Stack, Opts) -> + ?incomplete(value, <<>>, Out, Stack, Opts); +value(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -colon(<>, T, [key|Stack], Opts) -> - value(Rest, T, [object|Stack], Opts); -colon(<>, T, Stack, Opts) when ?is_whitespace(S) -> - colon(Rest, T, Stack, Opts); -colon(<<>>, T, Stack, Opts) -> - ?incomplete(colon, <<>>, T, Stack, Opts); -colon(Bin, T, Stack, Opts) -> - ?error([Bin, T, Stack, Opts]). +colon(<>, Out, [key|Stack], Opts) -> + value(Rest, Out, [object|Stack], Opts); +colon(<>, Out, Stack, Opts) when ?is_whitespace(S) -> + colon(Rest, Out, Stack, Opts); +colon(<<>>, Out, Stack, Opts) -> + ?incomplete(colon, <<>>, Out, Stack, Opts); +colon(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -key(<>, T, Stack, Opts) -> - string(Rest, T, Stack, Opts, []); -key(<>, T, Stack, Opts) when ?is_whitespace(S) -> - key(Rest, T, Stack, Opts); -key(<<>>, T, Stack, Opts) -> - ?incomplete(key, <<>>, T, Stack, Opts); -key(Bin, T, Stack, Opts) -> - ?error([Bin, T, Stack, Opts]). +key(<>, Out, Stack, Opts) -> + string(Rest, Out, [?new_seq()|Stack], Opts); +key(<>, Out, Stack, Opts) when ?is_whitespace(S) -> + key(Rest, Out, Stack, Opts); +key(<<>>, Out, Stack, Opts) -> + ?incomplete(key, <<>>, Out, Stack, Opts); +key(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -%% string has an additional parameter, an accumulator (Acc) used to hold the -%% intermediate representation of the string being parsed. using a list of -%% integers representing unicode codepoints is faster than constructing -%% binaries, there's a branch kicking around which proves it +%% string appends it's output to the term at the top of the stack. for +%% efficiency the strings are build in reverse order and reversed before +%% being added to the output stream %% string uses partial_utf/1 to cease parsing when invalid encodings are %% encountered rather than just checking remaining binary size like other %% states to eliminate certain incomplete states @@ -215,24 +215,24 @@ partial_utf(<>) partial_utf(_) -> false. -string(<>, T, [key|_] = Stack, Opts, Acc) -> - ?event([{key, lists:reverse(Acc)}], colon, Rest, T, Stack, Opts); -string(<>, T, Stack, Opts, Acc) -> - ?event([{string, lists:reverse(Acc)}], maybe_done, Rest, T, Stack, Opts); -string(<>, T, Stack, Opts, Acc) -> - escape(Rest, T, Stack, Opts, Acc); +string(<>, Out, [Acc, key|Stack], Opts) -> + ?event([{key, ?end_seq(Acc)}], colon, Rest, Out, [key|Stack], Opts); +string(<>, Out, [Acc|Stack], Opts) -> + ?event([{string, ?end_seq(Acc)}], maybe_done, Rest, Out, Stack, Opts); +string(<>, Out, Stack, Opts) -> + escape(Rest, Out, Stack, Opts); %% things get dumb here. erlang doesn't properly restrict unicode non-characters %% so you can't trust the codepoints it returns always %% the range 32..16#fdcf is safe, so allow that -string(<>, T, Stack, Opts, Acc) +string(<>, Out, [Acc|Stack], Opts) when ?is_noncontrol(S), S < 16#fdd0 -> - string(Rest, T, Stack, Opts, [S] ++ Acc); + string(Rest, Out, [?acc_seq(Acc, S)|Stack], Opts); %% the range 16#fdf0..16#fffd is also safe -string(<>, T, Stack, Opts, Acc) +string(<>, Out, [Acc|Stack], Opts) when S > 16#fdef, S < 16#fffe -> - string(Rest, T, Stack, Opts, [S] ++ Acc); + string(Rest, Out, [?acc_seq(Acc, S)|Stack], Opts); %% yes, i think it's insane too -string(<>, T, Stack, Opts, Acc) +string(<>, Out, [Acc|Stack], Opts) when S > 16#ffff andalso S =/= 16#1fffe andalso S =/= 16#1ffff andalso S =/= 16#2fffe andalso S =/= 16#2ffff andalso @@ -250,14 +250,14 @@ string(<>, T, Stack, Opts, Acc) S =/= 16#efffe andalso S =/= 16#effff andalso S =/= 16#ffffe andalso S =/= 16#fffff andalso S =/= 16#10fffe andalso S =/= 16#10ffff -> - string(Rest, T, Stack, Opts, [S] ++ Acc); -string(Bin, T, Stack, Opts, Acc) -> + string(Rest, Out, [?acc_seq(Acc, S)|Stack], Opts); +string(Bin, Out, Stack, Opts) -> case partial_utf(Bin) of - true -> ?incomplete(string, Bin, T, Stack, Opts, Acc) + true -> ?incomplete(string, Bin, Out, Stack, Opts) ; false -> case Opts#opts.loose_unicode of - true -> noncharacter(Bin, T, Stack, Opts, Acc) - ; false -> ?error([Bin, T, Stack, Opts, Acc]) + true -> noncharacter(Bin, Out, Stack, Opts) + ; false -> ?error([Bin, Out, Stack, Opts]) end end. @@ -265,112 +265,112 @@ string(Bin, T, Stack, Opts, Acc) -> %% care of in string. theoretically, the last clause of noncharacter/4 is %% unreachable %% non-characters erlang doesn't recognize as non-characters, idiotically -noncharacter(<>, T, Stack, Opts, Acc) +noncharacter(<>, Out, [Acc|Stack], Opts) when ?is_noncontrol(S) -> - string(Rest, T, Stack, Opts, [16#fffd] ++ Acc); + string(Rest, Out, [?acc_seq(Acc, 16#fffd)|Stack], Opts); %% u+fffe and u+ffff -noncharacter(<<239, 191, X, Rest/binary>>, T, Stack, Opts, Acc) +noncharacter(<<239, 191, X, Rest/binary>>, Out, [Acc|Stack], Opts) when X == 190; X == 191 -> - string(Rest, T, Stack, Opts, [16#fffd] ++ Acc); + string(Rest, Out, [?acc_seq(Acc, 16#fffd)|Stack], Opts); %% surrogates -noncharacter(<<237, X, _, Rest/binary>>, T, Stack, Opts, Acc) when X >= 160 -> - string(Rest, T, Stack, Opts, [16#fffd] ++ Acc); -noncharacter(Bin, T, Stack, Opts, Acc) -> - ?error([Bin, T, Stack, Opts, Acc]). +noncharacter(<<237, X, _, Rest/binary>>, Out, [Acc|Stack], Opts) when X >= 160 -> + string(Rest, Out, [?acc_seq(Acc, 16#fffd)|Stack], Opts); +noncharacter(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -escape(<<$b, Rest/binary>>, T, Stack, Opts, Acc) -> - string(Rest, T, Stack, Opts, "\b" ++ Acc); -escape(<<$f, Rest/binary>>, T, Stack, Opts, Acc) -> - string(Rest, T, Stack, Opts, "\f" ++ Acc); -escape(<<$n, Rest/binary>>, T, Stack, Opts, Acc) -> - string(Rest, T, Stack, Opts, "\n" ++ Acc); -escape(<<$r, Rest/binary>>, T, Stack, Opts, Acc) -> - string(Rest, T, Stack, Opts, "\r" ++ Acc); -escape(<<$t, Rest/binary>>, T, Stack, Opts, Acc) -> - string(Rest, T, Stack, Opts, "\t" ++ Acc); -escape(<<$u, Rest/binary>>, T, Stack, Opts, Acc) -> - escaped_unicode(Rest, T, Stack, Opts, {[], Acc}); -escape(<>, T, Stack, Opts, Acc) +escape(<<$b, Rest/binary>>, Out, [Acc|Stack], Opts) -> + string(Rest, Out, [?acc_seq(Acc, $\b)|Stack], Opts); +escape(<<$f, Rest/binary>>, Out, [Acc|Stack], Opts) -> + string(Rest, Out, [?acc_seq(Acc, $\f)|Stack], Opts); +escape(<<$n, Rest/binary>>, Out, [Acc|Stack], Opts) -> + string(Rest, Out, [?acc_seq(Acc, $\n)|Stack], Opts); +escape(<<$r, Rest/binary>>, Out, [Acc|Stack], Opts) -> + string(Rest, Out, [?acc_seq(Acc, $\r)|Stack], Opts); +escape(<<$t, Rest/binary>>, Out, [Acc|Stack], Opts) -> + string(Rest, Out, [?acc_seq(Acc, $\t)|Stack], Opts); +escape(<<$u, Rest/binary>>, Out, Stack, Opts) -> + escaped_unicode(Rest, Out, [?new_seq()|Stack], Opts); +escape(<>, Out, [Acc|Stack], Opts) when S =:= ?quote; S =:= ?solidus; S =:= ?rsolidus -> - string(Rest, T, Stack, Opts, [S] ++ Acc); -escape(<<>>, T, Stack, Opts, Acc) -> - ?incomplete(escape, <<>>, T, Stack, Opts, Acc); -escape(Bin, T, Stack, Opts, Acc) -> - ?error([Bin, T, Stack, Opts, Acc]). + string(Rest, Out, [?acc_seq(Acc, S)|Stack], Opts); +escape(<<>>, Out, Stack, Opts) -> + ?incomplete(escape, <<>>, Out, Stack, Opts); +escape(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). %% this code is ugly and unfortunate, but so is json's handling of escaped %% unicode codepoint sequences. -escaped_unicode(<>, T, Stack, Opts, {[C, B, A], String}) +escaped_unicode(<>, Out, [[C,B,A], Acc|Stack], Opts) when ?is_hex(D) -> case erlang:list_to_integer([A, B, C, D], 16) of %% high surrogate, we need a low surrogate next X when X >= 16#d800, X =< 16#dbff -> - low_surrogate(Rest, T, Stack, Opts, {X, String}) + low_surrogate(Rest, Out, [X, Acc|Stack], Opts) %% non-characters, you're not allowed to exchange these ; X when X == 16#fffe; X == 16#ffff; X >= 16#fdd0, X =< 16#fdef -> case Opts#opts.loose_unicode of true -> - string(Rest, T, Stack, Opts, [16#fffd] ++ String) + string(Rest, Out, [?acc_seq(Acc, 16#fffd)|Stack], Opts) ; false -> - ?error([<>, T, Stack, Opts, {[C, B, A], String}]) + ?error([<>, Out, [[C,B,A], Acc|Stack], Opts]) end %% allowing interchange of null bytes allows attackers to forge %% malicious streams ; X when X == 16#0000 -> case Opts#opts.loose_unicode of true -> - string(Rest, T, Stack, Opts, [16#fffd] ++ String) + string(Rest, Out, [?acc_seq(Acc, 16#fffd)|Stack], Opts) ; false -> - ?error([<>, T, Stack, Opts, {[C, B, A], String}]) + ?error([<>, Out, [[C,B,A], Acc|Stack], Opts]) end %% anything else ; X -> - string(Rest, T, Stack, Opts, [X] ++ String) + string(Rest, Out, [?acc_seq(Acc, X)|Stack], Opts) end; -escaped_unicode(<>, T, Stack, Opts, {Acc, String}) +escaped_unicode(<>, Out, [Acc|Stack], Opts) when ?is_hex(S) -> - escaped_unicode(Rest, T, Stack, Opts, {[S] ++ Acc, String}); -escaped_unicode(<<>>, T, Stack, Opts, Acc) -> - ?incomplete(escaped_unicode, <<>>, T, Stack, Opts, Acc); -escaped_unicode(Bin, T, Stack, Opts, Acc) -> - ?error([Bin, T, Stack, Opts, Acc]). + escaped_unicode(Rest, Out, [?acc_seq(Acc, S)|Stack], Opts); +escaped_unicode(<<>>, Out, Stack, Opts) -> + ?incomplete(escaped_unicode, <<>>, Out, Stack, Opts); +escaped_unicode(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -low_surrogate(<>, T, Stack, Opts, Acc) -> - low_surrogate_u(Rest, T, Stack, Opts, Acc); +low_surrogate(<>, Out, Stack, Opts) -> + low_surrogate_u(Rest, Out, Stack, Opts); %% not an escaped codepoint, our high codepoint is illegal. dispatch back to %% string to handle -low_surrogate(<> = Bin, T, Stack, Opts, {High, String}) -> +low_surrogate(<> = Bin, Out, [High, String|Stack], Opts) -> case Opts#opts.loose_unicode of true -> - string(Bin, T, Stack, Opts, [16#fffd] ++ String) + string(Bin, Out, [?acc_seq(String, 16#fffd)|Stack], Opts) ; false -> - ?error([<>, T, Stack, Opts, {High, String}]) + ?error([<>, Out, [High, String|Stack], Opts]) end; -low_surrogate(<<>>, T, Stack, Opts, Acc) -> - ?incomplete(low_surrogate, <<>>, T, Stack, Opts, Acc); -low_surrogate(Bin, T, Stack, Opts, Acc) -> - ?error([Bin, T, Stack, Opts, Acc]). +low_surrogate(<<>>, Out, Stack, Opts) -> + ?incomplete(low_surrogate, <<>>, Out, Stack, Opts); +low_surrogate(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -low_surrogate_u(<<$u, Rest/binary>>, T, Stack, Opts, {High, String}) -> - low_surrogate_v(Rest, T, Stack, Opts, {[], High, String}); -low_surrogate_u(<<>>, T, Stack, Opts, Acc) -> - ?incomplete(low_surrogate_u, <<>>, T, Stack, Opts, Acc); +low_surrogate_u(<<$u, Rest/binary>>, Out, Stack, Opts) -> + low_surrogate_v(Rest, Out, [?new_seq()|Stack], Opts); +low_surrogate_u(<<>>, Out, Stack, Opts) -> + ?incomplete(low_surrogate_u, <<>>, Out, Stack, Opts); %% not a low surrogate, dispatch back to string to handle, including the %% rsolidus we parsed previously -low_surrogate_u(Bin, T, Stack, Opts, {High, String}) -> +low_surrogate_u(Bin, Out, [High, String|Stack], Opts) -> case Opts#opts.loose_unicode of true -> - string(<>, T, Stack, Opts, [16#fffd] ++ String) + string(<>, Out, [?acc_seq(String, 16#fffd)|Stack], Opts) ; false -> - ?error([Bin, T, Stack, Opts, {High, String}]) + ?error([Bin, Out, [High, String|Stack], Opts]) end. -low_surrogate_v(<>, T, Stack, Opts, {[C, B, A], High, String}) +low_surrogate_v(<>, Out, [[C,B,A], High, String|Stack], Opts) when ?is_hex(D) -> case erlang:list_to_integer([A, B, C, D], 16) of X when X >= 16#dc00, X =< 16#dfff -> @@ -378,29 +378,29 @@ low_surrogate_v(<>, T, Stack, Opts, {[C, B, A], High, String}) case V rem 16#10000 of Y when Y == 16#fffe; Y == 16#ffff -> case Opts#opts.loose_unicode of true -> - string(Rest, T, Stack, Opts, [16#fffd] ++ String) + string(Rest, Out, [?acc_seq(String, 16#fffd)|Stack], Opts) ; false -> - ?error([<>, T, Stack, Opts, {[C, B, A], High, String}]) + ?error([<>, Out, [[C,B,A], High, String|Stack], Opts]) end ; _ -> - string(Rest, T, Stack, Opts, [V] ++ String) + string(Rest, Out, [?acc_seq(String, V)|Stack], Opts) end %% not a low surrogate, bad bad bad ; _ -> case Opts#opts.loose_unicode of true -> - string(Rest, T, Stack, Opts, [16#fffd, 16#fffd] ++ String) + string(Rest, Out, [?acc_seq(?acc_seq(String, 16#fffd), 16#fffd)|Stack], Opts) ; false -> - ?error([<>, T, Stack, Opts, {[C, B, A], High, String}]) + ?error([<>, Out, [[C,B,A], High, String|Stack], Opts]) end end; -low_surrogate_v(<>, T, Stack, Opts, {Low, High, String}) +low_surrogate_v(<>, Out, [Acc|Stack], Opts) when ?is_hex(S) -> - low_surrogate_v(Rest, T, Stack, Opts, {[S] ++ Low, High, String}); -low_surrogate_v(<<>>, T, Stack, Opts, Acc) -> - ?incomplete(low_surrogate_v, <<>>, T, Stack, Opts, Acc); -low_surrogate_v(Bin, T, Stack, Opts, Acc) -> - ?error([Bin, T, Stack, Opts, Acc]). + low_surrogate_v(Rest, Out, [?acc_seq(Acc, S)|Stack], Opts); +low_surrogate_v(<<>>, Out, Stack, Opts) -> + ?incomplete(low_surrogate_v, <<>>, Out, Stack, Opts); +low_surrogate_v(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). %% stole this from the unicode spec @@ -410,127 +410,127 @@ surrogate_to_codepoint(High, Low) -> %% like strings, numbers are collected in an intermediate accumulator before %% being emitted to the callback handler -negative(<<$0, Rest/binary>>, T, Stack, Opts, Acc) -> - zero(Rest, T, Stack, Opts, "0" ++ Acc); -negative(<>, T, Stack, Opts, Acc) when ?is_nonzero(S) -> - integer(Rest, T, Stack, Opts, [S] ++ Acc); -negative(<<>>, T, Stack, Opts, Acc) -> - ?incomplete(negative, <<>>, T, Stack, Opts, Acc); -negative(Bin, T, Stack, Opts, Acc) -> - ?error([Bin, T, Stack, Opts, Acc]). +negative(<<$0, Rest/binary>>, Out, [Acc|Stack], Opts) -> + zero(Rest, Out, ["0" ++ Acc|Stack], Opts); +negative(<>, Out, [Acc|Stack], Opts) when ?is_nonzero(S) -> + integer(Rest, Out, [[S] ++ Acc|Stack], Opts); +negative(<<>>, Out, Stack, Opts) -> + ?incomplete(negative, <<>>, Out, Stack, Opts); +negative(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -zero(<>, T, [object|Stack], Opts, Acc) -> - ?event([end_object, format_number(Acc)], maybe_done, Rest, T, Stack, Opts); -zero(<>, T, [array|Stack], Opts, Acc) -> - ?event([end_array, format_number(Acc)], maybe_done, Rest, T, Stack, Opts); -zero(<>, T, [object|Stack], Opts, Acc) -> - ?event([format_number(Acc)], key, Rest, T, [key|Stack], Opts); -zero(<>, T, [array|_] = Stack, Opts, Acc) -> - ?event([format_number(Acc)], value, Rest, T, Stack, Opts); -zero(<>, T, Stack, Opts, Acc) -> - initial_decimal(Rest, T, Stack, Opts, {Acc, []}); -zero(<>, T, Stack, Opts, Acc) when ?is_whitespace(S) -> - ?event([format_number(Acc)], maybe_done, Rest, T, Stack, Opts); -zero(<<>>, T, Stack, Opts, Acc) -> - ?incomplete(zero, <<>>, T, Stack, Opts, Acc); -zero(Bin, T, Stack, Opts, Acc) -> - ?error([Bin, T, Stack, Opts, Acc]). +zero(<>, Out, [Acc, object|Stack], Opts) -> + ?event([end_object, format_number(Acc)], maybe_done, Rest, Out, Stack, Opts); +zero(<>, Out, [Acc, array|Stack], Opts) -> + ?event([end_array, format_number(Acc)], maybe_done, Rest, Out, Stack, Opts); +zero(<>, Out, [Acc, object|Stack], Opts) -> + ?event([format_number(Acc)], key, Rest, Out, [key|Stack], Opts); +zero(<>, Out, [Acc, array|Stack], Opts) -> + ?event([format_number(Acc)], value, Rest, Out, [array|Stack], Opts); +zero(<>, Out, [Acc|Stack], Opts) -> + initial_decimal(Rest, Out, [{Acc, []}|Stack], Opts); +zero(<>, Out, [Acc|Stack], Opts) when ?is_whitespace(S) -> + ?event([format_number(Acc)], maybe_done, Rest, Out, Stack, Opts); +zero(<<>>, Out, Stack, Opts) -> + ?incomplete(zero, <<>>, Out, Stack, Opts); +zero(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -integer(<>, T, Stack, Opts, Acc) when ?is_nonzero(S) -> - integer(Rest, T, Stack, Opts, [S] ++ Acc); -integer(<>, T, [object|Stack], Opts, Acc) -> - ?event([end_object, format_number(Acc)], maybe_done, Rest, T, Stack, Opts); -integer(<>, T, [array|Stack], Opts, Acc) -> - ?event([end_array, format_number(Acc)], maybe_done, Rest, T, Stack, Opts); -integer(<>, T, [object|Stack], Opts, Acc) -> - ?event([format_number(Acc)], key, Rest, T, [key|Stack], Opts); -integer(<>, T, [array|_] = Stack, Opts, Acc) -> - ?event([format_number(Acc)], value, Rest, T, Stack, Opts); -integer(<>, T, Stack, Opts, Acc) -> - initial_decimal(Rest, T, Stack, Opts, {Acc, []}); -integer(<>, T, Stack, Opts, Acc) -> - integer(Rest, T, Stack, Opts, [?zero] ++ Acc); -integer(<>, T, Stack, Opts, Acc) when S =:= $e; S =:= $E -> - e(Rest, T, Stack, Opts, {Acc, [], []}); -integer(<>, T, Stack, Opts, Acc) when ?is_whitespace(S) -> - ?event([format_number(Acc)], maybe_done, Rest, T, Stack, Opts); -integer(<<>>, T, Stack, Opts, Acc) -> - ?incomplete(integer, <<>>, T, Stack, Opts, Acc); -integer(Bin, T, Stack, Opts, Acc) -> - ?error([Bin, T, Stack, Opts, Acc]). +integer(<>, Out, [Acc|Stack], Opts) when ?is_nonzero(S) -> + integer(Rest, Out, [[S] ++ Acc|Stack], Opts); +integer(<>, Out, [Acc, object|Stack], Opts) -> + ?event([end_object, format_number(Acc)], maybe_done, Rest, Out, Stack, Opts); +integer(<>, Out, [Acc, array|Stack], Opts) -> + ?event([end_array, format_number(Acc)], maybe_done, Rest, Out, Stack, Opts); +integer(<>, Out, [Acc, object|Stack], Opts) -> + ?event([format_number(Acc)], key, Rest, Out, [key|Stack], Opts); +integer(<>, Out, [Acc, array|Stack], Opts) -> + ?event([format_number(Acc)], value, Rest, Out, [array|Stack], Opts); +integer(<>, Out, [Acc|Stack], Opts) -> + initial_decimal(Rest, Out, [{Acc, []}|Stack], Opts); +integer(<>, Out, [Acc|Stack], Opts) -> + integer(Rest, Out, [[?zero] ++ Acc|Stack], Opts); +integer(<>, Out, [Acc|Stack], Opts) when S =:= $e; S =:= $E -> + e(Rest, Out, [{Acc, [], []}|Stack], Opts); +integer(<>, Out, [Acc|Stack], Opts) when ?is_whitespace(S) -> + ?event([format_number(Acc)], maybe_done, Rest, Out, Stack, Opts); +integer(<<>>, Out, Stack, Opts) -> + ?incomplete(integer, <<>>, Out, Stack, Opts); +integer(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -initial_decimal(<>, T, Stack, Opts, {Int, Frac}) +initial_decimal(<>, Out, [{Int, Frac}|Stack], Opts) when S =:= ?zero; ?is_nonzero(S) -> - decimal(Rest, T, Stack, Opts, {Int, [S] ++ Frac}); -initial_decimal(<<>>, T, Stack, Opts, Acc) -> - ?incomplete(initial_decimal, <<>>, T, Stack, Opts, Acc); -initial_decimal(Bin, T, Stack, Opts, Acc) -> - ?error([Bin, T, Stack, Opts, Acc]). + decimal(Rest, Out, [{Int, [S] ++ Frac}|Stack], Opts); +initial_decimal(<<>>, Out, Stack, Opts) -> + ?incomplete(initial_decimal, <<>>, Out, Stack, Opts); +initial_decimal(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -decimal(<>, T, Stack, Opts, {Int, Frac}) +decimal(<>, Out, [{Int, Frac}|Stack], Opts) when S=:= ?zero; ?is_nonzero(S) -> - decimal(Rest, T, Stack, Opts, {Int, [S] ++ Frac}); -decimal(<>, T, [object|Stack], Opts, Acc) -> - ?event([end_object, format_number(Acc)], maybe_done, Rest, T, Stack, Opts); -decimal(<>, T, [array|Stack], Opts, Acc) -> - ?event([end_array, format_number(Acc)], maybe_done, Rest, T, Stack, Opts); -decimal(<>, T, [object|Stack], Opts, Acc) -> - ?event([format_number(Acc)], key, Rest, T, [key|Stack], Opts); -decimal(<>, T, [array|_] = Stack, Opts, Acc) -> - ?event([format_number(Acc)], value, Rest, T, Stack, Opts); -decimal(<>, T, Stack, Opts, {Int, Frac}) + decimal(Rest, Out, [{Int, [S] ++ Frac}|Stack], Opts); +decimal(<>, Out, [Acc, object|Stack], Opts) -> + ?event([end_object, format_number(Acc)], maybe_done, Rest, Out, Stack, Opts); +decimal(<>, Out, [Acc, array|Stack], Opts) -> + ?event([end_array, format_number(Acc)], maybe_done, Rest, Out, Stack, Opts); +decimal(<>, Out, [Acc, object|Stack], Opts) -> + ?event([format_number(Acc)], key, Rest, Out, [key|Stack], Opts); +decimal(<>, Out, [Acc, array|Stack], Opts) -> + ?event([format_number(Acc)], value, Rest, Out, [array|Stack], Opts); +decimal(<>, Out, [{Int, Frac}|Stack], Opts) when S =:= $e; S =:= $E -> - e(Rest, T, Stack, Opts, {Int, Frac, []}); -decimal(<>, T, Stack, Opts, Acc) when ?is_whitespace(S) -> - ?event([format_number(Acc)], maybe_done, Rest, T, Stack, Opts); -decimal(<<>>, T, Stack, Opts, Acc) -> - ?incomplete(decimal, <<>>, T, Stack, Opts, Acc); -decimal(Bin, T, Stack, Opts, Acc) -> - ?error([Bin, T, Stack, Opts, Acc]). + e(Rest, Out, [{Int, Frac, []}|Stack], Opts); +decimal(<>, Out, [Acc|Stack], Opts) when ?is_whitespace(S) -> + ?event([format_number(Acc)], maybe_done, Rest, Out, Stack, Opts); +decimal(<<>>, Out, Stack, Opts) -> + ?incomplete(decimal, <<>>, Out, Stack, Opts); +decimal(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -e(<>, T, Stack, Opts, {Int, Frac, Exp}) +e(<>, Out, [{Int, Frac, Exp}|Stack], Opts) when S =:= ?zero; ?is_nonzero(S) -> - exp(Rest, T, Stack, Opts, {Int, Frac, [S] ++ Exp}); -e(<>, T, Stack, Opts, {Int, Frac, Exp}) + exp(Rest, Out, [{Int, Frac, [S] ++ Exp}|Stack], Opts); +e(<>, Out, [{Int, Frac, Exp}|Stack], Opts) when S =:= ?positive; S =:= ?negative -> - ex(Rest, T, Stack, Opts, {Int, Frac, [S] ++ Exp}); -e(<<>>, T, Stack, Opts, Acc) -> - ?incomplete(e, <<>>, T, Stack, Opts, Acc); -e(Bin, T, Stack, Opts, Acc) -> - ?error([Bin, T, Stack, Opts, Acc]). + ex(Rest, Out, [{Int, Frac, [S] ++ Exp}|Stack], Opts); +e(<<>>, Out, Stack, Opts) -> + ?incomplete(e, <<>>, Out, Stack, Opts); +e(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -ex(<>, T, Stack, Opts, {Int, Frac, Exp}) +ex(<>, Out, [{Int, Frac, Exp}|Stack], Opts) when S =:= ?zero; ?is_nonzero(S) -> - exp(Rest, T, Stack, Opts, {Int, Frac, [S] ++ Exp}); -ex(<<>>, T, Stack, Opts, Acc) -> - ?incomplete(ex, <<>>, T, Stack, Opts, Acc); -ex(Bin, T, Stack, Opts, Acc) -> - ?error([Bin, T, Stack, Opts, Acc]). + exp(Rest, Out, [{Int, Frac, [S] ++ Exp}|Stack], Opts); +ex(<<>>, Out, Stack, Opts) -> + ?incomplete(ex, <<>>, Out, Stack, Opts); +ex(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -exp(<>, T, Stack, Opts, {Int, Frac, Exp}) +exp(<>, Out, [{Int, Frac, Exp}|Stack], Opts) when S =:= ?zero; ?is_nonzero(S) -> - exp(Rest, T, Stack, Opts, {Int, Frac, [S] ++ Exp}); -exp(<>, T, [object|Stack], Opts, Acc) -> - ?event([end_object, format_number(Acc)], maybe_done, Rest, T, Stack, Opts); -exp(<>, T, [array|Stack], Opts, Acc) -> - ?event([end_array, format_number(Acc)], maybe_done, Rest, T, Stack, Opts); -exp(<>, T, [object|Stack], Opts, Acc) -> - ?event([format_number(Acc)], key, Rest, T, [key|Stack], Opts); -exp(<>, T, [array|_] = Stack, Opts, Acc) -> - ?event([format_number(Acc)], value, Rest, T, Stack, Opts); -exp(<>, T, Stack, Opts, Acc) when ?is_whitespace(S) -> - ?event([format_number(Acc)], maybe_done, Rest, T, Stack, Opts); -exp(<<>>, T, Stack, Opts, Acc) -> - ?incomplete(exp, <<>>, T, Stack, Opts, Acc); -exp(Bin, T, Stack, Opts, Acc) -> - ?error([Bin, T, Stack, Opts, Acc]). + exp(Rest, Out, [{Int, Frac, [S] ++ Exp}|Stack], Opts); +exp(<>, Out, [Acc, object|Stack], Opts) -> + ?event([end_object, format_number(Acc)], maybe_done, Rest, Out, Stack, Opts); +exp(<>, Out, [Acc, array|Stack], Opts) -> + ?event([end_array, format_number(Acc)], maybe_done, Rest, Out, Stack, Opts); +exp(<>, Out, [Acc, object|Stack], Opts) -> + ?event([format_number(Acc)], key, Rest, Out, [key|Stack], Opts); +exp(<>, Out, [Acc, array|Stack], Opts) -> + ?event([format_number(Acc)], value, Rest, Out, [array|Stack], Opts); +exp(<>, Out, [Acc|Stack], Opts) when ?is_whitespace(S) -> + ?event([format_number(Acc)], maybe_done, Rest, Out, Stack, Opts); +exp(<<>>, Out, Stack, Opts) -> + ?incomplete(exp, <<>>, Out, Stack, Opts); +exp(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). format_number(Int) when is_list(Int) -> @@ -543,105 +543,105 @@ format_number({Int, Frac, Exp}) -> {float, list_to_float(lists:reverse(Exp ++ "e" ++ Frac ++ "." ++ Int))}. -tr(<<$r, Rest/binary>>, T, Stack, Opts) -> - tru(Rest, T, Stack, Opts); -tr(<<>>, T, Stack, Opts) -> - ?incomplete(tr, <<>>, T, Stack, Opts); -tr(Bin, T, Stack, Opts) -> - ?error([Bin, T, Stack, Opts]). +tr(<<$r, Rest/binary>>, Out, Stack, Opts) -> + tru(Rest, Out, Stack, Opts); +tr(<<>>, Out, Stack, Opts) -> + ?incomplete(tr, <<>>, Out, Stack, Opts); +tr(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -tru(<<$u, Rest/binary>>, T, Stack, Opts) -> - true(Rest, T, Stack, Opts); -tru(<<>>, T, Stack, Opts) -> - ?incomplete(tru, <<>>, T, Stack, Opts); -tru(Bin, T, Stack, Opts) -> - ?error([Bin, T, Stack, Opts]). +tru(<<$u, Rest/binary>>, Out, Stack, Opts) -> + true(Rest, Out, Stack, Opts); +tru(<<>>, Out, Stack, Opts) -> + ?incomplete(tru, <<>>, Out, Stack, Opts); +tru(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -true(<<$e, Rest/binary>>, T, Stack, Opts) -> - ?event([{literal, true}], maybe_done, Rest, T, Stack, Opts); -true(<<>>, T, Stack, Opts) -> - ?incomplete(true, <<>>, T, Stack, Opts); -true(Bin, T, Stack, Opts) -> - ?error([Bin, T, Stack, Opts]). +true(<<$e, Rest/binary>>, Out, Stack, Opts) -> + ?event([{literal, true}], maybe_done, Rest, Out, Stack, Opts); +true(<<>>, Out, Stack, Opts) -> + ?incomplete(true, <<>>, Out, Stack, Opts); +true(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -fa(<<$a, Rest/binary>>, T, Stack, Opts) -> - fal(Rest, T, Stack, Opts); -fa(<<>>, T, Stack, Opts) -> - ?incomplete(fa, <<>>, T, Stack, Opts); -fa(Bin, T, Stack, Opts) -> - ?error([Bin, T, Stack, Opts]). +fa(<<$a, Rest/binary>>, Out, Stack, Opts) -> + fal(Rest, Out, Stack, Opts); +fa(<<>>, Out, Stack, Opts) -> + ?incomplete(fa, <<>>, Out, Stack, Opts); +fa(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -fal(<<$l, Rest/binary>>, T, Stack, Opts) -> - fals(Rest, T, Stack, Opts); -fal(<<>>, T, Stack, Opts) -> - ?incomplete(fal, <<>>, T, Stack, Opts); -fal(Bin, T, Stack, Opts) -> - ?error([Bin, T, Stack, Opts]). +fal(<<$l, Rest/binary>>, Out, Stack, Opts) -> + fals(Rest, Out, Stack, Opts); +fal(<<>>, Out, Stack, Opts) -> + ?incomplete(fal, <<>>, Out, Stack, Opts); +fal(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -fals(<<$s, Rest/binary>>, T, Stack, Opts) -> - false(Rest, T, Stack, Opts); -fals(<<>>, T, Stack, Opts) -> - ?incomplete(fals, <<>>, T, Stack, Opts); -fals(Bin, T, Stack, Opts) -> - ?error([Bin, T, Stack, Opts]). +fals(<<$s, Rest/binary>>, Out, Stack, Opts) -> + false(Rest, Out, Stack, Opts); +fals(<<>>, Out, Stack, Opts) -> + ?incomplete(fals, <<>>, Out, Stack, Opts); +fals(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -false(<<$e, Rest/binary>>, T, Stack, Opts) -> - ?event([{literal, false}], maybe_done, Rest, T, Stack, Opts); -false(<<>>, T, Stack, Opts) -> - ?incomplete(false, <<>>, T, Stack, Opts); -false(Bin, T, Stack, Opts) -> - ?error([Bin, T, Stack, Opts]). +false(<<$e, Rest/binary>>, Out, Stack, Opts) -> + ?event([{literal, false}], maybe_done, Rest, Out, Stack, Opts); +false(<<>>, Out, Stack, Opts) -> + ?incomplete(false, <<>>, Out, Stack, Opts); +false(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -nu(<<$u, Rest/binary>>, T, Stack, Opts) -> - nul(Rest, T, Stack, Opts); -nu(<<>>, T, Stack, Opts) -> - ?incomplete(nu, <<>>, T, Stack, Opts); -nu(Bin, T, Stack, Opts) -> - ?error([Bin, T, Stack, Opts]). +nu(<<$u, Rest/binary>>, Out, Stack, Opts) -> + nul(Rest, Out, Stack, Opts); +nu(<<>>, Out, Stack, Opts) -> + ?incomplete(nu, <<>>, Out, Stack, Opts); +nu(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -nul(<<$l, Rest/binary>>, T, Stack, Opts) -> - null(Rest, T, Stack, Opts); -nul(<<>>, T, Stack, Opts) -> - ?incomplete(nul, <<>>, T, Stack, Opts); -nul(Bin, T, Stack, Opts) -> - ?error([Bin, T, Stack, Opts]). +nul(<<$l, Rest/binary>>, Out, Stack, Opts) -> + null(Rest, Out, Stack, Opts); +nul(<<>>, Out, Stack, Opts) -> + ?incomplete(nul, <<>>, Out, Stack, Opts); +nul(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -null(<<$l, Rest/binary>>, T, Stack, Opts) -> - ?event([{literal, null}], maybe_done, Rest, T, Stack, Opts); -null(<<>>, T, Stack, Opts) -> - ?incomplete(null, <<>>, T, Stack, Opts); -null(Bin, T, Stack, Opts) -> - ?error([Bin, T, Stack, Opts]). +null(<<$l, Rest/binary>>, Out, Stack, Opts) -> + ?event([{literal, null}], maybe_done, Rest, Out, Stack, Opts); +null(<<>>, Out, Stack, Opts) -> + ?incomplete(null, <<>>, Out, Stack, Opts); +null(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -maybe_done(<>, T, [object|Stack], Opts) -> - ?event([end_object], maybe_done, Rest, T, Stack, Opts); -maybe_done(<>, T, [array|Stack], Opts) -> - ?event([end_array], maybe_done, Rest, T, Stack, Opts); -maybe_done(<>, T, [object|Stack], Opts) -> - key(Rest, T, [key|Stack], Opts); -maybe_done(<>, T, [array|_] = Stack, Opts) -> - value(Rest, T, Stack, Opts); -maybe_done(<>, T, Stack, Opts) when ?is_whitespace(S) -> - maybe_done(Rest, T, Stack, Opts); -maybe_done(<<>>, T, Stack, Opts) when length(Stack) > 0 -> - ?incomplete(maybe_done, <<>>, T, Stack, Opts); -maybe_done(Rest, T, [], Opts) -> - ?event([end_json], done, Rest, T, [], Opts); -maybe_done(Bin, T, Stack, Opts) -> - ?error([Bin, T, Stack, Opts]). +maybe_done(<>, Out, [object|Stack], Opts) -> + ?event([end_object], maybe_done, Rest, Out, Stack, Opts); +maybe_done(<>, Out, [array|Stack], Opts) -> + ?event([end_array], maybe_done, Rest, Out, Stack, Opts); +maybe_done(<>, Out, [object|Stack], Opts) -> + key(Rest, Out, [key|Stack], Opts); +maybe_done(<>, Out, [array|_] = Stack, Opts) -> + value(Rest, Out, Stack, Opts); +maybe_done(<>, Out, Stack, Opts) when ?is_whitespace(S) -> + maybe_done(Rest, Out, Stack, Opts); +maybe_done(<<>>, Out, Stack, Opts) when length(Stack) > 0 -> + ?incomplete(maybe_done, <<>>, Out, Stack, Opts); +maybe_done(Rest, Out, [], Opts) -> + ?event([end_json], done, Rest, Out, [], Opts); +maybe_done(Bin, Out, Stack, Opts) -> + ?error([Bin, Out, Stack, Opts]). -done(<>, T, [], Opts) when ?is_whitespace(S) -> - done(Rest, T, [], Opts); -done(<<>>, T, [], Opts) -> ?incomplete(done, <<>>, T, [], Opts); -done(Bin, T, [], Opts) -> ?error([Bin, T, [], Opts]). \ No newline at end of file +done(<>, Out, [], Opts) when ?is_whitespace(S) -> + done(Rest, Out, [], Opts); +done(<<>>, Out, [], Opts) -> ?incomplete(done, <<>>, Out, [], Opts); +done(Bin, Out, Stack, Opts) -> ?error([Bin, Out, Stack, Opts]). \ No newline at end of file