Просмотр исходного кода

specおよびedocコメントを追加

Takeru Ohta 11 лет назад
Родитель
Сommit
27423dcf2a
5 измененных файлов с 160 добавлено и 38 удалено
  1. 21 0
      COPYING
  2. 0 3
      Makefile
  3. 0 1
      rebar.config
  4. 50 12
      src/jsone.erl
  5. 89 22
      src/jsone_decode.erl

+ 21 - 0
COPYING

@@ -0,0 +1,21 @@
+The MIT License
+
+Copyright (c) 2013 Takeru Ohta <phjgt308@gmail.com>
+
+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.

+ 0 - 3
Makefile

@@ -24,9 +24,6 @@ eunit:
 
 edoc:
 	@./rebar doc skip_deps=true
-	find doc -name '*.html' | xargs sed -i.orig 's/ISO-8859-1/UTF-8/'
-	ERL_LIBS=deps/edown deps/edown/make_doc
-	sed -i.org 's_http://github.com/esl/.*doc_doc_' README.md && rm README.md.org
 
 start: compile
 	erl -sname $(NODE) -pz ebin deps/*/ebin \

+ 0 - 1
rebar.config

@@ -26,5 +26,4 @@
  
 {deps,
   [
-%   {edown, ".*", {git, "git://github.com/sile/edown.git", "master"}}
   ]}.

+ 50 - 12
src/jsone.erl

@@ -1,7 +1,36 @@
+%%% @doc JSON decoding/encoding module
+%%% @end
+%%%
+%%% Copyright (c) 2013, 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).
 
+%%--------------------------------------------------------------------------------
+%% Exported API
+%%--------------------------------------------------------------------------------
 -export([
-         decode/1, decode/2
+         decode/1
         ]).
 
 -export_type([
@@ -10,18 +39,27 @@
               json_string/0,
               json_array/0,
               json_object/0,
+              json_object_members/0,
               json_boolean/0
              ]).
 
--type json_value() :: json_number() | json_string() | json_array() | json_object() | json_boolean() | null.
--type json_number() :: number().
--type json_string() :: binary().
--type json_array() :: [json_value()].
--type json_object() :: {object, [{json_string(), json_value()}]}.
--type json_boolean() :: boolean().
+%%--------------------------------------------------------------------------------
+%% Types
+%%--------------------------------------------------------------------------------
+-type json_value()          :: json_number() | json_string() | json_array() | json_object() | json_boolean() | null.
+-type json_boolean()        :: boolean().
+-type json_number()         :: number().
+-type json_string()         :: binary().
+-type json_array()          :: [json_value()].
+-type json_object()         :: {object, json_object_members()}.
+-type json_object_members() :: [{json_string(), json_value()}].
 
-decode(JsonText) ->
-    decode(JsonText, []).
-
-decode(JsonText, Options) ->
-    jsone_decode:decode(JsonText, Options).
+%%--------------------------------------------------------------------------------
+%% Exported Functions
+%%--------------------------------------------------------------------------------
+%% @doc JSONテキストをデコードする.
+%%
+%% デコードに失敗した場合は`{invalid_json, 失敗位置より後のJSON::binary()}'形式のエラーが送出される.
+-spec decode(binary()) -> {json_value(), RestJson::binary()}.
+decode(Json) ->
+    jsone_decode:decode(Json).

+ 89 - 22
src/jsone_decode.erl

@@ -1,27 +1,78 @@
+%%% @doc JSON decoding module
+%%% @private
+%%% @end
+%%%
+%%% Copyright (c) 2013, 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).
 
--export([
-         decode/1,
-         decode/2
-        ]).
+%%--------------------------------------------------------------------------------
+%% Exported API
+%%--------------------------------------------------------------------------------
+-export([decode/1]).
 
+%%--------------------------------------------------------------------------------
+%% Macros & Types
+%%--------------------------------------------------------------------------------
 -define(ERROR(Json), error({invalid_json, Json})).
 
-decode(<<Bin/binary>>) ->
-    decode(Bin, []).
-
-decode(Bin, _Options) -> % TODO: delete
-    whitespace(Bin, value, []).
-
+-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
+                         | string
+                         | {array_next, [jsone:json_value()]}
+                         | {object_value, jsone:json_string(), jsone:json_object_members()}
+                         | {object_next, jsone:json_string(), jsone:json_value(), jsone:json_object_members()}.
+
+%%--------------------------------------------------------------------------------
+%% Exported Functions
+%%--------------------------------------------------------------------------------
+%% @doc JSONテキストをデコードする.
+%%
+%% デコードに失敗した場合は`{invalid_json, 失敗位置より後のJSON::binary()}'形式のエラーが送出される.
+-spec decode(binary()) -> {jsone:json_value(), RestJson::binary()}.
+decode(<<Json/binary>>) ->
+    whitespace(Json, value, []).
+
+%%--------------------------------------------------------------------------------
+%% Internal Functions
+%%--------------------------------------------------------------------------------
+-spec next(binary(), jsone:json_value(), [next()]) -> {jsone:json_value(), Rest::binary()}.
 next(<<Bin/binary>>, Value, []) ->
     {Value, Bin};
 next(<<Bin/binary>>, Value, [Next | Nexts]) ->
     case Next of
-        {array_next, Values} -> whitespace(Bin, {array_next, [Value | Values]}, Nexts);
-        {object_value, Entries} -> whitespace(Bin, {object_value, Value, Entries}, Nexts);
-        {object_next, Key, Entries} -> whitespace(Bin, {object_next, Key, Value, Entries}, Nexts)
+        {array_next, Values}        -> whitespace(Bin, {array_next, [Value | Values]}, Nexts);
+        {object_value, Members}     -> whitespace(Bin, {object_value, Value, Members}, Nexts);
+        {object_next, Key, Members} -> whitespace(Bin, {object_next, Key, Value, Members}, Nexts)
     end.
 
+-spec whitespace(binary(), whitespace_next(), [next()]) -> {jsone:json_value(), Rest::binary()}.
 whitespace(<<$  , Bin/binary>>, Next, Nexts) -> whitespace(Bin, Next, Nexts);
 whitespace(<<$\t, Bin/binary>>, Next, Nexts) -> whitespace(Bin, Next, Nexts);
 whitespace(<<$\r, Bin/binary>>, Next, Nexts) -> whitespace(Bin, Next, Nexts);
@@ -35,11 +86,12 @@ whitespace(<<Bin/binary>>,      Next, Nexts) ->
                       <<$", Bin2/binary>> -> string(Bin2, [], Nexts);
                       _                   -> ?ERROR(Bin)
                   end;
-        {array_next, Values} -> array_next(Bin, Values, Nexts);
-        {object_value, Key, Entries} -> object_value(Bin, Key, Entries, Nexts);
-        {object_next, Key, Value, Entries} -> object_next(Bin, [{Key, Value} | Entries], Nexts)
+        {array_next, Values}               -> array_next(Bin, Values, Nexts);
+        {object_value, Key, Members}       -> object_value(Bin, Key, Members, Nexts);
+        {object_next, Key, Value, Members} -> object_next(Bin, [{Key, Value} | Members], Nexts)
     end.
- 
+
+-spec value(binary(), [next()]) -> {jsone:json_value(), Rest::binary()}.
 value(<<"false", Bin/binary>>, Nexts) -> next(Bin, false, Nexts);
 value(<<"true", Bin/binary>>, Nexts)  -> next(Bin, true, Nexts);
 value(<<"null", Bin/binary>>, Nexts)  -> next(Bin, null, Nexts);
@@ -48,23 +100,29 @@ value(<<${, Bin/binary>>, Nexts)      -> whitespace(Bin, object, Nexts);
 value(<<$", Bin/binary>>, Nexts)      -> string(Bin, [], Nexts);
 value(<<Bin/binary>>, Nexts)          -> number(Bin, Nexts).
 
+-spec array(binary(), [next()]) -> {jsone:json_value(), Rest::binary()}.
 array(<<$], Bin/binary>>, Nexts) -> next(Bin, [], Nexts);
 array(<<Bin/binary>>, Nexts)     -> whitespace(Bin, value, [{array_next, []} | Nexts]).
 
+-spec array_next(binary(), [jsone:json_value()], [next()]) -> {jsone:json_value(), Rest::binary()}.
 array_next(<<$], Bin/binary>>, Values, Nexts) -> next(Bin, lists:reverse(Values), Nexts);
 array_next(<<$,, Bin/binary>>, Values, Nexts) -> whitespace(Bin, value, [{array_next, Values} | Nexts]);
 array_next(<<Bin/binary>>, _Values, _Nexts)   -> ?ERROR(Bin).
 
+-spec object(binary(), [next()]) -> {jsone:json_value(), Rest::binary()}.
 object(<<$}, Bin/binary>>, Nexts) -> next(Bin, {object, []}, Nexts);
 object(<<Bin/binary>>, Nexts) -> whitespace(Bin, string, [{object_value, []} | Nexts]).
 
-object_value(<<$:, Bin/binary>>, Key, Entries, Nexts) -> whitespace(Bin, value, [{object_next, Key, Entries} | Nexts]);
-object_value(<<Bin/binary>>, _Key, _Entries, _Nexts)  -> ?ERROR(Bin).
+-spec object_value(binary(), jsone:json_string(), jsone:json_object_members(), [next()]) -> {jsone:json_value(), Rest::binary()}.
+object_value(<<$:, Bin/binary>>, Key, Members, Nexts) -> whitespace(Bin, value, [{object_next, Key, Members} | Nexts]);
+object_value(<<Bin/binary>>, _Key, _Members, _Nexts)  -> ?ERROR(Bin).
 
-object_next(<<$}, Bin/binary>>, Entries, Nexts) -> next(Bin, {object, lists:reverse(Entries)}, Nexts);
-object_next(<<$,, Bin/binary>>, Entries, Nexts) -> whitespace(Bin, string, [{object_value, Entries} | Nexts]);
-object_next(<<Bin/binary>>, _Entries, _Nexts)   -> ?ERROR(Bin).
+-spec object_next(binary(), jsone:json_object_members(), [next()]) -> {jsone:json_value(), Rest::binary()}.
+object_next(<<$}, Bin/binary>>, Members, Nexts) -> next(Bin, {object, lists:reverse(Members)}, Nexts);
+object_next(<<$,, Bin/binary>>, Members, Nexts) -> whitespace(Bin, string, [{object_value, Members} | Nexts]);
+object_next(<<Bin/binary>>, _Members, _Nexts)   -> ?ERROR(Bin).
 
+-spec string(binary(), iolist(), [next()]) -> {jsone:json_value(), Rest::binary()}.
 string(<<$", Bin/binary>>, Acc, Nexts) -> next(Bin, list_to_binary(lists:reverse(Acc)), Nexts);
 string(<<$\\, B/binary>>,  Acc, Nexts) ->
     case B of
@@ -82,6 +140,7 @@ string(<<$\\, B/binary>>,  Acc, Nexts) ->
 string(<<C, Bin/binary>>, Acc, Nexts) when 16#20 =< C ->
     string(Bin, [C | Acc], Nexts).
 
+-spec unicode_string(binary(), iolist(), [next()]) -> {jsone:json_value(), Rest::binary()}.
 unicode_string(<<N:4/binary, Bin/binary>>, Acc, Nexts) ->
     case binary_to_integer(N, 16) of
         High when 16#D800 =< High, High =< 16#DBFF ->
@@ -104,6 +163,7 @@ unicode_string(<<N:4/binary, Bin/binary>>, Acc, Nexts) ->
 unicode_string(<<Bin/binary>>, _Acc, _Nexts) ->
     ?ERROR(Bin).
 
+-spec unicode_to_utf8(0..1114111, iolist()) -> iolist().
 unicode_to_utf8(Code, Acc) when Code < 16#80 ->
     [Code | Acc];
 unicode_to_utf8(Code, Acc) when Code < 16#800 ->
@@ -122,9 +182,11 @@ unicode_to_utf8(Code, Acc) -> % NOTE: サロゲートペアの仕組み上、コ
     D = 2#10000000 bor (Code band 2#111111),
     [D, C, B, A | Acc].
 
+-spec number(binary(), [next()]) -> {jsone:json_value(), Rest::binary()}.
 number(<<$-, Bin/binary>>, Nexts) -> number_integer_part(Bin, -1, Nexts);
 number(<<Bin/binary>>,     Nexts) -> number_integer_part(Bin,  1, Nexts).
 
+-spec number_integer_part(binary(), 1|-1, [next()]) -> {jsone:json_value(), Rest::binary()}.
 number_integer_part(<<$0, Bin/binary>>, Sign, Nexts) ->
     number_fraction_part(Bin, Sign, 0, Nexts);
 number_integer_part(<<C, Bin/binary>>, Sign, Nexts) when $1 =< C, C =< $9 ->
@@ -132,16 +194,19 @@ number_integer_part(<<C, Bin/binary>>, Sign, Nexts) when $1 =< C, C =< $9 ->
 number_integer_part(<<Bin/binary>>, _Sign, _Nexts) ->
     ?ERROR(Bin).
 
+-spec number_integer_part_rest(binary(), non_neg_integer(), 1|-1, [next()]) -> {jsone:json_value(), Rest::binary()}.
 number_integer_part_rest(<<C, Bin/binary>>, N, Sign, Nexts) when $0 =< C, C =< $9 ->
     number_integer_part_rest(Bin, N * 10 + C - $0, Sign, Nexts);
 number_integer_part_rest(<<Bin/binary>>, N, Sign, Nexts) ->
     number_fraction_part(Bin, Sign, N, Nexts).
 
+-spec number_fraction_part(binary(), 1|-1, non_neg_integer(), [next()]) -> {jsone:json_value(), Rest::binary()}.
 number_fraction_part(<<$., Bin/binary>>, Sign, Int, Nexts) ->
     number_fraction_part_rest(Bin, Sign, Int, 0, Nexts);
 number_fraction_part(<<Bin/binary>>, Sign, Int, Nexts) ->
     number_exponation_part(Bin, Sign * Int, 0, Nexts).
 
+-spec number_fraction_part_rest(binary(), 1|-1, non_neg_integer(), non_neg_integer(), [next()]) -> {jsone:json_value(), Rest::binary()}.
 number_fraction_part_rest(<<C, Bin/binary>>, Sign, N, DecimalOffset, Nexts) when $0 =< C, C =< $9 ->
     number_fraction_part_rest(Bin, Sign, N * 10 + C - $0, DecimalOffset + 1, Nexts);
 number_fraction_part_rest(<<Bin/binary>>, Sign, N, DecimalOffset, Nexts) when DecimalOffset > 0 ->
@@ -149,6 +214,7 @@ number_fraction_part_rest(<<Bin/binary>>, Sign, N, DecimalOffset, Nexts) when De
 number_fraction_part_rest(<<Bin/binary>>, _Sign, _N, _DecimalOffset, _Nexts) ->
     ?ERROR(Bin).
 
+-spec number_exponation_part(binary(), integer(), non_neg_integer(), [next()]) -> {jsone:json_value(), Rest::binary()}.
 number_exponation_part(<<$e, $+, Bin/binary>>, N, DecimalOffset, Nexts) ->
     number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts);
 number_exponation_part(<<$E, $+, Bin/binary>>, N, DecimalOffset, Nexts) ->
@@ -167,6 +233,7 @@ number_exponation_part(<<Bin/binary>>, N, DecimalOffset, Nexts) ->
         _ -> next(Bin, N / math:pow(10, DecimalOffset), Nexts)
     end.
 
+-spec number_exponation_part(binary(), integer(), non_neg_integer(), 1|-1, non_neg_integer(), boolean(), [next()]) -> {jsone:json_value(), Rest::binary()}.
 number_exponation_part(<<C, Bin/binary>>, N, DecimalOffset, ExpSign, Exp, _, Nexts) when $0 =< C, C =< $9 ->
     number_exponation_part(Bin, N, DecimalOffset, ExpSign, Exp * 10 + C - $0, false, Nexts);
 number_exponation_part(<<Bin/binary>>, N, DecimalOffset, ExpSign, Exp, false, Nexts) ->