709 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Elixir
		
	
	
	
	
	
			
		
		
	
	
			709 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Elixir
		
	
	
	
	
	
defmodule Jason.DecodeError do
 | 
						|
  @type t :: %__MODULE__{position: integer, data: String.t}
 | 
						|
 | 
						|
  defexception [:position, :token, :data]
 | 
						|
 | 
						|
  def message(%{position: position, token: token}) when is_binary(token) do
 | 
						|
    "unexpected sequence at position #{position}: #{inspect token}"
 | 
						|
  end
 | 
						|
  def message(%{position: position, data: data}) when position == byte_size(data) do
 | 
						|
    "unexpected end of input at position #{position}"
 | 
						|
  end
 | 
						|
  def message(%{position: position, data: data}) do
 | 
						|
    byte = :binary.at(data, position)
 | 
						|
    str = <<byte>>
 | 
						|
    if String.printable?(str) do
 | 
						|
      "unexpected byte at position #{position}: " <>
 | 
						|
        "#{inspect byte, base: :hex} (#{inspect str})"
 | 
						|
    else
 | 
						|
      "unexpected byte at position #{position}: " <>
 | 
						|
        "#{inspect byte, base: :hex}"
 | 
						|
    end
 | 
						|
  end
 | 
						|
end
 | 
						|
 | 
						|
