Browse Source

少数のデコードに対応

Takeru Ohta 11 years ago
parent
commit
d52e882bb0
1 changed files with 55 additions and 56 deletions
  1. 55 56
      src/jsone_decode.erl

+ 55 - 56
src/jsone_decode.erl

@@ -1,7 +1,7 @@
 -module(jsone_decode).
 
 -compile(native).
--compile(bin_opt_info).
+%-compile(bin_opt_info).
 
 -export([
          decode/2
@@ -106,58 +106,57 @@ unicode_to_utf8(Code, Acc) ->
     D = 2#10000000 bor (Code band 2#111111),
     [D, C, B, A | Acc].
 
-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).
-
-
-%% decode_number(<<$-, Bin/binary>>) -> {Num, Bin2} = decode_number_impl(Bin),
-%%                                      {-Num, Bin2};
-%% decode_number(<<$ , Bin/binary>>) -> decode_number(Bin);
-%% decode_number(<<$\t,Bin/binary>>) -> decode_number(Bin);
-%% decode_number(<<$\r,Bin/binary>>) -> decode_number(Bin);
-%% decode_number(<<$\n,Bin/binary>>) -> decode_number(Bin);
-%% decode_number(<<Bin/binary>>)     -> decode_number_impl(Bin).
-
-%% decode_number_impl(<<$0, Bin/binary>>) -> decode_fraction(Bin, 0);
-%% decode_number_impl(<<C, Bin/binary>>) when $1 =< C, C =< $9 -> decode_int(Bin, C - $0).
-
-%% decode_int(<<C, Bin/binary>>, Acc) when $0 =< C, C =< $9 ->
-%%     decode_int(Bin, (Acc*10) + (C-$0));
-%% decode_int(<<Bin/binary>>, Acc) ->
-%%     decode_fraction(Bin, Acc).
-
-%% decode_fraction(<<$., Bin/binary>>, Acc) ->
-%%     {Digit, Bin2} = decode_digit(Bin),
-%%     Frac  = Digit / (math:pow(10, byte_size(Bin) - byte_size(Bin2))),
-%%     decode_exponation(Bin2, Acc + Frac);
-%% decode_fraction(<<Bin/binary>>, Acc) ->
-%%     {Acc, Bin}.
-
-%% decode_exponation(<<$e, $+, Bin/binary>>, Acc) -> decode_exponation(Bin, Acc, plus);
-%% decode_exponation(<<$E, $+, Bin/binary>>, Acc) -> decode_exponation(Bin, Acc, plus);
-%% decode_exponation(<<$e, $-, Bin/binary>>, Acc) -> decode_exponation(Bin, Acc, minus);
-%% decode_exponation(<<$E, $-, Bin/binary>>, Acc) -> decode_exponation(Bin, Acc, minus);
-%% decode_exponation(<<$e,     Bin/binary>>, Acc) -> decode_exponation(Bin, Acc, plus);
-%% decode_exponation(<<$E,     Bin/binary>>, Acc) -> decode_exponation(Bin, Acc, plus);
-%% decode_exponation(<<Bin/binary>>, Acc)         -> {Acc, Bin}.
-
-%% decode_exponation(<<Bin/binary>>, Acc, Sign) ->
-%%     {Digit, Bin2} = decode_digit(Bin),
-%%     Num = case Sign of
-%%               plus  -> Acc * math:pow(10, Digit);
-%%               minus -> Acc / math:pow(10, Digit)
-%%           end,
-%%     {Num, Bin2}.
-
-%% decode_digit(<<C, Bin/binary>>) when $0 =< C, C =< $9 -> 
-%%     decode_digit(Bin, C - $0).
-
-%% decode_digit(<<C, Bin/binary>>, Acc) when $0 =< C, C =< $9 ->
-%%     decode_digit(Bin, (Acc*10) - (C-$0));
-%% decode_digit(<<Bin/binary>>, Acc) ->
-%%     {Acc, Bin}.
+%% 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).
+
+number(<<$-, Bin/binary>>, Nexts) -> number_integer_part(Bin, -1, Nexts);
+number(<<Bin/binary>>,     Nexts) -> number_integer_part(Bin,  1, Nexts).
+
+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 ->
+    number_integer_part_rest(Bin, C - $0, Sign, Nexts).
+
+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).
+
+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).
+
+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 ->
+    number_exponation_part(Bin, Sign * N, DecimalOffset, Nexts).
+
+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) ->
+    number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts);
+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) ->
+    number_exponation_part(Bin, N, DecimalOffset, -1, 0, true, Nexts);
+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) ->
+    number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts);
+number_exponation_part(<<Bin/binary>>, N, DecimalOffset, Nexts) ->
+    case DecimalOffset of
+        0 -> next(Bin, N, Nexts);
+        _ -> next(Bin, N / math:pow(10, DecimalOffset), Nexts)
+    end.
+
+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) ->
+    Pos = ExpSign * Exp - DecimalOffset,
+    next(Bin, N * math:pow(10, Pos), Nexts).