/// Bitwise helper function
/// @param {List} $args - list of parameters
/// @return {Number | false}
/// @require {function} bw-and
/// @require {function} bw-not
/// @require {function} bw-or
/// @require {function} bw-xor
/// @require {function} bw-shift-left
/// @require {function} bw-shift-right
/// @example scss AND
/// $value: bitwise(42 '&' 48);
/// // -> 32
/// @example scss OR
/// $value: bitwise(42 '|' 48);
/// // -> 58
/// @example scss XOR
/// $value: bitwise(42 '^' 48);
/// // -> 26
/// @example scss NOT
/// $value: bitwise('~' 42);
/// // -> -43
/// @example scss SHIFTLEFT
/// $value: bitwise(42 '<<' 48);
/// // -> 168
/// @example scss SHIFTRIGHT
/// $value: bitwise(42 '>>' 48);
/// // -> 10
@function bitwise($args) {
  @if not arguments-validator($args) {
    @return false;
  }

  $result: null;
  $operator: null;
  $not-operator: false;
  $operators: (
    "&"  : "and",
    "|"  : "or",
    "^"  : "xor",
    "<<" : "shift-left",
    ">>" : "shift-right"
  );

  // Loop through all arguments
  @each $current in $args {

    // If current argument is an operator
    // Store it while waiting for next value
    @if map-has-key($operators, $current) {
      $operator: $current;
    }

    // If current argument is `not` bitwise operator
    // Pass $not boolean to true
    @else if $current == "~" {
      $not-operator: true;
    }

    // If current argument is not an operator
    @else {
      // If $not is true
      // Compute not first
      @if $not-operator {
        $current: bw-not($current);
        $not-operator: false;
      }

      // Then the operation
      @if $operator {
        $result: call("bw-" + map-get($operators, $operator), $result, $current);
        $operator: null;
      }

      @else {
        $result: $current;
      }
    }
  }

  @return $result;
}


/// Alias for `bitwise`
/// @alias bitwise
@function bw($args) {
  @return bitwise($args);
}
