Browse Source

first commit

Takeru Ohta 11 years ago
commit
bff1c05ea2
7 changed files with 231 additions and 0 deletions
  1. 11 0
      .gitignore
  2. 44 0
      Makefile
  3. BIN
      rebar
  4. 31 0
      rebar.config
  5. 12 0
      src/jsone.app.src
  6. 11 0
      src/jsone.erl
  7. 122 0
      src/jsone_decode.erl

+ 11 - 0
.gitignore

@@ -0,0 +1,11 @@
+.eunit
+deps
+*.o
+*.beam
+*.plt
+*.dump
+*.app
+*~
+doc/*
+!doc/overview.edoc
+!doc/*.md

+ 44 - 0
Makefile

@@ -0,0 +1,44 @@
+APP=jsone
+NODE=$(APP)@localhost
+
+DIALYZER_OPTS=-Werror_handling -Wrace_conditions -Wunmatched_returns
+
+DEPENDED_APPS=
+
+all: compile xref eunit dialyze
+
+init:
+	@./rebar get-deps compile 
+
+compile:
+	@./rebar compile skip_deps=true
+
+xref:
+	@./rebar xref skip_deps=true
+
+clean:
+	@./rebar clean skip_deps=true
+
+eunit:
+	@./rebar eunit skip_deps=true
+
+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 \
+      -eval 'erlang:display({start_depended_app, [{A, application:start(A)} || A <- [$(DEPENDED_APPS)]]}).' \
+      -eval 'erlang:display({start_app, $(APP), application:start($(APP))}).'
+
+.dialyzer.plt:
+	touch .dialyzer.plt
+	dialyzer --build_plt --plt .dialyzer.plt --apps erts kernel stdlib $(shell echo $(DEPENDED_APPS) | sed -e 's/,/ /g')
+
+dialyze: .dialyzer.plt
+	dialyzer --plt .dialyzer.plt -r ebin $(DIALYZER_OPTS)
+
+create_app:
+	@./rebar create-app appid=$(APP) skip_deps=true

BIN
rebar


+ 31 - 0
rebar.config

@@ -0,0 +1,31 @@
+%% -*- erlang -*-
+{erl_opts, [
+            warnings_as_errors,
+            warn_export_all,
+            warn_untyped_record
+%,native
+%            ,bin_opt_info
+           ]}. 
+
+{xref_checks, [
+               fail_on_warning,
+               undefined_function_calls
+              ]}.
+ 
+{clean_files, [".eunit/*", "ebin/*.beam"]}.
+ 
+{cover_enabled, true}.
+ 
+{edoc_opts, [
+             {dialyzer_specs, all},
+             {report_missing_type, true}, 
+             {report_type_mismatch, true},
+             {pretty_print, erl_pp},
+             {preprocess, true}
+            ]}.
+{validate_app_modules, true}.
+ 
+{deps,
+  [
+%   {edown, ".*", {git, "git://github.com/sile/edown.git", "master"}}
+  ]}.

+ 12 - 0
src/jsone.app.src

@@ -0,0 +1,12 @@
+%% -*- erlang -*-
+{application, jsone,
+ [
+  {description, "Erlang JSON Library"},
+  {vsn, "0.0.1"},
+  {registered, []},
+  {applications, [
+                  kernel,
+                  stdlib
+                 ]},
+  {env, []}
+ ]}.

+ 11 - 0
src/jsone.erl

@@ -0,0 +1,11 @@
+-module(jsone).
+
+-export([
+         decode/1, decode/2
+        ]).
+
+decode(JsonText) ->
+    decode(JsonText, []).
+
+decode(JsonText, Options) ->
+    jsone_decode:decode(JsonText, Options).

+ 122 - 0
src/jsone_decode.erl

@@ -0,0 +1,122 @@
+-module(jsone_decode).
+
+-compile(inline).
+-compile(native).
+
+-export([
+         decode/2
+        ]).
+
+decode(Bin, _Options) ->
+    whitespace(Bin, value, []).
+
+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)
+    end.
+
+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);
+whitespace(<<$\n, Bin/binary>>, Next, Nexts) -> whitespace(Bin, Next, Nexts);
+whitespace(<<Bin/binary>>,      Next, Nexts) ->
+    case Next of
+        value  -> value(Bin, Nexts);
+        array  -> array(Bin, Nexts);
+        object -> object(Bin, Nexts);
+        string -> <<$", Bin2/binary>> = Bin,
+                  string(Bin2, [], Nexts);
+        {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)
+    end.
+ 
+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);
+value(<<$[, Bin/binary>>, Nexts)      -> whitespace(Bin, array, Nexts);
+value(<<${, Bin/binary>>, Nexts)      -> whitespace(Bin, object, Nexts);
+value(<<$", Bin/binary>>, Nexts)      -> string(Bin, [], Nexts);
+value(<<Bin/binary>>, Nexts)          -> number(Bin, Nexts).
+
+array(<<$], Bin/binary>>, Nexts) -> next(Bin, [], Nexts);
+array(<<Bin/binary>>, Nexts)     -> whitespace(Bin, value, [{array_next, []} | Nexts]).
+
+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]).
+
+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_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]).
+
+string(<<$", Bin/binary>>,      Acc, Nexts) -> next(Bin, list_to_binary(lists:reverse(Acc)), Nexts);
+string(<<$\\, $", Bin/binary>>, Acc, Nexts) -> string(Bin, [$" | Acc], Nexts);
+string(<<$\\, $/, Bin/binary>>, Acc, Nexts) -> string(Bin, [$/ | Acc], Nexts);
+string(<<$\\, $\\,Bin/binary>>, Acc, Nexts) -> string(Bin, [$\\| Acc], Nexts);
+string(<<$\\, $b, Bin/binary>>, Acc, Nexts) -> string(Bin, [$\b | Acc], Nexts);
+string(<<$\\, $f, Bin/binary>>, Acc, Nexts) -> string(Bin, [$\f | Acc], Nexts);
+string(<<$\\, $n, Bin/binary>>, Acc, Nexts) -> string(Bin, [$\n | Acc], Nexts);
+string(<<$\\, $r, Bin/binary>>, Acc, Nexts) -> string(Bin, [$\r | Acc], Nexts);
+string(<<$\\, $t, Bin/binary>>, Acc, Nexts) -> string(Bin, [$\t | Acc], Nexts);
+string(<<$\\, $u, N:4/binary, Bin/binary>>, Acc, Nexts) ->
+    case binary_to_integer(N, 16) of
+        High when 16#D800 =< High, High =< 16#DBFF ->
+            <<$\\, $u, N2:4/binary, Bin2/binary>> = Bin,
+            case binary_to_integer(N2, 16) of
+                Low when 16#DC00 =< Low, Low =< 16#DFFF ->
+                    Unicode = 16#10000 + (High - 16#D800) * 16#400 + (Low - 16#DC00),
+                    string(Bin2, [unicode_to_utf8(Unicode) | Acc], Nexts)
+            end;
+        Unicode ->
+            string(Bin, [unicode_to_utf8(Unicode) | Acc], Nexts)
+    end;
+string(<<C, Rest/binary>>, Acc, Nexts) when 16#20 =< C, C =< 16#21;
+                                            16#23 =< C, C =< 16#5B;
+                                            16#5D =< C, C =< 16#FF ->
+    ordinal_string_end(Rest, 0, [C | Acc], Nexts).
+
+%% XXX: name
+ordinal_string_end(<<C, Bin/binary>>, Pos, Acc, Nexts) when 16#20 =< C, C =< 16#21;
+                                                            16#23 =< C, C =< 16#5B;
+                                                            16#5D =< C, C =< 16#FF ->
+    ordinal_string_end(Bin, Pos + 1, [C | Acc], Nexts); %XXX:
+ordinal_string_end(<<Bin/binary>>, _Pos, Acc, Nexts) ->
+%    io:format("! ~p, ~p, ~p, ~p\n", [Bin, Pos, Acc, Nexts]),
+%    <<Bin1:Pos/binary, Bin2/binary>> = Bin,
+%    string(Bin2, [Bin1 | Acc], Nexts).
+    string(Bin, Acc, Nexts).
+
+unicode_to_utf8(Code) when Code < 16#80 ->
+    Code;
+unicode_to_utf8(Code) when Code < 16#800 ->
+    [2#11000000 + (Code bsr 6),
+     2#10000000 + (Code band 2#111111)];
+unicode_to_utf8(Code) when Code < 16#10000 ->
+    %% NOTE: Codeの値が 16#D800 から 16#DFFF の範囲内にないことは、呼び出し元が保証している
+    [2#11100000 + (Code bsr 12),
+     2#10000000 + ((Code bsr 6) band 2#111111),
+     2#10000000 + (Code band 2#111111)];
+unicode_to_utf8(Code) ->
+    %% NOTE: ユニコード範囲内云々
+    [2#1111000 + (Code bsr 18),
+     2#1000000 + ((Code bsr 12) band 2#111111),
+     2#1000000 + ((Code bsr 12) band 2#111111),
+     2#1000000 + (Code band 2#111111)].
+
+number(<<Bin/binary>>, Nexts) ->
+    %% XXX:
+    number(Bin, 0, Nexts).
+
+number(<<C, Bin/binary>>, N, Nexts) when $0 =< C, C =< $9 ->
+    number(Bin, N * 10 + C - $0, Nexts);
+number(<<Bin/binary>>, N, Nexts) -> next(Bin, N, Nexts).
+
+