From dd302eb7b49abca537eaa1598b1f4153cfeb2c47 Mon Sep 17 00:00:00 2001 From: alisdair sullivan Date: Tue, 5 Mar 2013 21:10:33 -0800 Subject: [PATCH] extend resume api to parser --- src/jsx.erl | 8 +++--- src/jsx_parser.erl | 64 +++++++++++++++++++++++++++------------------- 2 files changed, 43 insertions(+), 29 deletions(-) diff --git a/src/jsx.erl b/src/jsx.erl index 4477db6..8d209f4 100644 --- a/src/jsx.erl +++ b/src/jsx.erl @@ -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)). \ No newline at end of file + 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)). \ No newline at end of file diff --git a/src/jsx_parser.erl b/src/jsx_parser.erl index 0e3cd5a..b41f89b 100644 --- a/src/jsx_parser.erl +++ b/src/jsx_parser.erl @@ -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;