@function __range($start, $end: null, $step: null) {
  @if ($step and $step != 0 and __is-iteratee-call($start, $end, $step)) {
    $end: null;
    $step: null;
  }

  $start: if(__is-integer($start), $start, if(__is-truthy($start), 1, 0));
  $step: if($step == null, 1, if(__is-integer($step), $step, if($step, 1, 0)));

  @if ($end == null) {
    $end: $start;
    $start: 0;
  } @else {
    $end: if(__is-integer($end), $end, if($end, 1, 0));
  }

  $index: 1;
  $length: max(ceil(($end - $start) / (if($step == 0, 1, $step))), 0);
  $result: ();

  @while ($index <= $length) {
    $result: append($result, $start);
    $start: $start + $step;
    $index: $index + 1;
  }

  @return $result;
}

/// Creates a list of numbers (positive and/or negative) progressing from
/// `$start` up to, but not including, `$end`. If `$end` is not specified it
/// defaults to `$start` with `$start` becoming `0`. If `$start` is less than
/// `$end` a zero-length range is created unless a negative `$step` is specified.
///
///
/// @access public
/// @group Utility
/// @param {number} $start [0] - The start of the range.
/// @param {number} $end - The end of the range.
/// @param {number} $step [1] - The value to increment or decrement by.
/// @returns {List} Returns the new list of numbers.
/// @example scss
/// $foo: _range(4);
/// // => (0, 1, 2, 3)
/// $foo: _range(1, 5);
/// // => (1, 2, 3, 4)
/// $foo: _range(0, 20, 5);
/// // => (0, 5, 10, 15)
/// $foo: _range(0, -4, -1);
/// // => (0, -1, -2, -3)
/// $foo: _range(1, 4, 0);
/// // => (1, 1, 1)
/// $foo: _range(0);
/// // => ()

@function _range($args...) {
  @return call(get-function("__range"), $args...);
}