defmodule Jason.Decoder do
 | 
						|
  @moduledoc false
 | 
						|
 | 
						|
  import Bitwise
 | 
						|
 | 
						|
  alias Jason.{DecodeError, Codegen}
 | 
						|
 | 
						|
  import Codegen, only: [bytecase: 2, bytecase: 3]
 | 
						|
  import Record
 | 
						|
 | 
						|
  @dialyzer :no_improper_lists
 | 
						|
 | 
						|
  # @compile :native
 | 
						|
 | 
						|
  # We use integers instead of atoms to take advantage of the jump table
 | 
						|
  # optimization
 | 
						|
  @terminate 0
 | 
						|
  @array     1
 | 
						|
  @key       2
 | 
						|
  @object    3
 | 
						|
 | 
						|
  defrecordp :decode, [keys: nil, strings: nil, objects: nil, floats: nil]
 | 
						|
 | 
						|
  def parse(data, opts) when is_binary(data) do
 | 
						|
    key_decode = key_decode_function(opts)
 | 
						|
    string_decode = string_decode_function(opts)
 | 
						|
    float_decode = float_decode_function(opts)
 | 
						|
    object_decode = object_decode_function(opts)
 | 
						|
    decode = decode(keys: key_decode, strings: string_decode, objects: object_decode, floats: float_decode)
 | 
						|
    try do
 | 
						|
      value(data, data, 0, [@terminate], decode)
 | 
						|
    catch
 | 
						|
      {:position, position} ->
 | 
						|
        {:error, %DecodeError{position: position, data: data}}
 | 
						|
      {:token, token, position} ->
 | 
						|
        {:error, %DecodeError{token: token, position: position, data: data}}
 | 
						|
    else
 | 
						|
      value ->
 | 
						|
        {:ok, value}
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  defp key_decode_function(%{keys: :atoms}), do: &String.to_atom/1
 | 
						|
  defp key_decode_function(%{keys: :atoms!}), do: &String.to_existing_atom/1
 | 
						|
  defp key_decode_function(%{keys: :strings}), do: &(&1)
 | 
						|
  defp key_decode_function(%{keys: fun}) when is_function(fun, 1), do: fun
 | 
						|
 | 
						|
  defp string_decode_function(%{strings: :copy}), do: &:binary.copy/1
 | 
						|
  defp string_decode_function(%{strings: :reference}), do: &(&1)
 | 
						|
 | 
						|
  defp object_decode_function(%{objects: :maps}), do: &:maps.from_list/1
 | 
						|
  defp object_decode_function(%{objects: :ordered_objects}), do: &Jason.OrderedObject.new(:lists.reverse(&1))
 | 
						|
 | 
						|
  defp float_decode_function(%{floats: :native}) do
 | 
						|
    fn string, token, skip ->
 | 
						|
      try do
 | 
						|
        :erlang.binary_to_float(string)
 | 
						|
      catch
 | 
						|
        :error, :badarg ->
 | 
						|
          token_error(token, skip)
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  if Code.ensure_loaded?(Decimal) do
 | 
						|
    defp float_decode_function(%{floats: :decimals}) do
 | 
						|
      fn string, token, skip ->
 | 
						|
        try do
 | 
						|
          Decimal.new(string)
 | 
						|
        rescue
 | 
						|
          Decimal.Error ->
 | 
						|
            token_error(token, skip)
 | 
						|
        end
 | 
						|
      end
 | 
						|
    end
 | 
						|
  else
 | 
						|
    defp float_decode_function(%{floats: :decimals}) do
 | 
						|
      raise ArgumentError, "decimal library not found, :decimals option not available"
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  defp value(data, original, skip, stack, decode) do
 | 
						|
    bytecase data do
 | 
						|
      _ in ~c'\s\n\t\r', rest ->
 | 
						|
        value(rest, original, skip + 1, stack, decode)
 | 
						|
      _ in ~c'0', rest ->
 | 
						|
        number_zero(rest, original, skip, stack, decode, 1)
 | 
						|
      _ in ~c'123456789', rest ->
 | 
						|
        number(rest, original, skip, stack, decode, 1)
 | 
						|
      _ in ~c'-', rest ->
 | 
						|
        number_minus(rest, original, skip, stack, decode)
 | 
						|
      _ in ~c'"', rest ->
 | 
						|
        string(rest, original, skip + 1, stack, decode, 0)
 | 
						|
      _ in ~c'[', rest ->
 | 
						|
        array(rest, original, skip + 1, stack, decode)
 | 
						|
      _ in ~c'{', rest ->
 | 
						|
        object(rest, original, skip + 1, stack, decode)
 | 
						|
      _ in ~c']', rest ->
 | 
						|
        empty_array(rest, original, skip + 1, stack, decode)
 | 
						|
      _ in ~c't', rest ->
 | 
						|
        case rest do
 | 
						|
          <<"rue", rest::bits>> ->
 | 
						|
            continue(rest, original, skip + 4, stack, decode, true)
 | 
						|
          <<_::bits>> ->
 | 
						|
            error(original, skip)
 | 
						|
        end
 | 
						|
      _ in ~c'f', rest ->
 | 
						|
        case rest do
 | 
						|
          <<"alse", rest::bits>> ->
 | 
						|
            continue(rest, original, skip + 5, stack, decode, false)
 | 
						|
          <<_::bits>> ->
 | 
						|
            error(original, skip)
 | 
						|
        end
 | 
						|
      _ in ~c'n', rest ->
 | 
						|
        case rest do
 | 
						|
          <<"ull", rest::bits>> ->
 | 
						|
            continue(rest, original, skip + 4, stack, decode, nil)
 | 
						|
          <<_::bits>> ->
 | 
						|
            error(original, skip)
 | 
						|
        end
 | 
						|
      _, rest ->
 | 
						|
        error(rest, original, skip + 1, stack, decode)
 | 
						|
      <<_::bits>> ->
 | 
						|
        error(original, skip)
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  defp number_minus(<<?0, rest::bits>>, original, skip, stack, decode) do
 | 
						|
    number_zero(rest, original, skip, stack, decode, 2)
 | 
						|
  end
 | 
						|
  defp number_minus(<<byte, rest::bits>>, original, skip, stack, decode)
 | 
						|
       when byte in ~c'123456789' do
 | 
						|
    number(rest, original, skip, stack, decode, 2)
 | 
						|
  end
 | 
						|
  defp number_minus(<<_rest::bits>>, original, skip, _stack, _decode) do
 | 
						|
    error(original, skip + 1)
 | 
						|
  end
 | 
						|
 | 
						|
  if function_exported?(Application, :compile_env, 3) do
 | 
						|
    @integer_digit_limit Application.compile_env(:jason, :decoding_integer_digit_limit, 1024)
 | 
						|
  else
 | 
						|
    # use apply to avoid warnings in newer Elixir versions
 | 
						|
    @integer_digit_limit apply(Application, :get_env, [:jason, :decoding_integer_digit_limit, 1024])
 | 
						|
  end
 | 
						|
 | 
						|
  defp number(<<byte, rest::bits>>, original, skip, stack, decode, len)
 | 
						|
       when byte in ~c'0123456789' do
 | 
						|
    number(rest, original, skip, stack, decode, len + 1)
 | 
						|
  end
 | 
						|
  defp number(<<?., rest::bits>>, original, skip, stack, decode, len) do
 | 
						|
    number_frac(rest, original, skip, stack, decode, len + 1)
 | 
						|
  end
 | 
						|
  defp number(<<e, rest::bits>>, original, skip, stack, decode, len) when e in ~c'eE' do
 | 
						|
    prefix = binary_part(original, skip, len)
 | 
						|
    number_exp_copy(rest, original, skip + len + 1, stack, decode, prefix)
 | 
						|
  end
 | 
						|
  defp number(<<rest::bits>>, original, skip, stack, decode, len) do
 | 
						|
    token = binary_part(original, skip, len)
 | 
						|
    if byte_size(token) > @integer_digit_limit do
 | 
						|
      token_error(token, skip)
 | 
						|
    end
 | 
						|
    int = String.to_integer(token)
 | 
						|
    continue(rest, original, skip + len, stack, decode, int)
 | 
						|
  end
 | 
						|
 | 
						|
  defp number_frac(<<byte, rest::bits>>, original, skip, stack, decode, len)
 | 
						|
       when byte in ~c'0123456789' do
 | 
						|
    number_frac_cont(rest, original, skip, stack, decode, len + 1)
 | 
						|
  end
 | 
						|
  defp number_frac(<<_rest::bits>>, original, skip, _stack, _decode, len) do
 | 
						|
    error(original, skip + len)
 | 
						|
  end
 | 
						|
 | 
						|
  defp number_frac_cont(<<byte, rest::bits>>, original, skip, stack, decode, len)
 | 
						|
       when byte in ~c'0123456789' do
 | 
						|
    number_frac_cont(rest, original, skip, stack, decode, len + 1)
 | 
						|
  end
 | 
						|
  defp number_frac_cont(<<e, rest::bits>>, original, skip, stack, decode, len)
 | 
						|
       when e in ~c'eE' do
 | 
						|
    number_exp(rest, original, skip, stack, decode, len + 1)
 | 
						|
  end
 | 
						|
  defp number_frac_cont(<<rest::bits>>, original, skip, stack, decode, len) do
 | 
						|
    token = binary_part(original, skip, len)
 | 
						|
    decode(floats: float_decode) = decode
 | 
						|
    float = float_decode.(token, token, skip)
 | 
						|
    continue(rest, original, skip + len, stack, decode, float)
 | 
						|
  end
 | 
						|
 | 
						|
  defp number_exp(<<byte, rest::bits>>, original, skip, stack, decode, len)
 | 
						|
       when byte in ~c'0123456789' do
 | 
						|
    number_exp_cont(rest, original, skip, stack, decode, len + 1)
 | 
						|
  end
 | 
						|
  defp number_exp(<<byte, rest::bits>>, original, skip, stack, decode, len)
 | 
						|
       when byte in ~c'+-' do
 | 
						|
    number_exp_sign(rest, original, skip, stack, decode, len + 1)
 | 
						|
  end
 | 
						|
  defp number_exp(<<_rest::bits>>, original, skip, _stack, _decode, len) do
 | 
						|
    error(original, skip + len)
 | 
						|
  end
 | 
						|
 | 
						|
  defp number_exp_sign(<<byte, rest::bits>>, original, skip, stack, decode, len)
 | 
						|
       when byte in ~c'0123456789' do
 | 
						|
    number_exp_cont(rest, original, skip, stack, decode, len + 1)
 | 
						|
  end
 | 
						|
  defp number_exp_sign(<<_rest::bits>>, original, skip, _stack, _decode, len) do
 | 
						|
    error(original, skip + len)
 | 
						|
  end
 | 
						|
 | 
						|
  defp number_exp_cont(<<byte, rest::bits>>, original, skip, stack, decode, len)
 | 
						|
       when byte in ~c'0123456789' do
 | 
						|
    number_exp_cont(rest, original, skip, stack, decode, len + 1)
 | 
						|
  end
 | 
						|
  defp number_exp_cont(<<rest::bits>>, original, skip, stack, decode, len) do
 | 
						|
    token = binary_part(original, skip, len)
 | 
						|
    decode(floats: float_decode) = decode
 | 
						|
    float = float_decode.(token, token, skip)
 | 
						|
    continue(rest, original, skip + len, stack, decode, float)
 | 
						|
  end
 | 
						|
 | 
						|
  defp number_exp_copy(<<byte, rest::bits>>, original, skip, stack, decode, prefix)
 | 
						|
       when byte in ~c'0123456789' do
 | 
						|
    number_exp_cont(rest, original, skip, stack, decode, prefix, 1)
 | 
						|
  end
 | 
						|
  defp number_exp_copy(<<byte, rest::bits>>, original, skip, stack, decode, prefix)
 | 
						|
       when byte in ~c'+-' do
 | 
						|
    number_exp_sign(rest, original, skip, stack, decode, prefix, 1)
 | 
						|
  end
 | 
						|
  defp number_exp_copy(<<_rest::bits>>, original, skip, _stack, _decode, _prefix) do
 | 
						|
    error(original, skip)
 | 
						|
  end
 | 
						|
 | 
						|
  defp number_exp_sign(<<byte, rest::bits>>, original, skip, stack, decode, prefix, len)
 | 
						|
       when byte in ~c'0123456789' do
 | 
						|
    number_exp_cont(rest, original, skip, stack, decode, prefix, len + 1)
 | 
						|
  end
 | 
						|
  defp number_exp_sign(<<_rest::bits>>, original, skip, _stack, _decode, _prefix, len) do
 | 
						|
    error(original, skip + len)
 | 
						|
  end
 | 
						|
 | 
						|
  defp number_exp_cont(<<byte, rest::bits>>, original, skip, stack, decode, prefix, len)
 | 
						|
       when byte in ~c'0123456789' do
 | 
						|
    number_exp_cont(rest, original, skip, stack, decode, prefix, len + 1)
 | 
						|
  end
 | 
						|
  defp number_exp_cont(<<rest::bits>>, original, skip, stack, decode, prefix, len) do
 | 
						|
    suffix = binary_part(original, skip, len)
 | 
						|
    string = prefix <> ".0e" <> suffix
 | 
						|
    prefix_size = byte_size(prefix)
 | 
						|
    initial_skip = skip - prefix_size - 1
 | 
						|
    final_skip = skip + len
 | 
						|
    token = binary_part(original, initial_skip, prefix_size + len + 1)
 | 
						|
    decode(floats: float_decode) = decode
 | 
						|
    float = float_decode.(string, token, initial_skip)
 | 
						|
    continue(rest, original, final_skip, stack, decode, float)
 | 
						|
  end
 | 
						|
 | 
						|
  defp number_zero(<<?., rest::bits>>, original, skip, stack, decode, len) do
 | 
						|
    number_frac(rest, original, skip, stack, decode, len + 1)
 | 
						|
  end
 | 
						|
  defp number_zero(<<e, rest::bits>>, original, skip, stack, decode, len) when e in ~c'eE' do
 | 
						|
    number_exp_copy(rest, original, skip + len + 1, stack, decode, "0")
 | 
						|
  end
 | 
						|
  defp number_zero(<<rest::bits>>, original, skip, stack, decode, len) do
 | 
						|
    continue(rest, original, skip + len, stack, decode, 0)
 | 
						|
  end
 | 
						|
 | 
						|
  @compile {:inline, array: 5}
 | 
						|
 | 
						|
  defp array(rest, original, skip, stack, decode) do
 | 
						|
    value(rest, original, skip, [@array, [] | stack], decode)
 | 
						|
  end
 | 
						|
 | 
						|
  defp empty_array(<<rest::bits>>, original, skip, stack, decode) do
 | 
						|
    case stack do
 | 
						|
      [@array, [] | stack] ->
 | 
						|
        continue(rest, original, skip, stack, decode, [])
 | 
						|
      _ ->
 | 
						|
        error(original, skip - 1)
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  defp array(data, original, skip, stack, decode, value) do
 | 
						|
    bytecase data do
 | 
						|
      _ in ~c'\s\n\t\r', rest ->
 | 
						|
        array(rest, original, skip + 1, stack, decode, value)
 | 
						|
      _ in ~c']', rest ->
 | 
						|
        [acc | stack] = stack
 | 
						|
        value = :lists.reverse(acc, [value])
 | 
						|
        continue(rest, original, skip + 1, stack, decode, value)
 | 
						|
      _ in ~c',', rest ->
 | 
						|
        [acc | stack] = stack
 | 
						|
        value(rest, original, skip + 1, [@array, [value | acc] | stack], decode)
 | 
						|
      _, _rest ->
 | 
						|
        error(original, skip)
 | 
						|
      <<_::bits>> ->
 | 
						|
        empty_error(original, skip)
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  @compile {:inline, object: 5}
 | 
						|
 | 
						|
  defp object(rest, original, skip, stack, decode) do
 | 
						|
    key(rest, original, skip, [[] | stack], decode)
 | 
						|
  end
 | 
						|
 | 
						|
  defp object(data, original, skip, stack, decode, value) do
 | 
						|
    bytecase data do
 | 
						|
      _ in ~c'\s\n\t\r', rest ->
 | 
						|
        object(rest, original, skip + 1, stack, decode, value)
 | 
						|
      _ in ~c'}', rest ->
 | 
						|
        skip = skip + 1
 | 
						|
        [key, acc | stack] = stack
 | 
						|
        decode(keys: key_decode) = decode
 | 
						|
        final = [{key_decode.(key), value} | acc]
 | 
						|
        decode(objects: object_decode) = decode
 | 
						|
        continue(rest, original, skip, stack, decode, object_decode.(final))
 | 
						|
      _ in ~c',', rest ->
 | 
						|
        skip = skip + 1
 | 
						|
        [key, acc | stack] = stack
 | 
						|
        decode(keys: key_decode) = decode
 | 
						|
        acc = [{key_decode.(key), value} | acc]
 | 
						|
        key(rest, original, skip, [acc | stack], decode)
 | 
						|
      _, _rest ->
 | 
						|
        error(original, skip)
 | 
						|
      <<_::bits>> ->
 | 
						|
        empty_error(original, skip)
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  defp key(data, original, skip, stack, decode) do
 | 
						|
    bytecase data do
 | 
						|
      _ in ~c'\s\n\t\r', rest ->
 | 
						|
        key(rest, original, skip + 1, stack, decode)
 | 
						|
      _ in ~c'}', rest ->
 | 
						|
        case stack do
 | 
						|
          [[] | stack] ->
 | 
						|
            decode(objects: object_decode) = decode
 | 
						|
            continue(rest, original, skip + 1, stack, decode, object_decode.([]))
 | 
						|
          _ ->
 | 
						|
            error(original, skip)
 | 
						|
        end
 | 
						|
      _ in ~c'"', rest ->
 | 
						|
        string(rest, original, skip + 1, [@key | stack], decode, 0)
 | 
						|
      _, _rest ->
 | 
						|
        error(original, skip)
 | 
						|
      <<_::bits>> ->
 | 
						|
        empty_error(original, skip)
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  defp key(data, original, skip, stack, decode, value) do
 | 
						|
    bytecase data do
 | 
						|
      _ in ~c'\s\n\t\r', rest ->
 | 
						|
        key(rest, original, skip + 1, stack, decode, value)
 | 
						|
      _ in ~c':', rest ->
 | 
						|
        value(rest, original, skip + 1, [@object, value | stack], decode)
 | 
						|
      _, _rest ->
 | 
						|
        error(original, skip)
 | 
						|
      <<_::bits>> ->
 | 
						|
        empty_error(original, skip)
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  # TODO: check if this approach would be faster:
 | 
						|
  # https://git.ninenines.eu/cowlib.git/tree/src/cow_ws.erl#n469
 | 
						|
  # http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
 | 
						|
  defp string(data, original, skip, stack, decode, len) do
 | 
						|
    bytecase data, 128 do
 | 
						|
      _ in ~c'"', rest ->
 | 
						|
        decode(strings: string_decode) = decode
 | 
						|
        string = string_decode.(binary_part(original, skip, len))
 | 
						|
        continue(rest, original, skip + len + 1, stack, decode, string)
 | 
						|
      _ in ~c'\\', rest ->
 | 
						|
        part = binary_part(original, skip, len)
 | 
						|
        escape(rest, original, skip + len, stack, decode, part)
 | 
						|
      _ in unquote(0x00..0x1F), _rest ->
 | 
						|
        error(original, skip + len)
 | 
						|
      _, rest ->
 | 
						|
        string(rest, original, skip, stack, decode, len + 1)
 | 
						|
      <<char::utf8, rest::bits>> when char <= 0x7FF ->
 | 
						|
        string(rest, original, skip, stack, decode, len + 2)
 | 
						|
      <<char::utf8, rest::bits>> when char <= 0xFFFF ->
 | 
						|
        string(rest, original, skip, stack, decode, len + 3)
 | 
						|
      <<_char::utf8, rest::bits>> ->
 | 
						|
        string(rest, original, skip, stack, decode, len + 4)
 | 
						|
      <<_::bits>> ->
 | 
						|
        empty_error(original, skip + len)
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  defp string(data, original, skip, stack, decode, acc, len) do
 | 
						|
    bytecase data, 128 do
 | 
						|
      _ in ~c'"', rest ->
 | 
						|
        last = binary_part(original, skip, len)
 | 
						|
        string = IO.iodata_to_binary([acc | last])
 | 
						|
        continue(rest, original, skip + len + 1, stack, decode, string)
 | 
						|
      _ in ~c'\\', rest ->
 | 
						|
        part = binary_part(original, skip, len)
 | 
						|
        escape(rest, original, skip + len, stack, decode, [acc | part])
 | 
						|
      _ in unquote(0x00..0x1F), _rest ->
 | 
						|
        error(original, skip + len)
 | 
						|
      _, rest ->
 | 
						|
        string(rest, original, skip, stack, decode, acc, len + 1)
 | 
						|
      <<char::utf8, rest::bits>> when char <= 0x7FF ->
 | 
						|
        string(rest, original, skip, stack, decode, acc, len + 2)
 | 
						|
      <<char::utf8, rest::bits>> when char <= 0xFFFF ->
 | 
						|
        string(rest, original, skip, stack, decode, acc, len + 3)
 | 
						|
      <<_char::utf8, rest::bits>> ->
 | 
						|
        string(rest, original, skip, stack, decode, acc, len + 4)
 | 
						|
      <<_::bits>> ->
 | 
						|
        empty_error(original, skip + len)
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  defp escape(data, original, skip, stack, decode, acc) do
 | 
						|
    bytecase data do
 | 
						|
      _ in ~c'b', rest ->
 | 
						|
        string(rest, original, skip + 2, stack, decode, [acc | ~c'\b'], 0)
 | 
						|
      _ in ~c't', rest ->
 | 
						|
        string(rest, original, skip + 2, stack, decode, [acc | ~c'\t'], 0)
 | 
						|
      _ in ~c'n', rest ->
 | 
						|
        string(rest, original, skip + 2, stack, decode, [acc | ~c'\n'], 0)
 | 
						|
      _ in ~c'f', rest ->
 | 
						|
        string(rest, original, skip + 2, stack, decode, [acc | ~c'\f'], 0)
 | 
						|
      _ in ~c'r', rest ->
 | 
						|
        string(rest, original, skip + 2, stack, decode, [acc | ~c'\r'], 0)
 | 
						|
      _ in ~c'"', rest ->
 | 
						|
        string(rest, original, skip + 2, stack, decode, [acc | ~c'\"'], 0)
 | 
						|
      _ in ~c'/', rest ->
 | 
						|
        string(rest, original, skip + 2, stack, decode, [acc | ~c'/'], 0)
 | 
						|
      _ in ~c'\\', rest ->
 | 
						|
        string(rest, original, skip + 2, stack, decode, [acc | ~c'\\'], 0)
 | 
						|
      _ in ~c'u', rest ->
 | 
						|
        escapeu(rest, original, skip, stack, decode, acc)
 | 
						|
      _, _rest ->
 | 
						|
        error(original, skip + 1)
 | 
						|
      <<_::bits>> ->
 | 
						|
        empty_error(original, skip)
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  defmodule Unescape do
 | 
						|
    @moduledoc false
 | 
						|
 | 
						|
    import Bitwise
 | 
						|
 | 
						|
    @digits Enum.concat([?0..?9, ?A..?F, ?a..?f])
 | 
						|
 | 
						|
    def unicode_escapes(chars1 \\ @digits, chars2 \\ @digits) do
 | 
						|
      for char1 <- chars1, char2 <- chars2 do
 | 
						|
        {(char1 <<< 8) + char2, integer8(char1, char2)}
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    defp integer8(char1, char2) do
 | 
						|
      (integer4(char1) <<< 4) + integer4(char2)
 | 
						|
    end
 | 
						|
 | 
						|
    defp integer4(char) when char in ?0..?9, do: char - ?0
 | 
						|
    defp integer4(char) when char in ?A..?F, do: char - ?A + 10
 | 
						|
    defp integer4(char) when char in ?a..?f, do: char - ?a + 10
 | 
						|
 | 
						|
    defp token_error_clause(original, skip, len) do
 | 
						|
      quote do
 | 
						|
        _ ->
 | 
						|
          token_error(unquote_splicing([original, skip, len]))
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    defmacro escapeu_first(int, last, rest, original, skip, stack, decode, acc) do
 | 
						|
      clauses = escapeu_first_clauses(last, rest, original, skip, stack, decode, acc)
 | 
						|
      quote location: :keep do
 | 
						|
        case unquote(int) do
 | 
						|
          unquote(clauses ++ token_error_clause(original, skip, 6))
 | 
						|
        end
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    defp escapeu_first_clauses(last, rest, original, skip, stack, decode, acc) do
 | 
						|
      for {int, first} <- unicode_escapes(),
 | 
						|
          not (first in 0xDC..0xDF) do
 | 
						|
        escapeu_first_clause(int, first, last, rest, original, skip, stack, decode, acc)
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    defp escapeu_first_clause(int, first, last, rest, original, skip, stack, decode, acc)
 | 
						|
         when first in 0xD8..0xDB do
 | 
						|
      hi =
 | 
						|
        quote bind_quoted: [first: first, last: last] do
 | 
						|
          0x10000 + ((((first &&& 0x03) <<< 8) + last) <<< 10)
 | 
						|
        end
 | 
						|
      args = [rest, original, skip, stack, decode, acc, hi]
 | 
						|
      [clause] =
 | 
						|
        quote location: :keep do
 | 
						|
          unquote(int) -> escape_surrogate(unquote_splicing(args))
 | 
						|
        end
 | 
						|
      clause
 | 
						|
    end
 | 
						|
 | 
						|
    defp escapeu_first_clause(int, first, last, rest, original, skip, stack, decode, acc)
 | 
						|
         when first <= 0x00 do
 | 
						|
      skip = quote do: (unquote(skip) + 6)
 | 
						|
      acc =
 | 
						|
        quote bind_quoted: [acc: acc, first: first, last: last] do
 | 
						|
          if last <= 0x7F do
 | 
						|
            # 0?????
 | 
						|
            [acc, last]
 | 
						|
          else
 | 
						|
            # 110xxxx??  10?????
 | 
						|
            byte1 = ((0b110 <<< 5) + (first <<< 2)) + (last >>> 6)
 | 
						|
            byte2 = (0b10 <<< 6) + (last &&& 0b111111)
 | 
						|
            [acc, byte1, byte2]
 | 
						|
          end
 | 
						|
        end
 | 
						|
      args = [rest, original, skip, stack, decode, acc, 0]
 | 
						|
      [clause] =
 | 
						|
        quote location: :keep do
 | 
						|
          unquote(int) -> string(unquote_splicing(args))
 | 
						|
        end
 | 
						|
      clause
 | 
						|
    end
 | 
						|
 | 
						|
    defp escapeu_first_clause(int, first, last, rest, original, skip, stack, decode, acc)
 | 
						|
         when first <= 0x07 do
 | 
						|
      skip = quote do: (unquote(skip) + 6)
 | 
						|
      acc =
 | 
						|
        quote bind_quoted: [acc: acc, first: first, last: last] do
 | 
						|
          # 110xxx??  10??????
 | 
						|
          byte1 = ((0b110 <<< 5) + (first <<< 2)) + (last >>> 6)
 | 
						|
          byte2 = (0b10 <<< 6) + (last &&& 0b111111)
 | 
						|
          [acc, byte1, byte2]
 | 
						|
        end
 | 
						|
      args = [rest, original, skip, stack, decode, acc, 0]
 | 
						|
      [clause] =
 | 
						|
        quote location: :keep do
 | 
						|
          unquote(int) -> string(unquote_splicing(args))
 | 
						|
        end
 | 
						|
      clause
 | 
						|
    end
 | 
						|
 | 
						|
    defp escapeu_first_clause(int, first, last, rest, original, skip, stack, decode, acc)
 | 
						|
         when first <= 0xFF do
 | 
						|
      skip = quote do: (unquote(skip) + 6)
 | 
						|
      acc =
 | 
						|
        quote bind_quoted: [acc: acc, first: first, last: last] do
 | 
						|
          # 1110xxxx  10xxxx??  10??????
 | 
						|
          byte1 = (0b1110 <<< 4) + (first >>> 4)
 | 
						|
          byte2 = ((0b10 <<< 6) + ((first &&& 0b1111) <<< 2)) + (last >>> 6)
 | 
						|
          byte3 = (0b10 <<< 6) + (last &&& 0b111111)
 | 
						|
          [acc, byte1, byte2, byte3]
 | 
						|
        end
 | 
						|
      args = [rest, original, skip, stack, decode, acc, 0]
 | 
						|
      [clause] =
 | 
						|
        quote location: :keep do
 | 
						|
          unquote(int) -> string(unquote_splicing(args))
 | 
						|
        end
 | 
						|
      clause
 | 
						|
    end
 | 
						|
 | 
						|
    defmacro escapeu_last(int, original, skip) do
 | 
						|
      clauses = escapeu_last_clauses()
 | 
						|
      quote location: :keep do
 | 
						|
        case unquote(int) do
 | 
						|
          unquote(clauses ++ token_error_clause(original, skip, 6))
 | 
						|
        end
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    defp escapeu_last_clauses() do
 | 
						|
      for {int, last} <- unicode_escapes() do
 | 
						|
        [clause] =
 | 
						|
          quote do
 | 
						|
            unquote(int) -> unquote(last)
 | 
						|
          end
 | 
						|
        clause
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    defmacro escapeu_surrogate(int, last, rest, original, skip, stack, decode, acc,
 | 
						|
             hi) do
 | 
						|
      clauses = escapeu_surrogate_clauses(last, rest, original, skip, stack, decode, acc, hi)
 | 
						|
      quote location: :keep do
 | 
						|
        case unquote(int) do
 | 
						|
          unquote(clauses ++ token_error_clause(original, skip, 12))
 | 
						|
        end
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    defp escapeu_surrogate_clauses(last, rest, original, skip, stack, decode, acc, hi) do
 | 
						|
      digits1 = ~c'Dd'
 | 
						|
      digits2 = Stream.concat([?C..?F, ?c..?f])
 | 
						|
      for {int, first} <- unicode_escapes(digits1, digits2) do
 | 
						|
        escapeu_surrogate_clause(int, first, last, rest, original, skip, stack, decode, acc, hi)
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    defp escapeu_surrogate_clause(int, first, last, rest, original, skip, stack, decode, acc, hi) do
 | 
						|
      skip = quote do: unquote(skip) + 12
 | 
						|
      acc =
 | 
						|
        quote bind_quoted: [acc: acc, first: first, last: last, hi: hi] do
 | 
						|
          lo = ((first &&& 0x03) <<< 8) + last
 | 
						|
          [acc | <<(hi + lo)::utf8>>]
 | 
						|
        end
 | 
						|
      args = [rest, original, skip, stack, decode, acc, 0]
 | 
						|
      [clause] =
 | 
						|
        quote do
 | 
						|
          unquote(int) ->
 | 
						|
            string(unquote_splicing(args))
 | 
						|
        end
 | 
						|
      clause
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  defp escapeu(<<int1::16, int2::16, rest::bits>>, original, skip, stack, decode, acc) do
 | 
						|
    require Unescape
 | 
						|
    last = escapeu_last(int2, original, skip)
 | 
						|
    Unescape.escapeu_first(int1, last, rest, original, skip, stack, decode, acc)
 | 
						|
  end
 | 
						|
  defp escapeu(<<_rest::bits>>, original, skip, _stack, _decode, _acc) do
 | 
						|
    empty_error(original, skip)
 | 
						|
  end
 | 
						|
 | 
						|
  # @compile {:inline, escapeu_last: 3}
 | 
						|
 | 
						|
  defp escapeu_last(int, original, skip) do
 | 
						|
    require Unescape
 | 
						|
    Unescape.escapeu_last(int, original, skip)
 | 
						|
  end
 | 
						|
 | 
						|
  defp escape_surrogate(<<?\\, ?u, int1::16, int2::16, rest::bits>>, original,
 | 
						|
       skip, stack, decode, acc, hi) do
 | 
						|
    require Unescape
 | 
						|
    last = escapeu_last(int2, original, skip + 6)
 | 
						|
    Unescape.escapeu_surrogate(int1, last, rest, original, skip, stack, decode, acc, hi)
 | 
						|
  end
 | 
						|
  defp escape_surrogate(<<_rest::bits>>, original, skip, _stack, _decode, _acc, _hi) do
 | 
						|
    error(original, skip + 6)
 | 
						|
  end
 | 
						|
 | 
						|
  defp error(<<_rest::bits>>, _original, skip, _stack, _decode) do
 | 
						|
    throw {:position, skip - 1}
 | 
						|
  end
 | 
						|
 | 
						|
  defp empty_error(_original, skip) do
 | 
						|
    throw {:position, skip}
 | 
						|
  end
 | 
						|
 | 
						|
  @compile {:inline, error: 2, token_error: 2, token_error: 3}
 | 
						|
  defp error(_original, skip) do
 | 
						|
    throw {:position, skip}
 | 
						|
  end
 | 
						|
 | 
						|
  defp token_error(token, position) do
 | 
						|
    throw {:token, token, position}
 | 
						|
  end
 | 
						|
 | 
						|
  defp token_error(token, position, len) do
 | 
						|
    throw {:token, binary_part(token, position, len), position}
 | 
						|
  end
 | 
						|
 | 
						|
  @compile {:inline, continue: 6}
 | 
						|
  defp continue(rest, original, skip, stack, decode, value) do
 | 
						|
    case stack do
 | 
						|
      [@terminate | stack] ->
 | 
						|
        terminate(rest, original, skip, stack, decode, value)
 | 
						|
      [@array | stack] ->
 | 
						|
        array(rest, original, skip, stack, decode, value)
 | 
						|
      [@key | stack] ->
 | 
						|
        key(rest, original, skip, stack, decode, value)
 | 
						|
      [@object | stack] ->
 | 
						|
        object(rest, original, skip, stack, decode, value)
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  defp terminate(<<byte, rest::bits>>, original, skip, stack, decode, value)
 | 
						|
       when byte in ~c'\s\n\r\t' do
 | 
						|
    terminate(rest, original, skip + 1, stack, decode, value)
 | 
						|
  end
 | 
						|
  defp terminate(<<>>, _original, _skip, _stack, _decode, value) do
 | 
						|
    value
 | 
						|
  end
 | 
						|
  defp terminate(<<_rest::bits>>, original, skip, _stack, _decode, _value) do
 | 
						|
    error(original, skip)
 | 
						|
  end
 | 
						|
end
 |