internal override SourceLocation GetLocation(int position)
    {
        if (position < 0 || position > _document.Length)
        {
            throw new IndexOutOfRangeException(nameof(position));
        }

        var index = Array.BinarySearch <int>(_lineStarts, position);

        if (index >= 0)
        {
            // We have an exact match for the start of a line.
            Debug.Assert(_lineStarts[index] == position);

            return(new SourceLocation(_document.GetFilePathForDisplay(), position, index, characterIndex: 0));
        }


        // Index is the complement of the line *after* the one we want, because BinarySearch tells
        // us where we'd put position *if* it were the start of a line.
        index = (~index) - 1;
        if (index == -1)
        {
            // There's no preceding line, so it's based on the start of the string
            return(new SourceLocation(_document.GetFilePathForDisplay(), position, 0, position));
        }
        else
        {
            var characterIndex = position - _lineStarts[index];
            return(new SourceLocation(_document.GetFilePathForDisplay(), position, index, characterIndex));
        }
    }