/// Parses a JSON encoded object
/// @param {String} $source - JSON complete source
/// @param {Number} $pointer - current pointer
/// @throw Unexpected comma in object literal.
/// @throw Unexpected token $token in object literal.
/// @throw Missing comma in object literal.
/// @throw Unterminated object literal.
/// @throw Consuming token `:` failed.
/// @return {List} (new pointer, map)
/// @require {function} _throw
/// @require {function} _consume
/// @require {function} _json-decode--value
/// @require {function} _json-decode--string
@function _json-decode--map($source, $pointer) {
  $length: str-length($source);
  $map: ();
  $needs-comma: false;

  // Deal with empty map
  @if $pointer <= $length and str-slice($source, $pointer, $pointer) == "}" {
    @return ($pointer + 1, $map);
  }

  @while $pointer <= $length {
    $token: str-slice($source, $pointer, $pointer);
    $pointer: $pointer + 1;

    @if $token == "}" {
      @if not $needs-comma and length($map) != 0 {
        @return _throw("Unexpected comma in object literal.", $pointer);
      }
      @return ($pointer, $map);
    } @else if $token == " " or $token == "	" {
      // @continue;
    } @else if $token == "," {
      @if not $needs-comma {
        @return _throw("Unexpected comma in object literal.", $pointer);
      }
      $needs-comma: false;
    } @else if $token == '"' {
      @if $needs-comma {
        @return _throw("Missing comma in object literal.", $pointer);
      }

      // Read key
      $read-key:  _json-decode--string($source, $pointer);
      $pointer: nth($read-key, 1);
      $key:     nth($read-key, 2);

      // Remove colon
      $pointer: _consume($source, $pointer, ":");
      @if length($pointer) > 1 { // If consume has failed
        @return _throw("Consuming token `:` failed.", 0);
      }

      // Read value
      $read-value: _json-decode--value($source, $pointer);
      $pointer: nth($read-value, 1);
      $value:    nth($read-value, 2);

      // Add pair to map
      $map: map-merge($map, ($key: $value));
      $needs-comma: true;
    } @else {
      @return _throw("Unexpected token `" + $token + "` in object literal.", $pointer);
    }
  }

  @return _throw("Unterminated object literal.", $pointer);
}
