Skip to content

Instantly share code, notes, and snippets.

@sile
Last active August 29, 2015 14:23
Show Gist options
  • Select an option

  • Save sile/d0fed8334c866a6c5b90 to your computer and use it in GitHub Desktop.

Select an option

Save sile/d0fed8334c866a6c5b90 to your computer and use it in GitHub Desktop.
OTP18.0でのカバレッジ出力確認
# package: http://packages.erlang-solutions.com/erlang/esl-erlang/FLAVOUR_3_general/esl-erlang_18.0-1~ubuntu~precise_amd64.deb
$ erl +V
Erlang (SMP,ASYNC_THREADS,HIPE) (BEAM) emulator version 7.0
$ git clone git@github.com:sile/jsone
$ cd jsone/
$ make init
$ make eunit
$ w3m -dump .eunit/jsone_decode.COVER.html
File generated from /path/to/jsone/.eunit/jsone_decode.erl by COVER 2015-06-26 at 02:07:11
****************************************************************************
| %%% @doc JSON decoding module
| %%% @private
| %%% @end
| %%%
| %%% Copyright (c) 2013-2015, Takeru Ohta <phjgt308@gmail.com>
| %%%
| %%% The MIT License
| %%%
| %%% Permission is hereby granted, free of charge, to any person obtaining a copy
| %%% of this software and associated documentation files (the "Software"), to deal
| %%% in the Software without restriction, including without limitation the rights
| %%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
| %%% copies of the Software, and to permit persons to whom the Software is
| %%% furnished to do so, subject to the following conditions:
| %%%
| %%% The above copyright notice and this permission notice shall be included in
| %%% all copies or substantial portions of the Software.
| %%%
| %%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
| %%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
| %%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
| %%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
| %%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
| %%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
| %%% THE SOFTWARE.
| %%%
| %%%---------------------------------------------------------------------------------------
| -module(jsone_decode).
|
| %%--------------------------------------------------------------------------------
| %% Exported API
| %%--------------------------------------------------------------------------------
| -export([decode/1, decode/2]).
|
| %%--------------------------------------------------------------------------------
| %% Macros & Records & Types
| %%--------------------------------------------------------------------------------
| -define(ERROR(Function, Args), {error, {badarg, [{?MODULE, Function, Args, [{line, ?LINE}]}]}}).
|
| -type next() :: {array_next, [jsone:json_value()]}
| | {object_value, jsone:json_object_members()}
| | {object_next, jsone:json_string(), jsone:json_object_members()}.
|
| -type whitespace_next() :: value
| | array
| | object
| | {array_next, [jsone:json_value()]}
| | {object_key, jsone:json_object_members()}
| | {object_value, jsone:json_string(), jsone:json_object_members()}
| | {object_next, jsone:json_object_members()}.
|
| -type decode_result() :: {ok, jsone:json_value(), Rest::binary()} | {error, {Reason::term(), [erlang:stack_item()]}}.
|
| -record(decode_opt_v1, { object_format=tuple :: tuple | proplist | map}).
| -define(OPT, #decode_opt_v1).
| -type opt() :: #decode_opt_v1{}.
|
| %%--------------------------------------------------------------------------------
| %% Exported Functions
| %%--------------------------------------------------------------------------------
| -spec decode(binary()) -> decode_result().
| decode(Json) ->
58..| decode(Json, []).
|
| -spec decode(binary(), [jsone:decode_option()]) -> decode_result().
| decode(<<Json/binary>>, Options) ->
63..| Opt = parse_options(Options),
63..| whitespace(Json, value, [], <<"">>, Opt).
|
| %%--------------------------------------------------------------------------------
| %% Internal Functions
| %%--------------------------------------------------------------------------------
| -spec next(binary(), jsone:json_value(), [next()], binary(), opt()) -> decode_result().
| next(<<Bin/binary>>, Value, [], _Buf, _Opt) ->
40..| {ok, Value, Bin};
| next(<<Bin/binary>>, Value, [Next | Nexts], Buf, Opt) ->
65..| case Next of
26..| {array_next, Values} -> whitespace(Bin, {array_next, [Value | Values]}, Nexts, Buf, Opt);
20..| {object_value, Members} -> whitespace(Bin, {object_value, Value, Members}, Nexts, Buf, Opt);
19..| {object_next, Key, Members} -> whitespace(Bin, {object_next, [{Key, Value} | Members]}, Nexts, Buf, Opt)
| end.
|
| -spec whitespace(binary(), whitespace_next(), [next()], binary(), opt()) -> decode_result().
40..| whitespace(<<$ , Bin/binary>>, Next, Nexts, Buf, Opt) -> whitespace(Bin, Next, Nexts, Buf, Opt);
4..| whitespace(<<$\t, Bin/binary>>, Next, Nexts, Buf, Opt) -> whitespace(Bin, Next, Nexts, Buf, Opt);
4..| whitespace(<<$\r, Bin/binary>>, Next, Nexts, Buf, Opt) -> whitespace(Bin, Next, Nexts, Buf, Opt);
5..| whitespace(<<$\n, Bin/binary>>, Next, Nexts, Buf, Opt) -> whitespace(Bin, Next, Nexts, Buf, Opt);
| whitespace(<<Bin/binary>>, Next, Nexts, Buf, Opt) ->
204..| case Next of
99..| value -> value(Bin, Nexts, Buf, Opt);
12..| array -> array(Bin, Nexts, Buf, Opt);
18..| object -> object(Bin, Nexts, Buf, Opt);
10..| {object_key, Members} -> object_key(Bin, Members, Nexts, Buf, Opt);
26..| {array_next, Values} -> array_next(Bin, Values, Nexts, Buf, Opt);
20..| {object_value, Key, Members} -> object_value(Bin, Key, Members, Nexts, Buf, Opt);
19..| {object_next, Members} -> object_next(Bin, Members, Nexts, Buf, Opt)
| end.
|
| -spec value(binary(), [next()], binary(), opt()) -> decode_result().
2..| value(<<"false", Bin/binary>>, Nexts, Buf, Opt) -> next(Bin, false, Nexts, Buf, Opt);
2..| value(<<"true", Bin/binary>>, Nexts, Buf, Opt) -> next(Bin, true, Nexts, Buf, Opt);
6..| value(<<"null", Bin/binary>>, Nexts, Buf, Opt) -> next(Bin, null, Nexts, Buf, Opt);
12..| value(<<$[, Bin/binary>>, Nexts, Buf, Opt) -> whitespace(Bin, array, Nexts, Buf, Opt);
18..| value(<<${, Bin/binary>>, Nexts, Buf, Opt) -> whitespace(Bin, object, Nexts, Buf, Opt);
25..| value(<<$", Bin/binary>>, Nexts, Buf, Opt) -> string(Bin, byte_size(Buf), Nexts, Buf, Opt);
44..| value(<<Bin/binary>>, Nexts, Buf, Opt) -> number(Bin, Nexts, Buf, Opt).
|
| -spec array(binary(), [next()], binary(), opt()) -> decode_result().
2..| array(<<$], Bin/binary>>, Nexts, Buf, Opt) -> next(Bin, [], Nexts, Buf, Opt);
10..| array(<<Bin/binary>>, Nexts, Buf, Opt) -> value(Bin, [{array_next, []} | Nexts], Buf, Opt).
|
| -spec array_next(binary(), [jsone:json_value()], [next()], binary(), opt()) -> decode_result().
7..| array_next(<<$], Bin/binary>>, Values, Nexts, Buf, Opt) -> next(Bin, lists:reverse(Values), Nexts, Buf, Opt);
17..| array_next(<<$,, Bin/binary>>, Values, Nexts, Buf, Opt) -> whitespace(Bin, value, [{array_next, Values} | Nexts], Buf, Opt);
2..| array_next(Bin, Values, Nexts, Buf, Opt) -> ?ERROR(array_next, [Bin, Values, Nexts, Buf, Opt]).
|
| -spec object(binary(), [next()], binary(), opt()) -> decode_result().
4..| object(<<$}, Bin/binary>>, Nexts, Buf, Opt) -> next(Bin, make_object([], Opt), Nexts, Buf, Opt);
14..| object(<<Bin/binary>>, Nexts, Buf, Opt) -> object_key(Bin, [], Nexts, Buf, Opt).
|
| -spec object_key(binary(), jsone:json_object_members(), [next()], binary(), opt()) -> decode_result().
20..| object_key(<<$", Bin/binary>>, Members, Nexts, Buf, Opt) -> string(Bin, byte_size(Buf), [{object_value, Members} | Nexts], Buf, Opt);
4..| object_key(<<Bin/binary>>, Members, Nexts, Buf, Opt) -> ?ERROR(object_key, [Bin, Members, Nexts, Buf, Opt]).
|
| -spec object_value(binary(), jsone:json_string(), jsone:json_object_members(), [next()], binary(), opt()) -> decode_result().
19..| object_value(<<$:, Bin/binary>>, Key, Members, Nexts, Buf, Opt) -> whitespace(Bin, value, [{object_next, Key, Members} | Nexts], Buf, Opt);
1..| object_value(Bin, Key, Members, Nexts, Buf, Opt) -> ?ERROR(object_value, [Bin, Key, Members, Nexts, Buf, Opt]).
|
| -spec object_next(binary(), jsone:json_object_members(), [next()], binary(), opt()) -> decode_result().
7..| object_next(<<$}, Bin/binary>>, Members, Nexts, Buf, Opt) -> next(Bin, make_object(Members, Opt), Nexts, Buf, Opt);
10..| object_next(<<$,, Bin/binary>>, Members, Nexts, Buf, Opt) -> whitespace(Bin, {object_key, Members}, Nexts, Buf, Opt);
2..| object_next(Bin, Members, Nexts, Buf, Opt) -> ?ERROR(object_next, [Bin, Members, Nexts, Buf, Opt]).
|
| -spec string(binary(), non_neg_integer(), [next()], binary(), opt()) -> decode_result().
| string(<<Bin/binary>>, Start, Nexts, Buf, Opt) ->
73..| string(Bin, Bin, Start, Nexts, Buf, Opt).
|
| -spec string(binary(), binary(), non_neg_integer(), [next()], binary(), opt()) -> decode_result().
| string(<<$", Bin/binary>>, Base, Start, Nexts, Buf, Opt) ->
40..| Prefix = binary:part(Base, 0, byte_size(Base) - byte_size(Bin) - 1),
40..| case Start =:= byte_size(Buf) of
34..| true -> next(Bin, Prefix, Nexts, Buf, Opt);
| false ->
6..| Buf2 = <<Buf/binary, Prefix/binary>>,
6..| next(Bin, binary:part(Buf2, Start, byte_size(Buf2) - Start), Nexts, Buf2, Opt)
| end;
| string(<<$\\, B/binary>>, Base, Start, Nexts, Buf, Opt) ->
33..| Prefix = binary:part(Base, 0, byte_size(Base) - byte_size(B) - 1),
33..| case B of
1..| <<$", Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $">>, Opt);
1..| <<$/, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $/>>, Opt);
1..| <<$\\,Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\\>>, Opt);
1..| <<$b, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\b>>, Opt);
1..| <<$f, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\f>>, Opt);
1..| <<$n, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\n>>, Opt);
1..| <<$r, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\r>>, Opt);
1..| <<$t, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\t>>, Opt);
24..| <<$u, Bin/binary>> -> unicode_string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary>>, Opt);
1..| _ -> ?ERROR(string, [<<$\\, B/binary>>, Base, Start, Nexts, Buf, Opt])
| end;
| string(<<C, Bin/binary>>, Base, Start, Nexts, Buf, Opt) when 16#20 =< C ->
107..| string(Bin, Base, Start, Nexts, Buf, Opt).
|
| -spec unicode_string(binary(), non_neg_integer(), [next()], binary(), opt()) -> decode_result().
| unicode_string(<<N:4/binary, Bin/binary>>, Start, Nexts, Buf, Opt) ->
23..| case binary_to_integer(N, 16) of
| High when 16#D800 =< High, High =< 16#DBFF ->
| %% surrogate pair
5..| case Bin of
| <<$\\, $u, N2:4/binary, Bin2/binary>> ->
4..| case binary_to_integer(N2, 16) of
| Low when 16#DC00 =< Low, Low =< 16#DFFF ->
3..| Unicode = 16#10000 + (High - 16#D800) * 16#400 + (Low - 16#DC00),
3..| string(Bin2, Start, Nexts, unicode_to_utf8(Unicode, Buf), Opt);
1..| _ -> ?ERROR(unicode_string, [<<N/binary, Bin/binary>>, Start, Nexts, Buf, Opt])
| end;
1..| _ -> ?ERROR(unicode_string, [<<N/binary, Bin/binary>>, Start, Nexts, Buf, Opt])
| end;
| Unicode when 16#DC00 =< Unicode, Unicode =< 16#DFFF -> % second part of surrogate pair (without first part)
1..| ?ERROR(unicode_string, [<<N/binary, Bin/binary>>, Start, Nexts, Buf, Opt]);
| Unicode ->
17..| string(Bin, Start, Nexts, unicode_to_utf8(Unicode, Buf), Opt)
| end;
| unicode_string(Bin, Start, Nexts, Buf, Opt) ->
1..| ?ERROR(unicode_string, [Bin, Start, Nexts, Buf, Opt]).
|
| -spec unicode_to_utf8(0..1114111, binary()) -> binary().
| unicode_to_utf8(Code, Buf) when Code < 16#80 ->
3..| <<Buf/binary, Code>>;
| unicode_to_utf8(Code, Buf) when Code < 16#800 ->
2..| A = 2#11000000 bor (Code bsr 6),
2..| B = 2#10000000 bor (Code band 2#111111),
2..| <<Buf/binary, A, B>>;
| unicode_to_utf8(Code, Buf) when Code < 16#10000 ->
12..| A = 2#11100000 bor (Code bsr 12),
12..| B = 2#10000000 bor ((Code bsr 6) band 2#111111),
12..| C = 2#10000000 bor (Code band 2#111111),
12..| <<Buf/binary, A, B, C>>;
| unicode_to_utf8(Code, Buf) ->
3..| A = 2#11110000 bor (Code bsr 18),
3..| B = 2#10000000 bor ((Code bsr 12) band 2#111111),
3..| C = 2#10000000 bor ((Code bsr 6) band 2#111111),
3..| D = 2#10000000 bor (Code band 2#111111),
3..| <<Buf/binary, A, B, C, D>>.
|
| -spec number(binary(), [next()], binary(), opt()) -> decode_result().
3..| number(<<$-, Bin/binary>>, Nexts, Buf, Opt) -> number_integer_part(Bin, -1, Nexts, Buf, Opt);
41..| number(<<Bin/binary>>, Nexts, Buf, Opt) -> number_integer_part(Bin, 1, Nexts, Buf, Opt).
|
| -spec number_integer_part(binary(), 1|-1, [next()], binary(), opt()) -> decode_result().
| number_integer_part(<<$0, Bin/binary>>, Sign, Nexts, Buf, Opt) ->
15..| number_fraction_part(Bin, Sign, 0, Nexts, Buf, Opt);
| number_integer_part(<<C, Bin/binary>>, Sign, Nexts, Buf, Opt) when $1 =< C, C =< $9 ->
26..| number_integer_part_rest(Bin, C - $0, Sign, Nexts, Buf, Opt);
| number_integer_part(Bin, Sign, Nexts, Buf, Opt) ->
3..| ?ERROR(number_integer_part, [Bin, Sign, Nexts, Buf, Opt]).
|
| -spec number_integer_part_rest(binary(), non_neg_integer(), 1|-1, [next()], binary(), opt()) -> decode_result().
| number_integer_part_rest(<<C, Bin/binary>>, N, Sign, Nexts, Buf, Opt) when $0 =< C, C =< $9 ->
89..| number_integer_part_rest(Bin, N * 10 + C - $0, Sign, Nexts, Buf, Opt);
| number_integer_part_rest(<<Bin/binary>>, N, Sign, Nexts, Buf, Opt) ->
26..| number_fraction_part(Bin, Sign, N, Nexts, Buf, Opt).
|
| -spec number_fraction_part(binary(), 1|-1, non_neg_integer(), [next()], binary(), opt()) -> decode_result().
| number_fraction_part(<<$., Bin/binary>>, Sign, Int, Nexts, Buf, Opt) ->
13..| number_fraction_part_rest(Bin, Sign, Int, 0, Nexts, Buf, Opt);
| number_fraction_part(<<Bin/binary>>, Sign, Int, Nexts, Buf, Opt) ->
28..| number_exponation_part(Bin, Sign * Int, 0, Nexts, Buf, Opt).
|
| -spec number_fraction_part_rest(binary(), 1|-1, non_neg_integer(), non_neg_integer(), [next()], binary(), opt()) -> decode_result().
| number_fraction_part_rest(<<C, Bin/binary>>, Sign, N, DecimalOffset, Nexts, Buf, Opt) when $0 =< C, C =< $9 ->
29..| number_fraction_part_rest(Bin, Sign, N * 10 + C - $0, DecimalOffset + 1, Nexts, Buf, Opt);
| number_fraction_part_rest(<<Bin/binary>>, Sign, N, DecimalOffset, Nexts, Buf, Opt) when DecimalOffset > 0 ->
11..| number_exponation_part(Bin, Sign * N, DecimalOffset, Nexts, Buf, Opt);
| number_fraction_part_rest(Bin, Sign, N, DecimalOffset, Nexts, Buf, Opt) ->
2..| ?ERROR(number_fraction_part_rest, [Bin, Sign, N, DecimalOffset, Nexts, Buf, Opt]).
|
| -spec number_exponation_part(binary(), integer(), non_neg_integer(), [next()], binary(), opt()) -> decode_result().
| number_exponation_part(<<$e, $+, Bin/binary>>, N, DecimalOffset, Nexts, Buf, Opt) ->
1..| number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts, Buf, Opt);
| number_exponation_part(<<$E, $+, Bin/binary>>, N, DecimalOffset, Nexts, Buf, Opt) ->
1..| number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts, Buf, Opt);
| number_exponation_part(<<$e, $-, Bin/binary>>, N, DecimalOffset, Nexts, Buf, Opt) ->
4..| number_exponation_part(Bin, N, DecimalOffset, -1, 0, true, Nexts, Buf, Opt);
| number_exponation_part(<<$E, $-, Bin/binary>>, N, DecimalOffset, Nexts, Buf, Opt) ->
1..| number_exponation_part(Bin, N, DecimalOffset, -1, 0, true, Nexts, Buf, Opt);
| number_exponation_part(<<$e, Bin/binary>>, N, DecimalOffset, Nexts, Buf, Opt) ->
3..| number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts, Buf, Opt);
| number_exponation_part(<<$E, Bin/binary>>, N, DecimalOffset, Nexts, Buf, Opt) ->
1..| number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts, Buf, Opt);
| number_exponation_part(<<Bin/binary>>, N, DecimalOffset, Nexts, Buf, Opt) ->
28..| case DecimalOffset of
26..| 0 -> next(Bin, N, Nexts, Buf, Opt);
2..| _ -> next(Bin, N / math:pow(10, DecimalOffset), Nexts, Buf, Opt)
| end.
|
| -spec number_exponation_part(binary(), integer(), non_neg_integer(), 1|-1, non_neg_integer(), boolean(), [next()], binary(), opt()) -> decode_result().
| number_exponation_part(<<C, Bin/binary>>, N, DecimalOffset, ExpSign, Exp, _, Nexts, Buf, Opt) when $0 =< C, C =< $9 ->
7..| number_exponation_part(Bin, N, DecimalOffset, ExpSign, Exp * 10 + C - $0, false, Nexts, Buf, Opt);
| number_exponation_part(<<Bin/binary>>, N, DecimalOffset, ExpSign, Exp, false, Nexts, Buf, Opt) ->
7..| Pos = ExpSign * Exp - DecimalOffset,
7..| next(Bin, N * math:pow(10, Pos), Nexts, Buf, Opt);
| number_exponation_part(Bin, N, DecimalOffset, ExpSign, Exp, IsFirst, Nexts, Buf, Opt) ->
4..| ?ERROR(number_exponation_part, [Bin, N, DecimalOffset, ExpSign, Exp, IsFirst, Nexts, Buf, Opt]).
|
| -spec make_object(jsone:json_object_members(), opt()) -> jsone:json_object().
6..| make_object(Members, ?OPT{object_format = tuple}) -> {lists:reverse(Members)};
3..| make_object(Members, ?OPT{object_format = map}) -> maps:from_list(Members);
1..| make_object([], _) -> [{}];
1..| make_object(Members, _) -> lists:reverse(Members).
|
| -spec parse_options([jsone:decode_option()]) -> opt().
| parse_options(Options) ->
63..| parse_option(Options, ?OPT{}).
|
| -spec parse_option([jsone:decode_option()], opt()) -> opt().
63..| parse_option([], Opt) -> Opt;
| parse_option([{object_format,F}|T], Opt) when F =:= tuple; F =:= proplist; F =:= map ->
5..| parse_option(T, Opt?OPT{object_format=F}).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment