diff --git a/src/jsx_decoder.hrl b/src/jsx_decoder.hrl index 537fb84..0e60ea0 100644 --- a/src/jsx_decoder.hrl +++ b/src/jsx_decoder.hrl @@ -26,6 +26,18 @@ %% this file should take that into account +%% exported solely to facilitate stupid trick i shouldn't be using +-export([start/4, + maybe_done/4, + done/3, + object/4, + array/4, + value/4, + colon/4, + key/4 +]). + + -export([decoder/1]). -spec decoder(OptsList::jsx_opts()) -> jsx_decoder(). @@ -33,7 +45,7 @@ decoder(OptsList) -> case parse_opts(OptsList) of {error, badopt} -> {error, badopt} - ; Opts -> fun(JSON) -> start(JSON, [], Opts) end + ; Opts -> fun(JSON) -> start(JSON, iterate, [], Opts) end end. @@ -219,140 +231,148 @@ partial_utf(_) -> false. %% emit takes a list of `events` to present to client code and formats them %% appropriately -emit([Event], F) -> {jsx, Event, F}; -emit([Event|Rest], F) -> {jsx, Event, fun() -> emit(Rest, F) end}. +emit([incomplete], {State, Rest, iterate, Args}) -> + {jsx, incomplete, fun(end_stream) -> + {error, {badjson, <<>>}} + ; (Stream) -> + erlang:apply(?MODULE, + State, + [<>, iterate] ++ Args + ) + end}; +emit([Event], {State, Rest, iterate, Args}) -> + {jsx, Event, fun() -> + erlang:apply(?MODULE, State, [Rest, iterate] ++ Args) + end}; +emit([Event|Rest], {_State, _Rest, iterate, _Args} = Next) -> + {jsx, Event, fun() -> emit(Rest, Next) end}. -start(<>, Stack, Opts) when ?is_whitespace(S) -> - start(Rest, Stack, Opts); -start(<>, Stack, Opts) -> - emit([start_object], fun() -> object(Rest, [key|Stack], Opts) end); -start(<>, Stack, Opts) -> - emit([start_array], fun() -> array(Rest, [array|Stack], Opts) end); -start(<>, Stack, Opts) -> - string(Rest, Stack, Opts); -start(<<$t/?utfx, Rest/binary>>, Stack, Opts) -> - tr(Rest, Stack, Opts); -start(<<$f/?utfx, Rest/binary>>, Stack, Opts) -> - fa(Rest, Stack, Opts); -start(<<$n/?utfx, Rest/binary>>, Stack, Opts) -> - nu(Rest, Stack, Opts); -start(<>, Stack, Opts) -> - negative(Rest, Stack, Opts, "-"); -start(<>, Stack, Opts) -> - zero(Rest, Stack, Opts, "0"); -start(<>, Stack, Opts) when ?is_nonzero(S) -> - integer(Rest, Stack, Opts, [S]); -start(Bin, Stack, Opts) -> - ?incomplete(start(<>, Stack, Opts)). + +start(<>, T, Stack, Opts) when ?is_whitespace(S) -> + start(Rest, T, Stack, Opts); +start(<>, T, Stack, Opts) -> + emit([start_object], {object, Rest, T, [[key|Stack], Opts]}); +start(<>, T, Stack, Opts) -> + emit([start_array], {array, Rest, T, [[array|Stack], Opts]}); +start(<>, T, Stack, Opts) -> + string(Rest, T, Stack, Opts); +start(<<$t/?utfx, Rest/binary>>, T, Stack, Opts) -> + tr(Rest, T, Stack, Opts); +start(<<$f/?utfx, Rest/binary>>, T, Stack, Opts) -> + fa(Rest, T, Stack, Opts); +start(<<$n/?utfx, 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(Bin, T, Stack, Opts) -> + ?incomplete(start(<>, T, Stack, Opts)). -maybe_done(<>, Stack, Opts) when ?is_whitespace(S) -> - maybe_done(Rest, Stack, Opts); -maybe_done(<>, [object|Stack], Opts) -> - emit([end_object], fun() -> maybe_done(Rest, Stack, Opts) end); -maybe_done(<>, [array|Stack], Opts) -> - emit([end_array], fun() -> maybe_done(Rest, Stack, Opts) end); -maybe_done(<>, [object|Stack], Opts) -> - key(Rest, [key|Stack], Opts); -maybe_done(<>, [array|_] = Stack, Opts) -> - value(Rest, Stack, Opts); -maybe_done(Rest, [], #opts{multi_term=true}=Opts) -> - emit([end_json], fun() -> start(Rest, [], Opts) end); -maybe_done(Rest, [], Opts) -> - done(Rest, Opts); -maybe_done(Bin, Stack, Opts) -> - ?incomplete(maybe_done(<>, Stack, Opts)). +maybe_done(<>, T, Stack, Opts) when ?is_whitespace(S) -> + maybe_done(Rest, T, Stack, Opts); +maybe_done(<>, T, [object|Stack], Opts) -> + emit([end_object], {maybe_done, Rest, T, [Stack, Opts]}); +maybe_done(<>, T, [array|Stack], Opts) -> + emit([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(Rest, T, [], #opts{multi_term=true}=Opts) -> + emit([end_json], {start, Rest, T, [[], Opts]}); +maybe_done(Rest, T, [], Opts) -> + done(Rest, T, Opts); +maybe_done(Bin, T, Stack, Opts) -> + ?incomplete(maybe_done(<>, T, Stack, Opts)). -done(<>, Opts) when ?is_whitespace(S) -> - done(Rest, Opts); -done(<<>>, Opts) -> - emit([end_json], fun() -> - {jsx, incomplete, fun(end_stream) -> - {error, {badjson, <<>>}} - ; (Stream) -> - done(Stream, Opts) - end} - end); -done(Bin, Opts) -> - ?incomplete(done(<>, Opts)). +done(<>, T, Opts) when ?is_whitespace(S) -> + done(Rest, T, Opts); +done(<<>>, T, Opts) -> + emit([end_json, incomplete], {done, <<>>, T, [Opts]}); +done(Bin, T, Opts) -> + ?incomplete(done(<>, T, Opts)). -object(<>, Stack, Opts) when ?is_whitespace(S) -> - object(Rest, Stack, Opts); -object(<>, Stack, Opts) -> - string(Rest, Stack, Opts); -object(<>, [key|Stack], Opts) -> - emit([end_object], fun() -> maybe_done(Rest, Stack, Opts) end); -object(Bin, Stack, Opts) -> - ?incomplete(object(<>, Stack, Opts)). +object(<>, T, Stack, Opts) when ?is_whitespace(S) -> + object(Rest, T, Stack, Opts); +object(<>, T, Stack, Opts) -> + string(Rest, T, Stack, Opts); +object(<>, T, [key|Stack], Opts) -> + emit([end_object], {maybe_done, Rest, T, [Stack, Opts]}); +object(Bin, T, Stack, Opts) -> + ?incomplete(object(<>, T, Stack, Opts)). -array(<>, Stack, Opts) when ?is_whitespace(S) -> - array(Rest, Stack, Opts); -array(<>, Stack, Opts) -> - string(Rest, Stack, Opts); -array(<<$t/?utfx, Rest/binary>>, Stack, Opts) -> - tr(Rest, Stack, Opts); -array(<<$f/?utfx, Rest/binary>>, Stack, Opts) -> - fa(Rest, Stack, Opts); -array(<<$n/?utfx, Rest/binary>>, Stack, Opts) -> - nu(Rest, Stack, Opts); -array(<>, Stack, Opts) -> - negative(Rest, Stack, Opts, "-"); -array(<>, Stack, Opts) -> - zero(Rest, Stack, Opts, "0"); -array(<>, Stack, Opts) when ?is_nonzero(S) -> - integer(Rest, Stack, Opts, [S]); -array(<>, Stack, Opts) -> - emit([start_object], fun() -> object(Rest, [key|Stack], Opts) end); -array(<>, Stack, Opts) -> - emit([start_array], fun() -> array(Rest, [array|Stack], Opts) end); -array(<>, [array|Stack], Opts) -> - emit([end_array], fun() -> maybe_done(Rest, Stack, Opts) end); -array(Bin, Stack, Opts) -> - ?incomplete(array(<>, Stack, Opts)). +array(<>, T, Stack, Opts) when ?is_whitespace(S) -> + array(Rest, T, Stack, Opts); +array(<>, T, Stack, Opts) -> + string(Rest, T, Stack, Opts); +array(<<$t/?utfx, Rest/binary>>, T, Stack, Opts) -> + tr(Rest, T, Stack, Opts); +array(<<$f/?utfx, Rest/binary>>, T, Stack, Opts) -> + fa(Rest, T, Stack, Opts); +array(<<$n/?utfx, 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) -> + emit([start_object], {object, Rest, T, [[key|Stack], Opts]}); +array(<>, T, Stack, Opts) -> + emit([start_array], {array, Rest, T, [[array|Stack], Opts]}); +array(<>, T, [array|Stack], Opts) -> + emit([end_array], {maybe_done, Rest, T, [Stack, Opts]}); +array(Bin, T, Stack, Opts) -> + ?incomplete(array(<>, T, Stack, Opts)). -value(<>, Stack, Opts) when ?is_whitespace(S) -> - value(Rest, Stack, Opts); -value(<>, Stack, Opts) -> - string(Rest, Stack, Opts); -value(<<$t/?utfx, Rest/binary>>, Stack, Opts) -> - tr(Rest, Stack, Opts); -value(<<$f/?utfx, Rest/binary>>, Stack, Opts) -> - fa(Rest, Stack, Opts); -value(<<$n/?utfx, Rest/binary>>, Stack, Opts) -> - nu(Rest, Stack, Opts); -value(<>, Stack, Opts) -> - negative(Rest, Stack, Opts, "-"); -value(<>, Stack, Opts) -> - zero(Rest, Stack, Opts, "0"); -value(<>, Stack, Opts) when ?is_nonzero(S) -> - integer(Rest, Stack, Opts, [S]); -value(<>, Stack, Opts) -> - emit([start_object], fun() -> object(Rest, [key|Stack], Opts) end); -value(<>, Stack, Opts) -> - emit([start_array], fun() -> array(Rest, [array|Stack], Opts) end); -value(Bin, Stack, Opts) -> - ?incomplete(value(<>, Stack, Opts)). +value(<>, T, Stack, Opts) when ?is_whitespace(S) -> + value(Rest, T, Stack, Opts); +value(<>, T, Stack, Opts) -> + string(Rest, T, Stack, Opts); +value(<<$t/?utfx, Rest/binary>>, T, Stack, Opts) -> + tr(Rest, T, Stack, Opts); +value(<<$f/?utfx, Rest/binary>>, T, Stack, Opts) -> + fa(Rest, T, Stack, Opts); +value(<<$n/?utfx, 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) -> + emit([start_object], {object, Rest, T, [[key|Stack], Opts]}); +value(<>, T, Stack, Opts) -> + emit([start_array], {array, Rest, T, [[array|Stack], Opts]}); +value(Bin, T, Stack, Opts) -> + ?incomplete(value(<>, T, Stack, Opts)). -colon(<>, Stack, Opts) when ?is_whitespace(S) -> - colon(Rest, Stack, Opts); -colon(<>, [key|Stack], Opts) -> - value(Rest, [object|Stack], Opts); -colon(Bin, Stack, Opts) -> - ?incomplete(colon(<>, Stack, Opts)). +colon(<>, T, Stack, Opts) when ?is_whitespace(S) -> + colon(Rest, T, Stack, Opts); +colon(<>, T, [key|Stack], Opts) -> + value(Rest, T, [object|Stack], Opts); +colon(Bin, T, Stack, Opts) -> + ?incomplete(colon(<>, T, Stack, Opts)). -key(<>, Stack, Opts) when ?is_whitespace(S) -> - key(Rest, Stack, Opts); -key(<>, Stack, Opts) -> - string(Rest, Stack, Opts); -key(Bin, Stack, Opts) -> - ?incomplete(key(<>, Stack, Opts)). +key(<>, T, Stack, Opts) when ?is_whitespace(S) -> + key(Rest, T, Stack, Opts); +key(<>, T, Stack, Opts) -> + string(Rest, T, Stack, Opts); +key(Bin, T, Stack, Opts) -> + ?incomplete(key(<>, T, Stack, Opts)). %% string has an additional parameter, an accumulator (Acc) used to hold the @@ -362,28 +382,26 @@ key(Bin, Stack, Opts) -> %% 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 -string(Bin, Stack, Opts) -> string(Bin, Stack, Opts, []). +string(Bin, T, Stack, Opts) -> string(Bin, T, Stack, Opts, []). -string(<>, [key|_] = Stack, Opts, Acc) -> - emit([{key, lists:reverse(Acc)}], fun() -> colon(Rest, Stack, Opts) end); -string(<>, Stack, Opts, Acc) -> - emit([{string, lists:reverse(Acc)}], fun() -> - maybe_done(Rest, Stack, Opts) - end); -string(<>, Stack, Opts, Acc) -> - escape(Rest, Stack, Opts, Acc); +string(<>, T, [key|_] = Stack, Opts, Acc) -> + emit([{key, lists:reverse(Acc)}], {colon, Rest, T, [Stack, Opts]}); +string(<>, T, Stack, Opts, Acc) -> + emit([{string, lists:reverse(Acc)}], {maybe_done, Rest, T, [Stack, Opts]}); +string(<>, T, Stack, Opts, Acc) -> + escape(Rest, T, Stack, Opts, Acc); %% 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(<>, Stack, Opts, Acc) +string(<>, T, Stack, Opts, Acc) when ?is_noncontrol(S), S < 16#fdd0 -> - string(Rest, Stack, Opts, [S] ++ Acc); + string(Rest, T, Stack, Opts, [S] ++ Acc); %% the range 16#fdf0..16#fffd is also safe -string(<>, Stack, Opts, Acc) +string(<>, T, Stack, Opts, Acc) when S > 16#fdef, S < 16#fffe -> - string(Rest, Stack, Opts, [S] ++ Acc); + string(Rest, T, Stack, Opts, [S] ++ Acc); %% yes, i think it's insane too -string(<>, Stack, Opts, Acc) +string(<>, T, Stack, Opts, Acc) when S > 16#ffff andalso S =/= 16#1fffe andalso S =/= 16#1ffff andalso S =/= 16#2fffe andalso S =/= 16#2ffff andalso @@ -401,18 +419,18 @@ string(<>, 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, Stack, Opts, [S] ++ Acc); -string(Bin, Stack, Opts, Acc) -> + string(Rest, T, Stack, Opts, [S] ++ Acc); +string(Bin, T, Stack, Opts, Acc) -> case partial_utf(Bin) of true -> {jsx, incomplete, fun(end_stream) -> {error, {badjson, Bin}} ; (Stream) -> - string(<>, Stack, Opts, Acc) + string(<>, T, Stack, Opts, Acc) end} ; false -> case Opts#opts.loose_unicode of - true -> noncharacter(Bin, Stack, Opts, Acc) + true -> noncharacter(Bin, T, Stack, Opts, Acc) ; false -> {error, {badjson, Bin}} end end. @@ -423,85 +441,85 @@ string(Bin, Stack, Opts, Acc) -> %% unreachable -ifdef(utf8). %% non-characters erlang doesn't recognize as non-characters, idiotically -noncharacter(<>, Stack, Opts, Acc) +noncharacter(<>, T, Stack, Opts, Acc) when ?is_noncontrol(S) -> - string(Rest, Stack, Opts, [16#fffd] ++ Acc); + string(Rest, T, Stack, Opts, [16#fffd] ++ Acc); %% u+fffe and u+ffff -noncharacter(<<239, 191, X, Rest/binary>>, Stack, Opts, Acc) +noncharacter(<<239, 191, X, Rest/binary>>, T, Stack, Opts, Acc) when X == 190; X == 191 -> - string(Rest, Stack, Opts, [16#fffd] ++ Acc); + string(Rest, T, Stack, Opts, [16#fffd] ++ Acc); %% surrogates -noncharacter(<<237, X, _, Rest/binary>>, Stack, Opts, Acc) when X >= 160 -> - string(Rest, Stack, Opts, [16#fffd] ++ Acc); -noncharacter(Bin, _Stack, _Opts, _Acc) -> +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, {badjson, Bin}}. -endif. -ifdef(utf16). %% non-characters blah blah -noncharacter(<>, Stack, Opts, Acc) +noncharacter(<>, T, Stack, Opts, Acc) when ?is_noncontrol(S) -> - string(Rest, Stack, Opts, [16#fffd] ++ Acc); + string(Rest, T, Stack, Opts, [16#fffd] ++ Acc); %% u+ffff and u+fffe -noncharacter(<<255, X, Rest/binary>>, Stack, Opts, Acc) +noncharacter(<<255, X, Rest/binary>>, T, Stack, Opts, Acc) when X == 254; X == 255 -> - string(Rest, Stack, Opts, [16#fffd] ++ Acc); + string(Rest, T, Stack, Opts, [16#fffd] ++ Acc); %% surrogates -noncharacter(<>, Stack, Opts, Acc) +noncharacter(<>, T, Stack, Opts, Acc) when X >= 216, X =< 223 -> - string(Rest, Stack, Opts, [16#fffd] ++ Acc); -noncharacter(Bin, _Stack, _Opts, _Acc) -> + string(Rest, T, Stack, Opts, [16#fffd] ++ Acc); +noncharacter(Bin, _T, _Stack, _Opts, _Acc) -> {error, {badjson, Bin}}. -endif. -ifdef(utf16le). %% non-characters blah blah -noncharacter(<>, Stack, Opts, Acc) +noncharacter(<>, T, Stack, Opts, Acc) when ?is_noncontrol(S) -> - string(Rest, Stack, Opts, [16#fffd] ++ Acc); + string(Rest, T, Stack, Opts, [16#fffd] ++ Acc); %% u+ffff and u+fffe -noncharacter(<>, Stack, Opts, Acc) +noncharacter(<>, T, Stack, Opts, Acc) when X == 254; X == 255 -> - string(Rest, Stack, Opts, [16#fffd] ++ Acc); + string(Rest, T, Stack, Opts, [16#fffd] ++ Acc); %% surrogates -noncharacter(<<_, X, Rest/binary>>, Stack, Opts, Acc) +noncharacter(<<_, X, Rest/binary>>, T, Stack, Opts, Acc) when X >= 216, X =< 223 -> - string(Rest, Stack, Opts, [16#fffd] ++ Acc); -noncharacter(Bin, _Stack, _Opts, _Acc) -> + string(Rest, T, Stack, Opts, [16#fffd] ++ Acc); +noncharacter(Bin, _T, _Stack, _Opts, _Acc) -> {error, {badjson, Bin}}. -endif. -ifdef(utf32). %% non-characters blah blah -noncharacter(<>, Stack, Opts, Acc) +noncharacter(<>, T, Stack, Opts, Acc) when ?is_noncontrol(S) -> - string(Rest, Stack, Opts, [16#fffd] ++ Acc); + string(Rest, T, Stack, Opts, [16#fffd] ++ Acc); %% u+ffff and u+fffe -noncharacter(<<0, 0, 255, X, Rest/binary>>, Stack, Opts, Acc) +noncharacter(<<0, 0, 255, X, Rest/binary>>, T, Stack, Opts, Acc) when X == 254; X == 255 -> - string(Rest, Stack, Opts, [16#fffd] ++ Acc); + string(Rest, T, Stack, Opts, [16#fffd] ++ Acc); %% surrogates -noncharacter(<<0, 0, X, _, Rest/binary>>, Stack, Opts, Acc) +noncharacter(<<0, 0, X, _, Rest/binary>>, T, Stack, Opts, Acc) when X >= 216, X =< 223 -> - string(Rest, Stack, Opts, [16#fffd] ++ Acc); -noncharacter(Bin, _Stack, _Opts, _Acc) -> + string(Rest, T, Stack, Opts, [16#fffd] ++ Acc); +noncharacter(Bin, _T, _Stack, _Opts, _Acc) -> {error, {badjson, Bin}}. -endif. -ifdef(utf32le). %% non-characters blah blah -noncharacter(<>, Stack, Opts, Acc) +noncharacter(<>, T, Stack, Opts, Acc) when ?is_noncontrol(S) -> - string(Rest, Stack, Opts, [16#fffd] ++ Acc); + string(Rest, T, Stack, Opts, [16#fffd] ++ Acc); %% u+ffff and u+fffe -noncharacter(<>, Stack, Opts, Acc) +noncharacter(<>, T, Stack, Opts, Acc) when X == 254; X == 255 -> - string(Rest, Stack, Opts, [16#fffd] ++ Acc); + string(Rest, T, Stack, Opts, [16#fffd] ++ Acc); %% surrogates -noncharacter(<<_, X, 0, 0, Rest/binary>>, Stack, Opts, Acc) +noncharacter(<<_, X, 0, 0, Rest/binary>>, T, Stack, Opts, Acc) when X >= 216, X =< 223 -> - string(Rest, Stack, Opts, [16#fffd] ++ Acc); -noncharacter(Bin, _Stack, _Opts, _Acc) -> + string(Rest, T, Stack, Opts, [16#fffd] ++ Acc); +noncharacter(Bin, _T, _Stack, _Opts, _Acc) -> {error, {badjson, Bin}}. -endif. @@ -509,38 +527,38 @@ noncharacter(Bin, _Stack, _Opts, _Acc) -> %% only thing to note here is the additional accumulator passed to %% escaped_unicode used to hold the codepoint sequence. unescessary, but nicer %% than using the string accumulator -escape(<<$b/?utfx, Rest/binary>>, Stack, Opts, Acc) -> - string(Rest, Stack, Opts, "\b" ++ Acc); -escape(<<$f/?utfx, Rest/binary>>, Stack, Opts, Acc) -> - string(Rest, Stack, Opts, "\f" ++ Acc); -escape(<<$n/?utfx, Rest/binary>>, Stack, Opts, Acc) -> - string(Rest, Stack, Opts, "\n" ++ Acc); -escape(<<$r/?utfx, Rest/binary>>, Stack, Opts, Acc) -> - string(Rest, Stack, Opts, "\r" ++ Acc); -escape(<<$t/?utfx, Rest/binary>>, Stack, Opts, Acc) -> - string(Rest, Stack, Opts, "\t" ++ Acc); -escape(<<$u/?utfx, Rest/binary>>, Stack, Opts, Acc) -> - escaped_unicode(Rest, Stack, Opts, Acc, []); -escape(<>, Stack, Opts, Acc) +escape(<<$b/?utfx, Rest/binary>>, T, Stack, Opts, Acc) -> + string(Rest, T, Stack, Opts, "\b" ++ Acc); +escape(<<$f/?utfx, Rest/binary>>, T, Stack, Opts, Acc) -> + string(Rest, T, Stack, Opts, "\f" ++ Acc); +escape(<<$n/?utfx, Rest/binary>>, T, Stack, Opts, Acc) -> + string(Rest, T, Stack, Opts, "\n" ++ Acc); +escape(<<$r/?utfx, Rest/binary>>, T, Stack, Opts, Acc) -> + string(Rest, T, Stack, Opts, "\r" ++ Acc); +escape(<<$t/?utfx, Rest/binary>>, T, Stack, Opts, Acc) -> + string(Rest, T, Stack, Opts, "\t" ++ Acc); +escape(<<$u/?utfx, Rest/binary>>, T, Stack, Opts, Acc) -> + escaped_unicode(Rest, T, Stack, Opts, Acc, []); +escape(<>, T, Stack, Opts, Acc) when S =:= ?quote; S =:= ?solidus; S =:= ?rsolidus -> - string(Rest, Stack, Opts, [S] ++ Acc); -escape(Bin, Stack, Opts, Acc) -> - ?incomplete(escape(<>, Stack, Opts, Acc)). + string(Rest, T, Stack, Opts, [S] ++ Acc); +escape(Bin, T, Stack, Opts, Acc) -> + ?incomplete(escape(<>, T, Stack, Opts, Acc)). %% this code is ugly and unfortunate, but so is json's handling of escaped %% unicode codepoint sequences. -escaped_unicode(<>, Stack, Opts, String, [C, B, A]) +escaped_unicode(<>, T, Stack, Opts, String, [C, B, A]) 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, Stack, Opts, String, X) + low_surrogate(Rest, T, Stack, Opts, String, X) %% 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, Stack, Opts, [16#fffd] ++ String) + string(Rest, T, Stack, Opts, [16#fffd] ++ String) ; false -> {error, {badjson, <>}} end @@ -549,48 +567,49 @@ escaped_unicode(<>, Stack, Opts, String, [C, B, A]) ; X when X == 16#0000 -> case Opts#opts.loose_unicode of true -> - string(Rest, Stack, Opts, [16#fffd] ++ String) + string(Rest, T, Stack, Opts, [16#fffd] ++ String) ; false -> {error, {badjson, <>}} end %% anything else ; X -> - string(Rest, Stack, Opts, [X] ++ String) + string(Rest, T, Stack, Opts, [X] ++ String) end; -escaped_unicode(<>, Stack, Opts, String, Acc) +escaped_unicode(<>, T, Stack, Opts, String, Acc) when ?is_hex(S) -> - escaped_unicode(Rest, Stack, Opts, String, [S] ++ Acc); -escaped_unicode(Bin, Stack, Opts, String, Acc) -> + escaped_unicode(Rest, T, Stack, Opts, String, [S] ++ Acc); +escaped_unicode(Bin, T, Stack, Opts, String, Acc) -> ?incomplete( - escaped_unicode(<>, Stack, Opts, String, Acc) + escaped_unicode(<>, T, Stack, Opts, String, Acc) ). -low_surrogate(<>, Stack, Opts, String, High) -> - low_surrogate_u(Rest, Stack, Opts, String, High); +low_surrogate(<>, T, Stack, Opts, String, High) -> + low_surrogate_u(Rest, T, Stack, Opts, String, High); %% not an escaped codepoint, our high codepoint is illegal. dispatch back to %% string to handle -low_surrogate(<> = Bin, Stack, Opts, String, _) -> +low_surrogate(<> = Bin, T, Stack, Opts, String, _) -> case Opts#opts.loose_unicode of true -> - string(Bin, Stack, Opts, [16#fffd] ++ String) + string(Bin, T, Stack, Opts, [16#fffd] ++ String) ; false -> {error, {badjson, <>}} end; -low_surrogate(Bin, Stack, Opts, String, High) -> +low_surrogate(Bin, T, Stack, Opts, String, High) -> ?incomplete( - low_surrogate(<>, Stack, Opts, String, High) + low_surrogate(<>, T, Stack, Opts, String, High) ). -low_surrogate_u(<<$u/?utfx, Rest/binary>>, Stack, Opts, String, H) -> - low_surrogate(Rest, Stack, Opts, String, [], H); +low_surrogate_u(<<$u/?utfx, Rest/binary>>, T, Stack, Opts, String, H) -> + low_surrogate(Rest, T, Stack, Opts, String, [], H); %% not a low surrogate, dispatch back to string to handle, including the %% rsolidus we parsed previously -low_surrogate_u(<> = Bin, Stack, Opts, String, _) -> +low_surrogate_u(<> = Bin, T, Stack, Opts, String, _) -> case Opts#opts.loose_unicode of true -> string(<>, + T, Stack, Opts, [16#fffd] ++ String @@ -598,13 +617,13 @@ low_surrogate_u(<> = Bin, Stack, Opts, String, _) -> ; false -> {error, {badjson, <>}} end; -low_surrogate_u(Bin, Stack, Opts, String, H) -> +low_surrogate_u(Bin, T, Stack, Opts, String, H) -> ?incomplete( - low_surrogate_u(<>, Stack, Opts, String, H) + low_surrogate_u(<>, T, Stack, Opts, String, H) ). -low_surrogate(<>, Stack, Opts, String, [C, B, A], H) +low_surrogate(<>, T, Stack, Opts, String, [C, B, A], H) when ?is_hex(D) -> case erlang:list_to_integer([A, B, C, D], 16) of X when X >= 16#dc00, X =< 16#dfff -> @@ -612,29 +631,29 @@ low_surrogate(<>, Stack, Opts, String, [C, B, A], H) case V rem 16#10000 of Y when Y == 16#fffe; Y == 16#ffff -> case Opts#opts.loose_unicode of true -> - string(Rest, Stack, Opts, [16#fffd] ++ String) + string(Rest, T, Stack, Opts, [16#fffd] ++ String) ; false -> {error, {badjson, <>}} end ; _ -> - string(Rest, Stack, Opts, [V] ++ String) + string(Rest, T, Stack, Opts, [V] ++ String) end %% not a low surrogate, bad bad bad ; _ -> case Opts#opts.loose_unicode of true -> - string(Rest, Stack, Opts, [16#fffd, 16#fffd] ++ String) + string(Rest, T, Stack, Opts, [16#fffd, 16#fffd] ++ String) ; false -> {error, {badjson, <>}} end end; -low_surrogate(<>, Stack, Opts, String, Acc, H) +low_surrogate(<>, T, Stack, Opts, String, Acc, H) when ?is_hex(S) -> - low_surrogate(Rest, Stack, Opts, String, [S] ++ Acc, H); -low_surrogate(Bin, Stack, Opts, String, Acc, H) -> + low_surrogate(Rest, T, Stack, Opts, String, [S] ++ Acc, H); +low_surrogate(Bin, T, Stack, Opts, String, Acc, H) -> ?incomplete( low_surrogate( - <>, Stack, Opts, String, Acc, H + <>, T, Stack, Opts, String, Acc, H ) ). @@ -646,153 +665,137 @@ surrogate_to_codepoint(High, Low) -> %% like strings, numbers are collected in an intermediate accumulator before %% being emitted to the callback handler -negative(<<$0/?utfx, Rest/binary>>, Stack, Opts, Acc) -> - zero(Rest, Stack, Opts, "0" ++ Acc); -negative(<>, Stack, Opts, Acc) when ?is_nonzero(S) -> - integer(Rest, Stack, Opts, [S] ++ Acc); -negative(Bin, Stack, Opts, Acc) -> - ?incomplete(negative(<>, Stack, Opts, Acc)). +negative(<<$0/?utfx, 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(Bin, T, Stack, Opts, Acc) -> + ?incomplete(negative(<>, T, Stack, Opts, Acc)). -zero(<>, [object|Stack], Opts, Acc) -> - emit([format_number(Acc), end_object], fun() -> - maybe_done(Rest, Stack, Opts) - end); -zero(<>, [array|Stack], Opts, Acc) -> - emit([format_number(Acc), end_array], fun() -> - maybe_done(Rest, Stack, Opts) - end); -zero(<>, [object|Stack], Opts, Acc) -> - emit([format_number(Acc)], fun() -> key(Rest, [key|Stack], Opts) end); -zero(<>, [array|_] = Stack, Opts, Acc) -> - emit([format_number(Acc)], fun() -> value(Rest, Stack, Opts) end); -zero(<>, Stack, Opts, Acc) -> - initial_decimal(Rest, Stack, Opts, {Acc, []}); -zero(<>, Stack, Opts, Acc) when ?is_whitespace(S) -> - emit([format_number(Acc)], fun() -> maybe_done(Rest, Stack, Opts) end); -zero(<<>>, [], Opts, Acc) -> +zero(<>, T, [object|Stack], Opts, Acc) -> + emit([format_number(Acc), end_object], {maybe_done, Rest, T, [Stack, Opts]}); +zero(<>, T, [array|Stack], Opts, Acc) -> + emit([format_number(Acc), end_array], {maybe_done, Rest, T, [Stack, Opts]}); +zero(<>, T, [object|Stack], Opts, Acc) -> + emit([format_number(Acc)], {key, Rest, T, [[key|Stack], Opts]}); +zero(<>, T, [array|_] = Stack, Opts, Acc) -> + emit([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) -> + emit([format_number(Acc)], {maybe_done, Rest, T, [Stack, Opts]}); +zero(<<>>, T, [], Opts, Acc) -> {jsx, incomplete, fun(end_stream) -> emit([format_number(Acc), end_json], - fun() -> decimal(<<>>, [], Opts, Acc) end) - ; (Stream) -> zero(Stream, [], Opts, Acc) + {decimal, <<>>, T, [[], Opts, Acc]}) + ; (Stream) -> zero(Stream, T, [], Opts, Acc) end}; -zero(Bin, Stack, Opts, Acc) -> - ?incomplete(zero(<>, Stack, Opts, Acc)). +zero(Bin, T, Stack, Opts, Acc) -> + ?incomplete(zero(<>, T, Stack, Opts, Acc)). -integer(<>, Stack, Opts, Acc) when ?is_nonzero(S) -> - integer(Rest, Stack, Opts, [S] ++ Acc); -integer(<>, [object|Stack], Opts, Acc) -> - emit([format_number(Acc), end_object], fun() -> - maybe_done(Rest, Stack, Opts) - end); -integer(<>, [array|Stack], Opts, Acc) -> - emit([format_number(Acc), end_array], fun() -> - maybe_done(Rest, Stack, Opts) - end); -integer(<>, [object|Stack], Opts, Acc) -> - emit([format_number(Acc)], fun() -> key(Rest, [key|Stack], Opts) end); -integer(<>, [array|_] = Stack, Opts, Acc) -> - emit([format_number(Acc)], fun() -> value(Rest, Stack, Opts) end); -integer(<>, Stack, Opts, Acc) -> - initial_decimal(Rest, Stack, Opts, {Acc, []}); -integer(<>, Stack, Opts, Acc) -> - integer(Rest, Stack, Opts, [?zero] ++ Acc); -integer(<>, Stack, Opts, Acc) when S =:= $e; S =:= $E -> - e(Rest, Stack, Opts, {Acc, [], []}); -integer(<>, Stack, Opts, Acc) when ?is_whitespace(S) -> - emit([format_number(Acc)], fun() -> maybe_done(Rest, Stack, Opts) end); -integer(<<>>, [], Opts, Acc) -> +integer(<>, T, Stack, Opts, Acc) when ?is_nonzero(S) -> + integer(Rest, T, Stack, Opts, [S] ++ Acc); +integer(<>, T, [object|Stack], Opts, Acc) -> + emit([format_number(Acc), end_object], {maybe_done, Rest, T, [Stack, Opts]}); +integer(<>, T, [array|Stack], Opts, Acc) -> + emit([format_number(Acc), end_array], {maybe_done, Rest, T, [Stack, Opts]}); +integer(<>, T, [object|Stack], Opts, Acc) -> + emit([format_number(Acc)], {key, Rest, T, [[key|Stack], Opts]}); +integer(<>, T, [array|_] = Stack, Opts, Acc) -> + emit([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) -> + emit([format_number(Acc)], {maybe_done, Rest, T, [Stack, Opts]}); +integer(<<>>, T, [], Opts, Acc) -> {jsx, incomplete, fun(end_stream) -> emit([format_number(Acc), end_json], - fun() -> decimal(<<>>, [], Opts, Acc) end) - ; (Stream) -> integer(Stream, [], Opts, Acc) + {decimal, <<>>, T, [[], Opts, Acc]}) + ; (Stream) -> integer(Stream, T, [], Opts, Acc) end}; -integer(Bin, Stack, Opts, Acc) -> - ?incomplete(integer(<>, Stack, Opts, Acc)). +integer(Bin, T, Stack, Opts, Acc) -> + ?incomplete(integer(<>, T, Stack, Opts, Acc)). -initial_decimal(<>, Stack, Opts, {Int, Frac}) +initial_decimal(<>, T, Stack, Opts, {Int, Frac}) when S =:= ?zero; ?is_nonzero(S) -> - decimal(Rest, Stack, Opts, {Int, [S] ++ Frac}); -initial_decimal(Bin, Stack, Opts, Acc) -> + decimal(Rest, T, Stack, Opts, {Int, [S] ++ Frac}); +initial_decimal(Bin, T, Stack, Opts, Acc) -> ?incomplete( - initial_decimal(<>, Stack, Opts, Acc) + initial_decimal(<>, T, Stack, Opts, Acc) ). -decimal(<>, Stack, Opts, {Int, Frac}) +decimal(<>, T, Stack, Opts, {Int, Frac}) when S=:= ?zero; ?is_nonzero(S) -> - decimal(Rest, Stack, Opts, {Int, [S] ++ Frac}); -decimal(<>, [object|Stack], Opts, Acc) -> - emit([format_number(Acc), end_object], fun() -> - maybe_done(Rest, Stack, Opts) - end); -decimal(<>, [array|Stack], Opts, Acc) -> - emit([format_number(Acc), end_array], fun() -> - maybe_done(Rest, Stack, Opts) - end); -decimal(<>, [object|Stack], Opts, Acc) -> - emit([format_number(Acc)], fun() -> key(Rest, [key|Stack], Opts) end); -decimal(<>, [array|_] = Stack, Opts, Acc) -> - emit([format_number(Acc)], fun() -> value(Rest, Stack, Opts) end); -decimal(<>, Stack, Opts, {Int, Frac}) + decimal(Rest, T, Stack, Opts, {Int, [S] ++ Frac}); +decimal(<>, T, [object|Stack], Opts, Acc) -> + emit([format_number(Acc), end_object], {maybe_done, Rest, T, [Stack, Opts]}); +decimal(<>, T, [array|Stack], Opts, Acc) -> + emit([format_number(Acc), end_array], {maybe_done, Rest, T, [Stack, Opts]}); +decimal(<>, T, [object|Stack], Opts, Acc) -> + emit([format_number(Acc)], {key, Rest, T, [[key|Stack], Opts]}); +decimal(<>, T, [array|_] = Stack, Opts, Acc) -> + emit([format_number(Acc)], {value, Rest, T, [Stack, Opts]}); +decimal(<>, T, Stack, Opts, {Int, Frac}) when S =:= $e; S =:= $E -> - e(Rest, Stack, Opts, {Int, Frac, []}); -decimal(<>, Stack, Opts, Acc) when ?is_whitespace(S) -> - emit([format_number(Acc)], fun() -> maybe_done(Rest, Stack, Opts) end); -decimal(<<>>, [], Opts, Acc) -> + e(Rest, T, Stack, Opts, {Int, Frac, []}); +decimal(<>, T, Stack, Opts, Acc) when ?is_whitespace(S) -> + emit([format_number(Acc)], {maybe_done, Rest, T, [Stack, Opts]}); +decimal(<<>>, T, [], Opts, Acc) -> {jsx, incomplete, fun(end_stream) -> emit([format_number(Acc), end_json], - fun() -> decimal(<<>>, [], Opts, Acc) end) - ; (Stream) -> decimal(Stream, [], Opts, Acc) + {decimal, <<>>, T, [[], Opts, Acc]}) + ; (Stream) -> decimal(Stream, T, [], Opts, Acc) end}; -decimal(Bin, Stack, Opts, Acc) -> - ?incomplete(decimal(<>, Stack, Opts, Acc)). +decimal(Bin, T, Stack, Opts, Acc) -> + ?incomplete(decimal(<>, T, Stack, Opts, Acc)). -e(<>, Stack, Opts, {Int, Frac, Exp}) +e(<>, T, Stack, Opts, {Int, Frac, Exp}) when S =:= ?zero; ?is_nonzero(S) -> - exp(Rest, Stack, Opts, {Int, Frac, [S] ++ Exp}); -e(<>, Stack, Opts, {Int, Frac, Exp}) + exp(Rest, T, Stack, Opts, {Int, Frac, [S] ++ Exp}); +e(<>, T, Stack, Opts, {Int, Frac, Exp}) when S =:= ?positive; S =:= ?negative -> - ex(Rest, Stack, Opts, {Int, Frac, [S] ++ Exp}); -e(Bin, Stack, Opts, Acc) -> - ?incomplete(e(<>, Stack, Opts, Acc)). + ex(Rest, T, Stack, Opts, {Int, Frac, [S] ++ Exp}); +e(Bin, T, Stack, Opts, Acc) -> + ?incomplete(e(<>, T, Stack, Opts, Acc)). -ex(<>, Stack, Opts, {Int, Frac, Exp}) +ex(<>, T, Stack, Opts, {Int, Frac, Exp}) when S =:= ?zero; ?is_nonzero(S) -> - exp(Rest, Stack, Opts, {Int, Frac, [S] ++ Exp}); -ex(Bin, Stack, Opts, Acc) -> - ?incomplete(ex(<>, Stack, Opts, Acc)). + exp(Rest, T, Stack, Opts, {Int, Frac, [S] ++ Exp}); +ex(Bin, T, Stack, Opts, Acc) -> + ?incomplete(ex(<>, T, Stack, Opts, Acc)). -exp(<>, Stack, Opts, {Int, Frac, Exp}) +exp(<>, T, Stack, Opts, {Int, Frac, Exp}) when S =:= ?zero; ?is_nonzero(S) -> - exp(Rest, Stack, Opts, {Int, Frac, [S] ++ Exp}); -exp(<>, [object|Stack], Opts, Acc) -> - emit([format_number(Acc), end_object], fun() -> - maybe_done(Rest, Stack, Opts) - end); -exp(<>, [array|Stack], Opts, Acc) -> - emit([format_number(Acc), end_array], fun() -> - maybe_done(Rest, Stack, Opts) - end); -exp(<>, [object|Stack], Opts, Acc) -> - emit([format_number(Acc)], fun() -> key(Rest, [key|Stack], Opts) end); -exp(<>, [array|_] = Stack, Opts, Acc) -> - emit([format_number(Acc)], fun() -> value(Rest, Stack, Opts) end); -exp(<>, Stack, Opts, Acc) when ?is_whitespace(S) -> - emit([format_number(Acc)], fun() -> maybe_done(Rest, Stack, Opts) end); -exp(<<>>, [], Opts, Acc) -> + exp(Rest, T, Stack, Opts, {Int, Frac, [S] ++ Exp}); +exp(<>, T, [object|Stack], Opts, Acc) -> + emit([format_number(Acc), end_object], {maybe_done, Rest, T, [Stack, Opts]}); +exp(<>, T, [array|Stack], Opts, Acc) -> + emit([format_number(Acc), end_array], {maybe_done, Rest, T, [Stack, Opts]}); +exp(<>, T, [object|Stack], Opts, Acc) -> + emit([format_number(Acc)], {key, Rest, T, [[key|Stack], Opts]}); +exp(<>, T, [array|_] = Stack, Opts, Acc) -> + emit([format_number(Acc)], {value, Rest, T, [Stack, Opts]}); +exp(<>, T, Stack, Opts, Acc) when ?is_whitespace(S) -> + emit([format_number(Acc)], {maybe_done, Rest, T, [Stack, Opts]}); +exp(<<>>, T, [], Opts, Acc) -> {jsx, incomplete, fun(end_stream) -> emit([format_number(Acc), end_json], - fun() -> exp(<<>>, [], Opts, Acc) end) - ; (Stream) -> exp(Stream, [], Opts, Acc) + {exp, <<>>, T, [[], Opts, Acc]}) + ; (Stream) -> exp(Stream, T, [], Opts, Acc) end}; -exp(Bin, Stack, Opts, Acc) -> - ?incomplete(exp(<>, Stack, Opts, Acc)). +exp(Bin, T, Stack, Opts, Acc) -> + ?incomplete(exp(<>, T, Stack, Opts, Acc)). format_number(Int) when is_list(Int) -> @@ -805,64 +808,64 @@ format_number({Int, Frac, Exp}) -> {float, list_to_float(lists:reverse(Exp ++ "e" ++ Frac ++ "." ++ Int))}. -tr(<<$r/?utfx, Rest/binary>>, Stack, Opts) -> - tru(Rest, Stack, Opts); -tr(Bin, Stack, Opts) -> - ?incomplete(tr(<>, Stack, Opts)). +tr(<<$r/?utfx, Rest/binary>>, T, Stack, Opts) -> + tru(Rest, T, Stack, Opts); +tr(Bin, T, Stack, Opts) -> + ?incomplete(tr(<>, T, Stack, Opts)). -tru(<<$u/?utfx, Rest/binary>>, Stack, Opts) -> - true(Rest, Stack, Opts); -tru(Bin, Stack, Opts) -> - ?incomplete(tru(<>, Stack, Opts)). +tru(<<$u/?utfx, Rest/binary>>, T, Stack, Opts) -> + true(Rest, T, Stack, Opts); +tru(Bin, T, Stack, Opts) -> + ?incomplete(tru(<>, T, Stack, Opts)). -true(<<$e/?utfx, Rest/binary>>, Stack, Opts) -> - emit([{literal, true}], fun() -> maybe_done(Rest, Stack, Opts) end); -true(Bin, Stack, Opts) -> - ?incomplete(true(<>, Stack, Opts)). +true(<<$e/?utfx, Rest/binary>>, T, Stack, Opts) -> + emit([{literal, true}], {maybe_done, Rest, T, [Stack, Opts]}); +true(Bin, T, Stack, Opts) -> + ?incomplete(true(<>, T, Stack, Opts)). -fa(<<$a/?utfx, Rest/binary>>, Stack, Opts) -> - fal(Rest, Stack, Opts); -fa(Bin, Stack, Opts) -> - ?incomplete(fa(<>, Stack, Opts)). +fa(<<$a/?utfx, Rest/binary>>, T, Stack, Opts) -> + fal(Rest, T, Stack, Opts); +fa(Bin, T, Stack, Opts) -> + ?incomplete(fa(<>, T, Stack, Opts)). -fal(<<$l/?utfx, Rest/binary>>, Stack, Opts) -> - fals(Rest, Stack, Opts); -fal(Bin, Stack, Opts) -> - ?incomplete(fal(<>, Stack, Opts)). +fal(<<$l/?utfx, Rest/binary>>, T, Stack, Opts) -> + fals(Rest, T, Stack, Opts); +fal(Bin, T, Stack, Opts) -> + ?incomplete(fal(<>, T, Stack, Opts)). -fals(<<$s/?utfx, Rest/binary>>, Stack, Opts) -> - false(Rest, Stack, Opts); -fals(Bin, Stack, Opts) -> - ?incomplete(fals(<>, Stack, Opts)). +fals(<<$s/?utfx, Rest/binary>>, T, Stack, Opts) -> + false(Rest, T, Stack, Opts); +fals(Bin, T, Stack, Opts) -> + ?incomplete(fals(<>, T, Stack, Opts)). -false(<<$e/?utfx, Rest/binary>>, Stack, Opts) -> - emit([{literal, false}], fun() -> maybe_done(Rest, Stack, Opts) end); -false(Bin, Stack, Opts) -> - ?incomplete(false(<>, Stack, Opts)). +false(<<$e/?utfx, Rest/binary>>, T, Stack, Opts) -> + emit([{literal, false}], {maybe_done, Rest, T, [Stack, Opts]}); +false(Bin, T, Stack, Opts) -> + ?incomplete(false(<>, T, Stack, Opts)). -nu(<<$u/?utfx, Rest/binary>>, Stack, Opts) -> - nul(Rest, Stack, Opts); -nu(Bin, Stack, Opts) -> - ?incomplete(nu(<>, Stack, Opts)). +nu(<<$u/?utfx, Rest/binary>>, T, Stack, Opts) -> + nul(Rest, T, Stack, Opts); +nu(Bin, T, Stack, Opts) -> + ?incomplete(nu(<>, T, Stack, Opts)). -nul(<<$l/?utfx, Rest/binary>>, Stack, Opts) -> - null(Rest, Stack, Opts); -nul(Bin, Stack, Opts) -> - ?incomplete(nul(<>, Stack, Opts)). +nul(<<$l/?utfx, Rest/binary>>, T, Stack, Opts) -> + null(Rest, T, Stack, Opts); +nul(Bin, T, Stack, Opts) -> + ?incomplete(nul(<>, T, Stack, Opts)). -null(<<$l/?utfx, Rest/binary>>, Stack, Opts) -> - emit([{literal, null}], fun() -> maybe_done(Rest, Stack, Opts) end); -null(Bin, Stack, Opts) -> - ?incomplete(null(<>, Stack, Opts)). +null(<<$l/?utfx, Rest/binary>>, T, Stack, Opts) -> + emit([{literal, null}], {maybe_done, Rest, T, [Stack, Opts]}); +null(Bin, T, Stack, Opts) -> + ?incomplete(null(<>, T, Stack, Opts)).