extend resume api to parser

This commit is contained in:
alisdair sullivan 2013-03-05 21:10:33 -08:00
parent 07836d5d58
commit dd302eb7b4
2 changed files with 43 additions and 29 deletions

View file

@ -27,11 +27,11 @@
-export([is_json/1, is_json/2, is_term/1, is_term/2]).
-export([format/1, format/2, minify/1, prettify/1]).
-export([encoder/3, decoder/3, parser/3]).
-export([resume/3]).
%% old api
-export([term_to_json/1, term_to_json/2, json_to_term/1, json_to_term/2]).
-export([to_json/1, to_json/2]).
-export([to_term/1, to_term/2]).
-export([resume/3]).
-export_type([json_term/0, json_text/0, token/0]).
-export_type([encoder/0, decoder/0, parser/0, internal_state/0]).
@ -157,7 +157,9 @@ parser(Handler, State, Config) -> jsx_parser:parser(Handler, State, Config).
-opaque internal_state() :: tuple().
-spec resume(Term::json_text(), InternalState::internal_state(), Config::list()) -> any().
-spec resume(Term::json_text() | token(), InternalState::internal_state(), Config::list()) -> any().
resume(Term, {decoder, State, Handler, Acc, Stack}, Config) ->
jsx_decoder:resume(Term, State, Handler, Acc, Stack, jsx_utils:parse_config(Config)).
jsx_decoder:resume(Term, State, Handler, Acc, Stack, jsx_utils:parse_config(Config));
resume(Term, {parser, State, Handler, Stack}, Config) ->
jsx_parser:resume(Term, State, Handler, Stack, jsx_utils:parse_config(Config)).

View file

@ -23,7 +23,7 @@
-module(jsx_parser).
-export([parser/3]).
-export([parser/3, resume/5]).
-spec parser(Handler::module(), State::any(), Config::jsx:config()) -> jsx:parser().
@ -32,6 +32,26 @@ parser(Handler, State, Config) ->
fun(Tokens) -> value(Tokens, {Handler, Handler:init(State)}, [], jsx_utils:parse_config(Config)) end.
%% resume allows continuation from interrupted decoding without having to explicitly export
%% all states
-spec resume(
Rest::binary(),
State::atom(),
Handler::{atom(), any()},
Stack::list(atom()),
Config::jsx:config()
) -> jsx:parser().
resume(Rest, State, Handler, Stack, Config) ->
case State of
value -> value(Rest, Handler, Stack, Config);
object -> object(Rest, Handler, Stack, Config);
array -> array(Rest, Handler, Stack, Config);
maybe_done -> maybe_done(Rest, Handler, Stack, Config);
done -> done(Rest, Handler, Stack, Config)
end.
-include("jsx_config.hrl").
@ -47,26 +67,18 @@ parser(Handler, State, Config) ->
-endif.
-ifndef(incomplete).
-define(incomplete(State, Handler, Stack, Config),
case Config#config.incomplete_handler of
false ->
{incomplete, fun(end_stream) ->
case State([end_json],
Handler,
Stack,
Config) of
{incomplete, _} -> ?error(State, [], Handler, Stack, Config)
; Events -> Events
end
; (Tokens) ->
State(Tokens, Handler, Stack, Config)
end
};
F -> F([], {parser, State, Handler, Stack}, jsx_utils:config_to_list(Config))
end
).
-endif.
incomplete(State, Handler, Stack, Config=#config{incomplete_handler=false}) ->
{incomplete, fun(end_stream) ->
case resume([end_json], State, Handler, Stack, Config) of
{incomplete, _} -> ?error(State, [], Handler, Stack, Config);
Else -> Else
end;
(Tokens) ->
resume(Tokens, State, Handler, Stack, Config)
end
};
incomplete(State, Handler, Stack, Config=#config{incomplete_handler=F}) ->
F([], {parser, State, Handler, Stack}, jsx_utils:config_to_list(Config)).
handle_event([], Handler, _Config) -> Handler;
@ -123,7 +135,7 @@ value([{string, String}|Tokens], Handler, Stack, Config) when is_binary(String)
value([String|Tokens], Handler, Stack, Config) when is_binary(String) ->
value([{string, String}] ++ Tokens, Handler, Stack, Config);
value([], Handler, Stack, Config) ->
?incomplete(value, Handler, Stack, Config);
incomplete(value, Handler, Stack, Config);
value(BadTokens, Handler, Stack, Config) when is_list(BadTokens) ->
?error(value, BadTokens, Handler, Stack, Config);
value(Token, Handler, Stack, Config) ->
@ -144,14 +156,14 @@ object([Key|Tokens], Handler, Stack, Config) when is_atom(Key); is_binary(Key) -
Error -> Error
end;
object([], Handler, Stack, Config) ->
?incomplete(object, Handler, Stack, Config);
incomplete(object, Handler, Stack, Config);
object(Token, Handler, Stack, Config) ->
object([Token], Handler, Stack, Config).
array([end_array|Tokens], Handler, [array|Stack], Config) ->
maybe_done(Tokens, handle_event(end_array, Handler, Config), Stack, Config);
array([], Handler, Stack, Config) ->
?incomplete(array, Handler, Stack, Config);
incomplete(array, Handler, Stack, Config);
array(Tokens, Handler, Stack, Config) when is_list(Tokens) ->
value(Tokens, Handler, Stack, Config);
array(Token, Handler, Stack, Config) ->
@ -164,14 +176,14 @@ maybe_done(Tokens, Handler, [object|_] = Stack, Config) when is_list(Tokens) ->
maybe_done(Tokens, Handler, [array|_] = Stack, Config) when is_list(Tokens) ->
array(Tokens, Handler, Stack, Config);
maybe_done([], Handler, Stack, Config) ->
?incomplete(maybe_done, Handler, Stack, Config);
incomplete(maybe_done, Handler, Stack, Config);
maybe_done(BadTokens, Handler, Stack, Config) when is_list(BadTokens) ->
?error(maybe_done, BadTokens, Handler, Stack, Config);
maybe_done(Token, Handler, Stack, Config) ->
maybe_done([Token], Handler, Stack, Config).
done([], Handler, [], Config=#config{explicit_end=true}) ->
?incomplete(done, Handler, [], Config);
incomplete(done, Handler, [], Config);
done(Tokens, Handler, [], Config) when Tokens == [end_json]; Tokens == [] ->
{_, State} = handle_event(end_json, Handler, Config),
State;