diff --git a/src/jsx.erl b/src/jsx.erl index 70bc502..ec7df00 100644 --- a/src/jsx.erl +++ b/src/jsx.erl @@ -21,15 +21,17 @@ %% THE SOFTWARE. - -module(jsx). -author("alisdairsullivan@yahoo.ca"). --export([decode/1, decode/2, parser/0, parser/1, parser/2]). +-export([decode/1, decode/2, parser/0, parser/1]). -include("jsx_types.hrl"). +%% decode takes a json binary (and optionally, a proplist of options) and returns a list +%% of events corresponding to the json structure/contents. it converts incompletes into +%% errors -spec decode(JSON::json()) -> {ok, [jsx_event(),...]} | {error, badjson}. -spec decode(JSON::json(), Opts::jsx_opts()) -> {ok, [jsx_event(),...]} | {error, badjson}. @@ -39,47 +41,39 @@ decode(JSON) -> decode(JSON, Opts) -> F = parser(Opts), - case F(JSON) of - {incomplete, _} -> {error, badjson} - ; {error, badjson} -> {error, badjson} - ; {Result, _} -> {ok, Result} - end. + decode_loop(F(JSON), []). +decode_loop({incomplete, _}, _) -> {error, badjson}; +decode_loop({error, badjson}, _) -> {error, badjson}; +decode_loop({end_json, _}, State) -> {ok, lists:reverse(State)}; +decode_loop({Event, F}, State) -> decode_loop(F(), [Event] ++ State). + + +%% parser returns an anonymous function of arity 1 that takes a json binary as it's +%% argument and returns a tuple containing an error, incomplete and a new parser that +%% can be handed more input to resume parsing or a single event and a function that +%% can be called to get the next result -spec parser() -> jsx_parser(). -spec parser(Opts::jsx_opts()) -> jsx_parser(). --spec parser(Callbacks::{fun((jsx_event(), any()) -> any())}, Opts::jsx_opts()) -> jsx_parser() - ; (Callbacks::{atom(), atom(), any()}, Opts::jsx_opts()) -> jsx_parser(). parser() -> parser([]). -parser(Opts) -> - F = fun(end_json, State) -> lists:reverse(State) - ; (Event, State) -> [Event] ++ State - end, - parser({F, []}, Opts). - -parser({F, S} = Callback, OptsList) when is_list(OptsList), is_function(F) -> - start(Callback, OptsList); -parser({Mod, Fun, State}, OptsList) when is_list(OptsList), is_atom(Mod), is_atom(Fun) -> - start({fun(E, S) -> Mod:Fun(E, S) end, State}, OptsList). - - -start(Callback, OptsList) -> +parser(OptsList) -> F = case proplists:get_value(encoding, OptsList, auto) of - utf8 -> fun jsx_utf8:parse/3 - ; utf16 -> fun jsx_utf16:parse/3 - ; utf32 -> fun jsx_utf32:parse/3 - ; {utf16, little} -> fun jsx_utf16le:parse/3 - ; {utf32, little} -> fun jsx_utf32le:parse/3 - ; auto -> fun detect_encoding/3 + utf8 -> fun jsx_utf8:parse/2 + ; utf16 -> fun jsx_utf16:parse/2 + ; utf32 -> fun jsx_utf32:parse/2 + ; {utf16, little} -> fun jsx_utf16le:parse/2 + ; {utf32, little} -> fun jsx_utf32le:parse/2 + ; auto -> fun detect_encoding/2 end, - start(F, Callback, OptsList). + start(F, OptsList). -start(F, Callback, OptsList) -> +start(F, OptsList) -> Opts = parse_opts(OptsList), - fun(Stream) -> F(Stream, Callback, Opts) end. + fun(Stream) -> F(Stream, Opts) end. parse_opts(Opts) -> @@ -95,84 +89,87 @@ parse_opts([{escaped_unicode, Value}|Rest], {Comments, _EscapedUnicode, Stream}) parse_opts(Rest, {Comments, Value, Stream}); parse_opts([{stream_mode, Value}|Rest], {Comments, EscapedUnicode, _Stream}) -> true = lists:member(Value, [true, false]), - parse_opts(Rest, {Comments, EscapedUnicode, Value}). + parse_opts(Rest, {Comments, EscapedUnicode, Value}); +parse_opts([{encoding, _}|Rest], Opts) -> + parse_opts(Rest, Opts). %% first check to see if there's a bom, if not, use the rfc4627 method for determining %% encoding. this function makes some assumptions about the validity of the stream -%% which may delay failure later than if an encoding is explicitly provided. +%% which may delay failure later than if an encoding is explicitly provided %% utf8 bom detection -detect_encoding(<<16#ef, 16#bb, 16#bf, Rest/binary>>, Callback, Opts) -> - jsx_utf8:parse(Rest, Callback, Opts); +detect_encoding(<<16#ef, 16#bb, 16#bf, Rest/binary>>, Opts) -> + jsx_utf8:parse(Rest, Opts); %% utf32-little bom detection (this has to come before utf16-little) -detect_encoding(<<16#ff, 16#fe, 0, 0, Rest/binary>>, Callback, Opts) -> - jsx_utf32le:parse(Rest, Callback, Opts); +detect_encoding(<<16#ff, 16#fe, 0, 0, Rest/binary>>, Opts) -> + jsx_utf32le:parse(Rest, Opts); %% utf16-big bom detection -detect_encoding(<<16#fe, 16#ff, Rest/binary>>, Callback, Opts) -> - jsx_utf16:parse(Rest, Callback, Opts); +detect_encoding(<<16#fe, 16#ff, Rest/binary>>, Opts) -> + jsx_utf16:parse(Rest, Opts); %% utf16-little bom detection -detect_encoding(<<16#ff, 16#fe, Rest/binary>>, Callback, Opts) -> - jsx_utf16le:parse(Rest, Callback, Opts); +detect_encoding(<<16#ff, 16#fe, Rest/binary>>, Opts) -> + jsx_utf16le:parse(Rest, Opts); %% utf32-big bom detection -detect_encoding(<<0, 0, 16#fe, 16#ff, Rest/binary>>, Callback, Opts) -> - jsx_utf32:parse(Rest, Callback, Opts); +detect_encoding(<<0, 0, 16#fe, 16#ff, Rest/binary>>, Opts) -> + jsx_utf32:parse(Rest, Opts); %% utf32-little null order detection -detect_encoding(<> = JSON, Callback, Opts) when X =/= 0 -> - jsx_utf32le:parse(JSON, Callback, Opts); +detect_encoding(<> = JSON, Opts) when X =/= 0 -> + jsx_utf32le:parse(JSON, Opts); %% utf16-big null order detection -detect_encoding(<<0, X, 0, Y, _Rest/binary>> = JSON, Callback, Opts) when X =/= 0, Y =/= 0 -> - jsx_utf16:parse(JSON, Callback, Opts); +detect_encoding(<<0, X, 0, Y, _Rest/binary>> = JSON, Opts) when X =/= 0, Y =/= 0 -> + jsx_utf16:parse(JSON, Opts); %% utf16-little null order detection -detect_encoding(<> = JSON, Callback, Opts) when X =/= 0, Y =/= 0 -> - jsx_utf16le:parse(JSON, Callback, Opts); +detect_encoding(<> = JSON, Opts) when X =/= 0, Y =/= 0 -> + jsx_utf16le:parse(JSON, Opts); %% utf32-big null order detection -detect_encoding(<<0, 0, 0, X, _Rest/binary>> = JSON, Callback, Opts) when X =/= 0 -> - jsx_utf32:parse(JSON, Callback, Opts); +detect_encoding(<<0, 0, 0, X, _Rest/binary>> = JSON, Opts) when X =/= 0 -> + jsx_utf32:parse(JSON, Opts); %% utf8 null order detection -detect_encoding(<> = JSON, Callback, Opts) when X =/= 0, Y =/= 0 -> - jsx_utf8:parse(JSON, Callback, Opts); +detect_encoding(<> = JSON, Opts) when X =/= 0, Y =/= 0 -> + jsx_utf8:parse(JSON, Opts); %% a problem, to autodetect naked single digits' encoding, there is not enough data %% to conclusively determine the encoding correctly. below is an attempt to solve %% the problem -detect_encoding(<>, Callback, Opts) when X =/= 0 -> - {try {Result, _} = jsx_utf8:parse(<>, Callback, Opts), Result +detect_encoding(<>, Opts) when X =/= 0 -> + {try {Result, _} = jsx_utf8:parse(<>, Opts), Result catch error:function_clause -> incomplete end, fun(Stream) -> - detect_encoding(<>, Callback, Opts) + detect_encoding(<>, Opts) end }; -detect_encoding(<<0, X>>, Callback, Opts) when X =/= 0 -> - {try {Result, _} = jsx_utf16:parse(<<0, X>>, Callback, Opts), Result +detect_encoding(<<0, X>>, Opts) when X =/= 0 -> + {try {Result, _} = jsx_utf16:parse(<<0, X>>, Opts), Result catch error:function_clause -> incomplete end, fun(Stream) -> - detect_encoding(<<0, X, Stream/binary>>, Callback, Opts) + detect_encoding(<<0, X, Stream/binary>>, Opts) end }; -detect_encoding(<>, Callback, Opts) when X =/= 0 -> - {try {Result, _} = jsx_utf16le:parse(<>, Callback, Opts), Result +detect_encoding(<>, Opts) when X =/= 0 -> + {try {Result, _} = jsx_utf16le:parse(<>, Opts), Result catch error:function_clause -> incomplete end, fun(Stream) -> - detect_encoding(<>, Callback, Opts) + detect_encoding(<>, Opts) end }; %% not enough input, request more -detect_encoding(Bin, Callback, Opts) -> + +detect_encoding(Bin, Opts) -> {incomplete, fun(Stream) -> - detect_encoding(<>, Callback, Opts) + detect_encoding(<>, Opts) end }. \ No newline at end of file diff --git a/src/jsx_decoder.erl b/src/jsx_decoder.erl index 80c8aa7..fcdbfa3 100644 --- a/src/jsx_decoder.erl +++ b/src/jsx_decoder.erl @@ -27,30 +27,16 @@ -module(?name). -author("alisdairsullivan@yahoo.ca"). +-export([parse/2]). + -include("jsx_decoder.hrl"). - --export([parse/3]). --compile(inline). +-include("jsx_types.hrl"). -parse(JSON, {Callback, State}, Opts) -> - parse(Callback, State, fun() -> start(JSON, [], Opts) end, Opts). - -parse(Callback, State, F, Opts) -> - case F() of - {incomplete, Next} -> {incomplete, Next} - ; {end_json, Next} -> {Callback(end_json, State), Next} - ; {error, badjson} -> {error, badjson} - ; {Event, Next} -> parse(Callback, Callback(Event, State), Next, Opts) - end. - +-spec parse(JSON::json(), Opts::jsx_opts()) -> parser_result(). -emit(incomplete, F) -> - {incomplete, F}; -emit(end_json, F) -> - {end_json, F}; -emit(Event, F) -> - {Event, F}. +parse(JSON, Opts) -> + start(JSON, [], Opts). %% this code is mostly autogenerated and mostly ugly. apologies. for more insight on @@ -64,9 +50,9 @@ emit(Event, F) -> 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_object, fun() -> object(Rest, [key|Stack], Opts) end}; start(<>, Stack, Opts) -> - emit(start_array, fun() -> array(Rest, [array|Stack], Opts) end); + {start_array, fun() -> array(Rest, [array|Stack], Opts) end}; start(<>, Stack, Opts) -> string(Rest, Stack, Opts, []); start(<<$t/?encoding, Rest/binary>>, Stack, Opts) -> @@ -86,16 +72,16 @@ start(<>, Stack, ?comments_enabled(Opts)) -> start(Bin, Stack, Opts) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> start(<>, Stack, Opts) end) + ; _ -> {incomplete, fun(Stream) -> start(<>, Stack, Opts) end} end. 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); + {end_object, fun() -> maybe_done(Rest, Stack, Opts) end}; maybe_done(<>, [array|Stack], Opts) -> - emit(end_array, fun() -> maybe_done(Rest, Stack, Opts) end); + {end_array, fun() -> maybe_done(Rest, Stack, Opts) end}; maybe_done(<>, [object|Stack], Opts) -> key(Rest, [key|Stack], Opts); maybe_done(<>, [array|_] = Stack, Opts) -> @@ -103,13 +89,13 @@ maybe_done(<>, [array|_] = Stack, Opts) -> maybe_done(<>, Stack, ?comments_enabled(Opts)) -> maybe_comment(Rest, fun(Resume) -> maybe_done(Resume, Stack, Opts) end); maybe_done(Bin, [], ?stream_mode(Opts)) -> - emit(end_json, fun() -> start(Bin, [], Opts) end); + {end_json, fun() -> start(Bin, [], Opts) end}; maybe_done(<<>>, [], Opts) -> - emit(end_json, fun() -> emit(incomplete, fun(Stream) -> maybe_done(Stream, [], Opts) end) end); + {end_json, fun() -> {incomplete, fun(Stream) -> maybe_done(Stream, [], Opts) end} end}; maybe_done(Bin, Stack, Opts) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> maybe_done(<>, Stack, Opts) end) + ; _ -> {incomplete, fun(Stream) -> maybe_done(<>, Stack, Opts) end} end. @@ -118,13 +104,13 @@ object(<>, Stack, Opts) when ?is_whitespace(S) -> object(<>, Stack, Opts) -> string(Rest, Stack, Opts, []); object(<>, [key|Stack], Opts) -> - emit(end_object, fun() -> maybe_done(Rest, Stack, Opts) end); + {end_object, fun() -> maybe_done(Rest, Stack, Opts) end}; object(<>, Stack, ?comments_enabled(Opts)) -> maybe_comment(Rest, fun(Resume) -> object(Resume, Stack, Opts) end); object(Bin, Stack, Opts) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> object(<>, Stack, Opts) end) + ; _ -> {incomplete, fun(Stream) -> object(<>, Stack, Opts) end} end. @@ -145,17 +131,17 @@ array(<>, Stack, Opts) -> 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); + {start_object, fun() -> object(Rest, [key|Stack], Opts) end}; array(<>, Stack, Opts) -> - emit(start_array, fun() -> array(Rest, [array|Stack], Opts) end); + {start_array, fun() -> array(Rest, [array|Stack], Opts) end}; array(<>, [array|Stack], Opts) -> - emit(end_array, fun() -> maybe_done(Rest, Stack, Opts) end); + {end_array, fun() -> maybe_done(Rest, Stack, Opts) end}; array(<>, Stack, ?comments_enabled(Opts)) -> maybe_comment(Rest, fun(Resume) -> array(Resume, Stack, Opts) end); array(Bin, Stack, Opts) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> array(<>, Stack, Opts) end) + ; _ -> {incomplete, fun(Stream) -> array(<>, Stack, Opts) end} end. @@ -176,15 +162,15 @@ value(<>, Stack, Opts) -> 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); + {start_object, fun() -> object(Rest, [key|Stack], Opts) end}; value(<>, Stack, Opts) -> - emit(start_array, fun() -> array(Rest, [array|Stack], Opts) end); + {start_array, fun() -> array(Rest, [array|Stack], Opts) end}; value(<>, Stack, ?comments_enabled(Opts)) -> maybe_comment(Rest, fun(Resume) -> value(Resume, Stack, Opts) end); value(Bin, Stack, Opts) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> value(<>, Stack, Opts) end) + ; _ -> {incomplete, fun(Stream) -> value(<>, Stack, Opts) end} end. @@ -197,7 +183,7 @@ colon(<>, Stack, ?comments_enabled(Opts)) -> colon(Bin, Stack, Opts) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> colon(<>, Stack, Opts) end) + ; _ -> {incomplete, fun(Stream) -> colon(<>, Stack, Opts) end} end. @@ -210,7 +196,7 @@ key(<>, Stack, ?comments_enabled(Opts)) -> key(Bin, Stack, Opts) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> key(<>, Stack, Opts) end) + ; _ -> {incomplete, fun(Stream) -> key(<>, Stack, Opts) end} end. @@ -220,9 +206,9 @@ key(Bin, Stack, Opts) -> %% converted back to lists by the user anyways. string(<>, [key|_] = Stack, Opts, Acc) -> - emit({key, lists:reverse(Acc)}, fun() -> colon(Rest, Stack, Opts) end); + {{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, lists:reverse(Acc)}, fun() -> maybe_done(Rest, Stack, Opts) end}; string(<>, Stack, Opts, Acc) -> escape(Rest, Stack, Opts, Acc); string(<>, Stack, Opts, Acc) when ?is_noncontrol(S) -> @@ -230,7 +216,7 @@ string(<>, Stack, Opts, Acc) when ?is_noncontrol(S) -> string(Bin, Stack, Opts, Acc) -> case partial_utf(Bin) of false -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> string(<>, Stack, Opts, Acc) end) + ; _ -> {incomplete, fun(Stream) -> string(<>, Stack, Opts, Acc) end} end. @@ -304,7 +290,7 @@ escape(<>, Stack, Opts, Acc) escape(Bin, Stack, Opts, Acc) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> escape(<>, Stack, Opts, Acc) end) + ; _ -> {incomplete, fun(Stream) -> escape(<>, Stack, Opts, Acc) end} end. @@ -354,9 +340,9 @@ escaped_unicode(<>, Stack, Opts, String, Acc) when ?is escaped_unicode(Bin, Stack, Opts, String, Acc) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> + ; _ -> {incomplete, fun(Stream) -> escaped_unicode(<>, Stack, Opts, String, Acc) - end) + end} end. %% upon encountering a low pair json/hex encoded value, check to see if there's a high @@ -389,58 +375,58 @@ negative(<>, Stack, Opts, Acc) when ?is_nonzero(S) -> negative(Bin, Stack, Opts, Acc) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> negative(<>, Stack, Opts, Acc) end) + ; _ -> {incomplete, fun(Stream) -> negative(<>, Stack, Opts, Acc) end} end. zero(<>, [object|Stack], Opts, Acc) -> - emit({integer, lists:reverse(Acc)}, fun() -> - emit(end_object, fun() -> maybe_done(Rest, Stack, Opts) end) - end); + {{integer, lists:reverse(Acc)}, fun() -> + {end_object, fun() -> maybe_done(Rest, Stack, Opts) end} + end}; zero(<>, [array|Stack], Opts, Acc) -> - emit({integer, lists:reverse(Acc)}, fun() -> - emit(end_array, fun() -> maybe_done(Rest, Stack, Opts) end) - end); + {{integer, lists:reverse(Acc)}, fun() -> + {end_array, fun() -> maybe_done(Rest, Stack, Opts) end} + end}; zero(<>, [object|Stack], Opts, Acc) -> - emit({integer, lists:reverse(Acc)}, fun() -> key(Rest, [key|Stack], Opts) end); + {{integer, lists:reverse(Acc)}, fun() -> key(Rest, [key|Stack], Opts) end}; zero(<>, [array|_] = Stack, Opts, Acc) -> - emit({integer, lists:reverse(Acc)}, fun() -> value(Rest, Stack, Opts) end); + {{integer, lists:reverse(Acc)}, fun() -> value(Rest, Stack, Opts) end}; zero(<>, Stack, Opts, Acc) -> initial_decimal(Rest, Stack, Opts, [?decimalpoint] ++ Acc); zero(<>, Stack, Opts, Acc) when ?is_whitespace(S) -> - emit({integer, lists:reverse(Acc)}, fun() -> maybe_done(Rest, Stack, Opts) end); + {{integer, lists:reverse(Acc)}, fun() -> maybe_done(Rest, Stack, Opts) end}; zero(<>, Stack, ?comments_enabled(Opts), Acc) -> maybe_comment(Rest, fun(Resume) -> zero(Resume, Stack, Opts, Acc) end); zero(Bin, [], ?stream_mode(Opts), Acc) -> - emit({integer, lists:reverse(Acc)}, fun() -> - emit(end_json, fun() -> start(Bin, [], Opts) end) - end); + {{integer, lists:reverse(Acc)}, fun() -> + {end_json, fun() -> start(Bin, [], Opts) end} + end}; zero(<<>>, [], Opts, Acc) -> - emit({integer, lists:reverse(Acc)}, fun() -> - emit(end_json, fun() -> emit(incomplete, fun(Stream) -> maybe_done(Stream, [], Opts) end) - end) - end); + {{integer, lists:reverse(Acc)}, fun() -> + {end_json, fun() -> {incomplete, fun(Stream) -> maybe_done(Stream, [], Opts) end} + end} + end}; zero(Bin, Stack, Opts, Acc) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> zero(<>, Stack, Opts, Acc) end) + ; _ -> {incomplete, fun(Stream) -> zero(<>, Stack, Opts, Acc) end} end. integer(<>, Stack, Opts, Acc) when ?is_nonzero(S) -> integer(Rest, Stack, Opts, [S] ++ Acc); integer(<>, [object|Stack], Opts, Acc) -> - emit({integer, lists:reverse(Acc)}, fun() -> - emit(end_object, fun() -> maybe_done(Rest, Stack, Opts) end) - end); + {{integer, lists:reverse(Acc)}, fun() -> + {end_object, fun() -> maybe_done(Rest, Stack, Opts) end} + end}; integer(<>, [array|Stack], Opts, Acc) -> - emit({integer, lists:reverse(Acc)}, fun() -> - emit(end_array, fun() -> maybe_done(Rest, Stack, Opts) end) - end); + {{integer, lists:reverse(Acc)}, fun() -> + {end_array, fun() -> maybe_done(Rest, Stack, Opts) end} + end}; integer(<>, [object|Stack], Opts, Acc) -> - emit({integer, lists:reverse(Acc)}, fun() -> key(Rest, [key|Stack], Opts) end); + {{integer, lists:reverse(Acc)}, fun() -> key(Rest, [key|Stack], Opts) end}; integer(<>, [array|_] = Stack, Opts, Acc) -> - emit({integer, lists:reverse(Acc)}, fun() -> value(Rest, Stack, Opts) end); + {{integer, lists:reverse(Acc)}, fun() -> value(Rest, Stack, Opts) end}; integer(<>, Stack, Opts, Acc) -> initial_decimal(Rest, Stack, Opts, [?decimalpoint] ++ Acc); integer(<>, Stack, Opts, Acc) -> @@ -450,22 +436,22 @@ integer(<<$e/?encoding, Rest/binary>>, Stack, Opts, Acc) -> integer(<<$E/?encoding, Rest/binary>>, Stack, Opts, Acc) -> e(Rest, Stack, Opts, "e0." ++ Acc); integer(<>, Stack, Opts, Acc) when ?is_whitespace(S) -> - emit({integer, lists:reverse(Acc)}, fun() -> maybe_done(Rest, Stack, Opts) end); + {{integer, lists:reverse(Acc)}, fun() -> maybe_done(Rest, Stack, Opts) end}; integer(<>, Stack, ?comments_enabled(Opts), Acc) -> maybe_comment(Rest, fun(Resume) -> integer(Resume, Stack, Opts, Acc) end); integer(Bin, [], ?stream_mode(Opts), Acc) -> - emit({integer, lists:reverse(Acc)}, fun() -> - emit(end_json, fun() -> start(Bin, [], Opts) end) - end); + {{integer, lists:reverse(Acc)}, fun() -> + {end_json, fun() -> start(Bin, [], Opts) end} + end}; integer(<<>>, [], Opts, Acc) -> - emit({integer, lists:reverse(Acc)}, fun() -> - emit(end_json, fun() -> emit(incomplete, fun(Stream) -> maybe_done(Stream, [], Opts) end) - end) - end); + {{integer, lists:reverse(Acc)}, fun() -> + {end_json, fun() -> {incomplete, fun(Stream) -> maybe_done(Stream, [], Opts) end} + end} + end}; integer(Bin, Stack, Opts, Acc) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> integer(<>, Stack, Opts, Acc) end) + ; _ -> {incomplete, fun(Stream) -> integer(<>, Stack, Opts, Acc) end} end. @@ -476,24 +462,24 @@ initial_decimal(<>, Stack, Opts, Acc) -> initial_decimal(Bin, Stack, Opts, Acc) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> initial_decimal(<>, Stack, Opts, Acc) end) + ; _ -> {incomplete, fun(Stream) -> initial_decimal(<>, Stack, Opts, Acc) end} end. decimal(<>, Stack, Opts, Acc) when ?is_nonzero(S) -> decimal(Rest, Stack, Opts, [S] ++ Acc); decimal(<>, [object|Stack], Opts, Acc) -> - emit({float, lists:reverse(Acc)}, fun() -> - emit(end_object, fun() -> maybe_done(Rest, Stack, Opts) end) - end); + {{float, lists:reverse(Acc)}, fun() -> + {end_object, fun() -> maybe_done(Rest, Stack, Opts) end} + end}; decimal(<>, [array|Stack], Opts, Acc) -> - emit({float, lists:reverse(Acc)}, fun() -> - emit(end_array, fun() -> maybe_done(Rest, Stack, Opts) end) - end); + {{float, lists:reverse(Acc)}, fun() -> + {end_array, fun() -> maybe_done(Rest, Stack, Opts) end} + end}; decimal(<>, [object|Stack], Opts, Acc) -> - emit({float, lists:reverse(Acc)}, fun() -> key(Rest, [key|Stack], Opts) end); + {{float, lists:reverse(Acc)}, fun() -> key(Rest, [key|Stack], Opts) end}; decimal(<>, [array|_] = Stack, Opts, Acc) -> - emit({float, lists:reverse(Acc)}, fun() -> value(Rest, Stack, Opts) end); + {{float, lists:reverse(Acc)}, fun() -> value(Rest, Stack, Opts) end}; decimal(<>, Stack, Opts, Acc) -> decimal(Rest, Stack, Opts, [?zero] ++ Acc); decimal(<<$e/?encoding, Rest/binary>>, Stack, Opts, Acc) -> @@ -501,22 +487,22 @@ decimal(<<$e/?encoding, Rest/binary>>, Stack, Opts, Acc) -> decimal(<<$E/?encoding, Rest/binary>>, Stack, Opts, Acc) -> e(Rest, Stack, Opts, "e" ++ Acc); decimal(<>, Stack, Opts, Acc) when ?is_whitespace(S) -> - emit({float, lists:reverse(Acc)}, fun() -> maybe_done(Rest, Stack, Opts) end); + {{float, lists:reverse(Acc)}, fun() -> maybe_done(Rest, Stack, Opts) end}; decimal(<>, Stack, ?comments_enabled(Opts), Acc) -> maybe_comment(Rest, fun(Resume) -> decimal(Resume, Stack, Opts, Acc) end); decimal(Bin, [], ?stream_mode(Opts), Acc) -> - emit({float, lists:reverse(Acc)}, fun() -> - emit(end_json, fun() -> start(Bin, [], Opts) end) - end); + {{float, lists:reverse(Acc)}, fun() -> + {end_json, fun() -> start(Bin, [], Opts) end} + end}; decimal(<<>>, [], Opts, Acc) -> - emit({float, lists:reverse(Acc)}, fun() -> - emit(end_json, fun() -> emit(incomplete, fun(Stream) -> maybe_done(Stream, [], Opts) end) - end) - end); + {{float, lists:reverse(Acc)}, fun() -> + {end_json, fun() -> {incomplete, fun(Stream) -> maybe_done(Stream, [], Opts) end} + end} + end}; decimal(Bin, Stack, Opts, Acc) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> decimal(<>, Stack, Opts, Acc) end) + ; _ -> {incomplete, fun(Stream) -> decimal(<>, Stack, Opts, Acc) end} end. @@ -527,7 +513,7 @@ e(<>, Stack, Opts, Acc) when S =:= ?positive; S =:= ?n e(Bin, Stack, Opts, Acc) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> e(<>, Stack, Opts, Acc) end) + ; _ -> {incomplete, fun(Stream) -> e(<>, Stack, Opts, Acc) end} end. @@ -536,43 +522,43 @@ ex(<>, Stack, Opts, Acc) when S =:= ?zero; ?is_nonzero ex(Bin, Stack, Opts, Acc) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> ex(<>, Stack, Opts, Acc) end) + ; _ -> {incomplete, fun(Stream) -> ex(<>, Stack, Opts, Acc) end} end. exp(<>, Stack, Opts, Acc) when ?is_nonzero(S) -> exp(Rest, Stack, Opts, [S] ++ Acc); exp(<>, [object|Stack], Opts, Acc) -> - emit({float, lists:reverse(Acc)}, fun() -> - emit(end_object, fun() -> maybe_done(Rest, Stack, Opts) end) - end); + {{float, lists:reverse(Acc)}, fun() -> + {end_object, fun() -> maybe_done(Rest, Stack, Opts) end} + end}; exp(<>, [array|Stack], Opts, Acc) -> - emit({float, lists:reverse(Acc)}, fun() -> - emit(end_array, fun() -> maybe_done(Rest, Stack, Opts) end) - end); + {{float, lists:reverse(Acc)}, fun() -> + {end_array, fun() -> maybe_done(Rest, Stack, Opts) end} + end}; exp(<>, [object|Stack], Opts, Acc) -> - emit({float, lists:reverse(Acc)}, fun() -> key(Rest, [key|Stack], Opts) end); + {{float, lists:reverse(Acc)}, fun() -> key(Rest, [key|Stack], Opts) end}; exp(<>, [array|_] = Stack, Opts, Acc) -> - emit({float, lists:reverse(Acc)}, fun() -> value(Rest, Stack, Opts) end); + {{float, lists:reverse(Acc)}, fun() -> value(Rest, Stack, Opts) end}; exp(<>, Stack, Opts, Acc) -> exp(Rest, Stack, Opts, [?zero] ++ Acc); exp(<>, Stack, Opts, Acc) when ?is_whitespace(S) -> - emit({float, lists:reverse(Acc)}, fun() -> maybe_done(Rest, Stack, Opts) end); + {{float, lists:reverse(Acc)}, fun() -> maybe_done(Rest, Stack, Opts) end}; exp(<>, Stack, ?comments_enabled(Opts), Acc) -> maybe_comment(Rest, fun(Resume) -> exp(Resume, Stack, Opts, Acc) end); exp(Bin, [], ?stream_mode(Opts), Acc) -> - emit({float, lists:reverse(Acc)}, fun() -> - emit(end_json, fun() -> start(Bin, [], Opts) end) - end); + {{float, lists:reverse(Acc)}, fun() -> + {end_json, fun() -> start(Bin, [], Opts) end} + end}; exp(<<>>, [], Opts, Acc) -> - emit({float, lists:reverse(Acc)}, fun() -> - emit(end_json, fun() -> emit(incomplete, fun(Stream) -> maybe_done(Stream, [], Opts) end) - end) - end); + {{float, lists:reverse(Acc)}, fun() -> + {end_json, fun() -> {incomplete, fun(Stream) -> maybe_done(Stream, [], Opts) end} + end} + end}; exp(Bin, Stack, Opts, Acc) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> exp(<>, Stack, Opts, Acc) end) + ; _ -> {incomplete, fun(Stream) -> exp(<>, Stack, Opts, Acc) end} end. @@ -581,7 +567,7 @@ tr(<<$r/?encoding, Rest/binary>>, Stack, Opts) -> tr(Bin, Stack, Opts) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> tr(<>, Stack, Opts) end) + ; _ -> {incomplete, fun(Stream) -> tr(<>, Stack, Opts) end} end. @@ -590,16 +576,16 @@ tru(<<$u/?encoding, Rest/binary>>, Stack, Opts) -> tru(Bin, Stack, Opts) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> tru(<>, Stack, Opts) end) + ; _ -> {incomplete, fun(Stream) -> tru(<>, Stack, Opts) end} end. true(<<$e/?encoding, Rest/binary>>, Stack, Opts) -> - emit({literal, true}, fun() -> maybe_done(Rest, Stack, Opts) end); + {{literal, true}, fun() -> maybe_done(Rest, Stack, Opts) end}; true(Bin, Stack, Opts) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> true(<>, Stack, Opts) end) + ; _ -> {incomplete, fun(Stream) -> true(<>, Stack, Opts) end} end. @@ -608,7 +594,7 @@ fa(<<$a/?encoding, Rest/binary>>, Stack, Opts) -> fa(Bin, Stack, Opts) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> fa(<>, Stack, Opts) end) + ; _ -> {incomplete, fun(Stream) -> fa(<>, Stack, Opts) end} end. @@ -617,7 +603,7 @@ fal(<<$l/?encoding, Rest/binary>>, Stack, Opts) -> fal(Bin, Stack, Opts) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> fal(<>, Stack, Opts) end) + ; _ -> {incomplete, fun(Stream) -> fal(<>, Stack, Opts) end} end. @@ -626,16 +612,16 @@ fals(<<$s/?encoding, Rest/binary>>, Stack, Opts) -> fals(Bin, Stack, Opts) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> fals(<>, Stack, Opts) end) + ; _ -> {incomplete, fun(Stream) -> fals(<>, Stack, Opts) end} end. false(<<$e/?encoding, Rest/binary>>, Stack, Opts) -> - emit({literal, false}, fun() -> maybe_done(Rest, Stack, Opts) end); + {{literal, false}, fun() -> maybe_done(Rest, Stack, Opts) end}; false(Bin, Stack, Opts) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> false(<>, Stack, Opts) end) + ; _ -> {incomplete, fun(Stream) -> false(<>, Stack, Opts) end} end. @@ -644,7 +630,7 @@ nu(<<$u/?encoding, Rest/binary>>, Stack, Opts) -> nu(Bin, Stack, Opts) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> nu(<>, Stack, Opts) end) + ; _ -> {incomplete, fun(Stream) -> nu(<>, Stack, Opts) end} end. @@ -653,16 +639,16 @@ nul(<<$l/?encoding, Rest/binary>>, Stack, Opts) -> nul(Bin, Stack, Opts) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> nul(<>, Stack, Opts) end) + ; _ -> {incomplete, fun(Stream) -> nul(<>, Stack, Opts) end} end. null(<<$l/?encoding, Rest/binary>>, Stack, Opts) -> - emit({literal, null}, fun() -> maybe_done(Rest, Stack, Opts) end); + {{literal, null}, fun() -> maybe_done(Rest, Stack, Opts) end}; null(Bin, Stack, Opts) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> null(<>, Stack, Opts) end) + ; _ -> {incomplete, fun(Stream) -> null(<>, Stack, Opts) end} end. @@ -677,7 +663,7 @@ maybe_comment(<>, Resume) -> maybe_comment(Bin, Resume) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> maybe_comment(<>, Resume) end) + ; _ -> {incomplete, fun(Stream) -> maybe_comment(<>, Resume) end} end. @@ -688,7 +674,7 @@ comment(<<_/?encoding, Rest/binary>>, Resume) -> comment(Bin, Resume) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> comment(<>, Resume) end) + ; _ -> {incomplete, fun(Stream) -> comment(<>, Resume) end} end. @@ -699,5 +685,5 @@ maybe_comment_done(<<_/?encoding, Rest/binary>>, Resume) -> maybe_comment_done(Bin, Resume) -> case byte_size(Bin) >= ?symbol_size of true -> {error, badjson} - ; _ -> emit(incomplete, fun(Stream) -> maybe_comment_done(<>, Resume) end) + ; _ -> {incomplete, fun(Stream) -> maybe_comment_done(<>, Resume) end} end. \ No newline at end of file diff --git a/src/jsx_types.hrl b/src/jsx_types.hrl index d67d381..d0a1677 100644 --- a/src/jsx_types.hrl +++ b/src/jsx_types.hrl @@ -44,7 +44,6 @@ | start_array | end_array | end_json - | reset | {key, unicode_string()} | {string, unicode_string()} | {integer, unicode_string()} @@ -59,4 +58,9 @@ -type jsx_parser() :: fun((json()) -> {[jsx_event(),...], jsx_parser()} | {incomplete, jsx_parser()} | {error, badjson} -). \ No newline at end of file +). + + +-type parser_result() :: {jsx_event(), fun(() -> parser_result())} + | {incomplete, jsx_parser()} + | {error, badjson}. \ No newline at end of file