"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});

exports.default = function (realm, obj) {
  // ECMA262 22.1.3.31
  obj.defineNativeProperty(realm.intrinsics.SymbolIterator, realm.intrinsics.ArrayProto_values);

  // ECMA262 22.1.3
  obj.defineNativeProperty("length", realm.intrinsics.zero);

  // ECMA262 22.1.3.1
  obj.defineNativeMethod("concat", 1, (context, args, argCount) => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let A be ? ArraySpeciesCreate(O, 0).
    let A = _singletons.Create.ArraySpeciesCreate(realm, O, 0);

    // 3. Let n be 0.
    let n = 0;

    // 4. Let items be a List whose first element is O and whose subsequent elements are, in left to right
    //    order, the arguments that were passed to this function invocation.
    let items = argCount === 0 ? [O] : [O, ...args];

    // 5. Repeat, while items is not empty
    while (items.length) {
      // a. Remove the first element from items and let E be the value of the element.
      let E = items.shift();

      // b. Let spreadable be ? IsConcatSpreadable(E).
      let spreadable = (0, _index2.IsConcatSpreadable)(realm, E);

      // c. If spreadable is true, then
      if (spreadable) {
        E = E.throwIfNotConcreteObject();

        // i. Let k be 0.
        let k = 0;

        // ii. Let len be ? ToLength(? Get(E, "length")).
        let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, E, "length"));

        // ii. If n + len > 2^53-1, throw a TypeError exception.
        if (n + len > Math.pow(2, 53) - 1) {
          throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "too damn high");
        }

        // iv. Repeat, while k < len
        while (k < len) {
          // 1. Let P be ! ToString(k).
          let P = new _index.StringValue(realm, k + "");

          // 2. Let exists be ? HasProperty(E, P).
          let exists = (0, _index2.HasProperty)(realm, E, P);

          // 3. If exists is true, then
          if (exists) {
            // a. Let subElement be ? Get(E, P).
            let subElement = (0, _index2.Get)(realm, E, P);

            // b. Perform ? CreateDataPropertyOrThrow(A, ! ToString(n), subElement).
            _singletons.Create.CreateDataPropertyOrThrow(realm, A, new _index.StringValue(realm, n + ""), subElement);
          }

          // 4. Increase n by 1.
          n++;

          // 5. Increase k by 1.
          k++;
        }
      } else {
        // d. Else E is added as a single item rather than spread,
        // i. If n≥2^53-1, throw a TypeError exception.
        if (n > Math.pow(2, 53) - 1) {
          throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "too damn high");
        }

        // ii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(n), E).
        _singletons.Create.CreateDataPropertyOrThrow(realm, A, new _index.StringValue(realm, n + ""), E);

        // iii. Increase n by 1.
        n++;
      }
    }

    // 6. Perform ? Set(A, "length", n, true).
    _singletons.Properties.Set(realm, A, "length", new _index.NumberValue(realm, n), true);

    // 7. Return A.
    return A;
  });

  // ECMA262 22.1.3.3
  if (!realm.isCompatibleWith(realm.MOBILE_JSC_VERSION) && !realm.isCompatibleWith("mobile")) obj.defineNativeMethod("copyWithin", 2, (context, [target, start, end]) => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // 3. Let relativeTarget be ? ToInteger(target).
    let relativeTarget = _singletons.To.ToInteger(realm, target);

    // 4. If relativeTarget < 0, let to be max((len + relativeTarget), 0); else let to be min(relativeTarget, len).
    let to = relativeTarget < 0 ? Math.max(len + relativeTarget, 0) : Math.min(relativeTarget, len);

    // 5. Let relativeStart be ? ToInteger(start).
    let relativeStart = _singletons.To.ToInteger(realm, start);

    // 6. If relativeStart < 0, let from be max((len + relativeStart), 0); else let from be min(relativeStart, len).
    let from = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len);

    // 7. If end is undefined, let relativeEnd be len; else let relativeEnd be ? ToInteger(end).
    let relativeEnd = !end || end instanceof _index.UndefinedValue ? len : _singletons.To.ToInteger(realm, end.throwIfNotConcrete());

    // 8. If relativeEnd < 0, let final be max((len + relativeEnd), 0); else let final be min(relativeEnd, len).
    let final = relativeEnd < 0 ? Math.max(len + relativeEnd, 0) : Math.min(relativeEnd, len);

    // 9. Let count be min(final-from, len-to).
    let count = Math.min(final - from, len - to);

    let direction;
    // 10. If from<to and to<from+count, then
    if (from < to && to < from + count) {
      // a. Let direction be -1.
      direction = -1;

      // b. Let from be from + count - 1.
      from = from + count - 1;

      // c. Let to be to + count - 1.
      to = to + count - 1;
    } else {
      // 11. Else,
      // a. Let direction be 1.
      direction = 1;
    }

    // 12. Repeat, while count > 0
    while (count > 0) {
      // a. Let fromKey be ! ToString(from).
      let fromKey = _singletons.To.ToString(realm, new _index.NumberValue(realm, from));

      // b. Let toKey be ! ToString(to).
      let toKey = _singletons.To.ToString(realm, new _index.NumberValue(realm, to));

      // c. Let fromPresent be ? HasProperty(O, fromKey).
      let fromPresent = (0, _index2.HasProperty)(realm, O, fromKey);

      // d. If fromPresent is true, then
      if (fromPresent === true) {
        // i. Let fromVal be ? Get(O, fromKey).
        let fromVal = (0, _index2.Get)(realm, O, fromKey);
        // ii. Perform ? Set(O, toKey, fromVal, true).
        _singletons.Properties.Set(realm, O, toKey, fromVal, true);
      } else {
        // e. Else fromPresent is false,
        // i. Perform ? DeletePropertyOrThrow(O, toKey).
        _singletons.Properties.DeletePropertyOrThrow(realm, O, toKey);
      }

      // f. Let from be from + direction.
      from = from + direction;

      // g. Let to be to + direction.
      to = to + direction;

      // h. Let count be count - 1.
      count = count - 1;
    }

    // 13. Return O.
    return O;
  });

  // ECMA262 22.1.3.4
  obj.defineNativeMethod("entries", 0, context => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Return CreateArrayIterator(O, "key+value").
    return _singletons.Create.CreateArrayIterator(realm, O, "key+value");
  });

  // ECMA262 22.1.3.5
  obj.defineNativeMethod("every", 1, (context, [callbackfn, thisArg]) => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
    if (!(0, _index2.IsCallable)(realm, callbackfn)) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "not a function");
    }

    // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
    let T = thisArg || realm.intrinsics.undefined;

    // 5. Let k be 0.
    let k = 0;

    // 6. Repeat, while k < len
    while (k < len) {
      // a. Let Pk be ! ToString(k).
      let Pk = new _index.StringValue(realm, k + "");

      // b. Let kPresent be ? HasProperty(O, Pk).
      let kPresent = (0, _index2.HasProperty)(realm, O, Pk);

      // c. If kPresent is true, then
      if (kPresent) {
        // i. Let kValue be ? Get(O, Pk).
        let kValue = (0, _index2.Get)(realm, O, Pk);

        // ii. Let testResult be ToBoolean(? Call(callbackfn, T, « kValue, k, O »)).
        let testResult = _singletons.To.ToBooleanPartial(realm, (0, _index2.Call)(realm, callbackfn, T, [kValue, new _index.NumberValue(realm, k), O]));

        // iii. If testResult is false, return false.
        if (!testResult) return realm.intrinsics.false;
      }

      // d. Increase k by 1.
      k++;
    }

    // 7. Return true.
    return realm.intrinsics.true;
  });

  // ECMA262 22.1.3.6
  obj.defineNativeMethod("fill", 1, (context, [value, start, end]) => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // 3. Let relativeStart be ? ToInteger(start).
    let relativeStart = _singletons.To.ToInteger(realm, start || realm.intrinsics.undefined);

    // 4. If relativeStart < 0, let k be max((len + relativeStart), 0); else let k be min(relativeStart, len).
    let k = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len);

    // 5. If end is undefined, let relativeEnd be len; else let relativeEnd be ? ToInteger(end).
    let relativeEnd = !end || end instanceof _index.UndefinedValue ? len : _singletons.To.ToInteger(realm, end.throwIfNotConcrete());

    // 6. If relativeEnd < 0, let final be max((len + relativeEnd), 0); else let final be min(relativeEnd, len).
    let final = relativeEnd < 0 ? Math.max(len + relativeEnd, 0) : Math.min(relativeEnd, len);

    // 7. Repeat, while k < final
    while (k < final) {
      // a. Let Pk be ! ToString(k).
      let Pk = new _index.StringValue(realm, k + "");

      // b. Perform ? Set(O, Pk, value, true).
      _singletons.Properties.Set(realm, O, Pk, value, true);

      // c. Increase k by 1.
      k++;
    }

    // 8. Return O.
    return O;
  });

  // ECMA262 22.1.3.7
  obj.defineNativeMethod("filter", 1, (context, [callbackfn, thisArg]) => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
    if (!(0, _index2.IsCallable)(realm, callbackfn)) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "not a function");
    }

    // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
    let T = thisArg || realm.intrinsics.undefined;

    // 5. Let A be ? ArraySpeciesCreate(O, 0).
    let A = _singletons.Create.ArraySpeciesCreate(realm, O, 0);

    // 6. Let k be 0.
    let k = 0;

    // 7. Let to be 0.
    let to = 0;

    // 8. Repeat, while k < len
    while (k < len) {
      // a. Let Pk be ! ToString(k).
      let Pk = new _index.StringValue(realm, k + "");

      // b. Let kPresent be ? HasProperty(O, Pk).
      let kPresent = (0, _index2.HasProperty)(realm, O, Pk);

      // c. If kPresent is true, then
      if (kPresent) {
        // i. Let kValue be ? Get(O, Pk).
        let kValue = (0, _index2.Get)(realm, O, Pk);

        // ii. Let selected be ToBoolean(? Call(callbackfn, T, « kValue, k, O »)).
        let selected = _singletons.To.ToBooleanPartial(realm, (0, _index2.Call)(realm, callbackfn, T, [kValue, new _index.NumberValue(realm, k), O]));

        // iii. If selected is true, then
        if (selected) {
          // 1. Perform ? CreateDataPropertyOrThrow(A, ! ToString(to), kValue).
          _singletons.Create.CreateDataPropertyOrThrow(realm, A, _singletons.To.ToString(realm, new _index.NumberValue(realm, to)), kValue);

          // 2. Increase to by 1.
          to++;
        }
      }

      // d. Increase k by 1.
      k++;
    }

    // 9. Return A.
    return A;
  });

  // ECMA262 22.1.3.8
  obj.defineNativeMethod("find", 1, (context, [predicate, thisArg]) => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // 3. If IsCallable(predicate) is false, throw a TypeError exception.
    if (!(0, _index2.IsCallable)(realm, predicate)) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "not a function");
    }

    // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
    let T = thisArg || realm.intrinsics.undefined;

    // 5. Let k be 0.
    let k = 0;

    // 6. Repeat, while k < len
    while (k < len) {
      // a. Let Pk be ! ToString(k).
      let Pk = new _index.StringValue(realm, k + "");

      // b. Let kValue be ? Get(O, Pk).
      let kValue = (0, _index2.Get)(realm, O, Pk);

      // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
      let testResult = _singletons.To.ToBooleanPartial(realm, (0, _index2.Call)(realm, predicate, T, [kValue, new _index.NumberValue(realm, k), O]));

      // d. If testResult is true, return kValue.
      if (testResult) return kValue;

      // e. Increase k by 1.
      k++;
    }

    // 7. Return undefined.
    return realm.intrinsics.undefined;
  });

  // ECMA262 22.1.3.9
  obj.defineNativeMethod("findIndex", 1, (context, [predicate, thisArg]) => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // 3. If IsCallable(predicate) is false, throw a TypeError exception.
    if ((0, _index2.IsCallable)(realm, predicate) === false) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "not a function");
    }

    // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
    let T = thisArg ? thisArg : realm.intrinsics.undefined;

    // 5. Let k be 0.
    let k = 0;

    // 6. Repeat, while k < len
    while (k < len) {
      // a. Let Pk be ! ToString(k).
      let Pk = _singletons.To.ToString(realm, new _index.NumberValue(realm, k));

      // b. Let kValue be ? Get(O, Pk).
      let kValue = (0, _index2.Get)(realm, O, new _index.StringValue(realm, Pk));

      // c. Let testResult be ToBoolean(? Call(predicate, T, « kValue, k, O »)).
      let testResult = _singletons.To.ToBooleanPartial(realm, (0, _index2.Call)(realm, predicate, T, [kValue, new _index.NumberValue(realm, k), O]));

      // d. If testResult is true, return k.
      if (testResult === true) return new _index.NumberValue(realm, k);

      // e. Increase k by 1.
      k = k + 1;
    }

    // 7. Return -1.
    return new _index.NumberValue(realm, -1);
  });

  // ECMA262 22.1.3.10
  obj.defineNativeMethod("forEach", 1, (context, [callbackfn, thisArg]) => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
    if (!(0, _index2.IsCallable)(realm, callbackfn)) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "not a function");
    }

    // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
    let T = thisArg || realm.intrinsics.undefined;

    // 5. Let k be 0.
    let k = 0;

    // 6. Repeat, while k < len
    while (k < len) {
      // a. Let Pk be ! To.ToString(k).
      let Pk = new _index.StringValue(realm, k + "");

      // b. Let kPresent be ? HasProperty(O, Pk).
      let kPresent = (0, _index2.HasProperty)(realm, O, Pk);

      // c. If kPresent is true, then
      if (kPresent) {
        // i. Let kValue be ? Get(O, Pk).
        let kValue = (0, _index2.Get)(realm, O, Pk);

        // ii. Perform ? Call(callbackfn, T, « kValue, k, O »).
        (0, _index2.Call)(realm, callbackfn, T, [kValue, new _index.NumberValue(realm, k), O]);
      }

      // d. Increase k by 1.
      k++;
    }

    // 7. Return undefined.
    return realm.intrinsics.undefined;
  });

  // ECMA262 22.1.3.11
  if (!realm.isCompatibleWith(realm.MOBILE_JSC_VERSION) && !realm.isCompatibleWith("mobile")) obj.defineNativeMethod("includes", 1, (context, [searchElement, fromIndex]) => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // 3. If len is 0, return false.
    if (len === 0) return realm.intrinsics.false;

    // 4. Let n be ? ToInteger(fromIndex). (If fromIndex is undefined, this step produces the value 0.)
    let n = _singletons.To.ToInteger(realm, fromIndex || realm.intrinsics.undefined);

    let k;
    // 5. If n ≥ 0, then
    if (n >= 0) {
      // a. Let k be n.
      k = n;
    } else {
      // 6. Else n < 0,
      // a. Let k be len + n.
      k = len + n;
      // b. If k < 0, let k be 0.
      if (k < 0) k = 0;
    }

    // 7. Repeat, while k < len
    while (k < len) {
      // a. Let elementK be the result of ? Get(O, ! ToString(k)).
      let elementK = (0, _index2.Get)(realm, O, _singletons.To.ToString(realm, new _index.NumberValue(realm, k)));

      // b. If SameValueZero(searchElement, elementK) is true, return true.
      if ((0, _abstract.SameValueZeroPartial)(realm, searchElement, elementK) === true) return realm.intrinsics.true;

      // c. Increase k by 1.
      k = k + 1;
    }

    // 8. Return false.
    return realm.intrinsics.false;
  });

  // ECMA262 22.1.3.12
  obj.defineNativeMethod("indexOf", 1, (context, [searchElement, fromIndex]) => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // 3. If len is 0, return -1.
    if (len === 0) return new _index.NumberValue(realm, -1);

    // 4. Let n be ? ToInteger(fromIndex). (If fromIndex is undefined, this step produces the value 0.)
    let n = fromIndex ? _singletons.To.ToInteger(realm, fromIndex) : 0;

    // 5. If n ≥ len, return -1.
    if (n >= len) return new _index.NumberValue(realm, -1);

    // 6. If n ≥ 0, then
    let k;
    if (n >= 0) {
      // a. If n is -0, let k be +0; else let k be n.
      k = Object.is(n, -0) ? +0 : n;
    } else {
      // 7. Else n < 0,
      // a. Let k be len + n.
      k = len + n;

      // b. If k < 0, let k be 0.
      if (k < 0) k = 0;
    }

    // 8. Repeat, while k < len
    while (k < len) {
      // a. Let kPresent be ? HasProperty(O, ! ToString(k)).
      let kPresent = (0, _index2.HasProperty)(realm, O, k + "");

      // b. If kPresent is true, then
      if (kPresent === true) {
        // i. Let elementK be ? Get(O, ! ToString(k)).
        let elementK = (0, _index2.Get)(realm, O, k + "");

        // ii. Let same be the result of performing Strict Equality Comparison searchElement === elementK.
        let same = (0, _index2.StrictEqualityComparisonPartial)(realm, searchElement, elementK);

        // iii. If same is true, return k.
        if (same) return new _index.NumberValue(realm, k);
      }

      // c. Increase k by 1.
      k++;
    }

    // 9. Return -1.
    return new _index.NumberValue(realm, -1);
  });

  // ECMA262 22.1.3.13
  obj.defineNativeMethod("join", 1, (context, [separator]) => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // 3. If separator is undefined, let separator be the single-element String ",".
    if (!separator || separator instanceof _index.UndefinedValue) separator = new _index.StringValue(realm, ",");

    // 4. Let sep be ? ToString(separator).
    let sep = _singletons.To.ToStringPartial(realm, separator);

    // 5. If len is zero, return the empty String.
    if (len === 0) return realm.intrinsics.emptyString;

    // 6. Let element0 be Get(O, "0").
    let element0 = (0, _index2.Get)(realm, O, "0");

    // 7. If element0 is undefined or null, let R be the empty String; otherwise, let R be ? ToString(element0).
    let R;
    if ((0, _index2.HasSomeCompatibleType)(element0, _index.UndefinedValue, _index.NullValue)) {
      R = "";
    } else {
      R = _singletons.To.ToStringPartial(realm, element0);
    }

    // 8. Let k be 1.
    let k = 1;

    // 9. Repeat, while k < len
    while (k < len) {
      // a. Let S be the String value produced by concatenating R and sep.
      let S = R + sep;

      // b. Let element be ? Get(O, ! To.ToString(k)).
      let element = (0, _index2.Get)(realm, O, new _index.StringValue(realm, k + ""));

      // c. If element is undefined or null, let next be the empty String; otherwise, let next be ? ToString(element).
      let next;
      if ((0, _index2.HasSomeCompatibleType)(element, _index.UndefinedValue, _index.NullValue)) {
        next = "";
      } else {
        next = _singletons.To.ToStringPartial(realm, element);
      }

      // d. Let R be a String value produced by concatenating S and next.
      R = S + next;

      // e. Increase k by 1.
      k++;
    }

    // 10. Return R.
    return new _index.StringValue(realm, R + "");
  });

  // ECMA262 22.1.3.14
  obj.defineNativeMethod("keys", 0, context => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Return CreateArrayIterator(O, "key").
    return _singletons.Create.CreateArrayIterator(realm, O, "key");
  });

  // ECMA262 22.1.3.15
  obj.defineNativeMethod("lastIndexOf", 1, (context, [searchElement, fromIndex]) => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // 3. If len is 0, return -1.
    if (len === 0) return new _index.NumberValue(realm, -1);

    // 4. If argument fromIndex was passed, let n be ? ToInteger(fromIndex); else let n be len-1.
    let n = fromIndex ? _singletons.To.ToInteger(realm, fromIndex) : len - 1;

    // 5. If n ≥ 0, then
    let k;
    if (n >= 0) {
      // a. If n is -0, let k be +0; else let k be min(n, len - 1).
      k = Object.is(n, -0) ? +0 : Math.min(n, len - 1);
    } else {
      // 6. Else n < 0,
      // a. Let k be len + n.
      k = len + n;
    }

    // 7. Repeat, while k ≥ 0
    while (k >= 0) {
      // a. Let kPresent be ? HasProperty(O, ! ToString(k)).
      let kPresent = (0, _index2.HasProperty)(realm, O, new _index.StringValue(realm, k + ""));

      // b. If kPresent is true, then
      if (kPresent) {
        // i. Let elementK be ? Get(O, ! ToString(k)).
        let elementK = (0, _index2.Get)(realm, O, new _index.StringValue(realm, k + ""));

        // ii. Let same be the result of performing Strict Equality Comparison searchElement === elementK.
        let same = (0, _index2.StrictEqualityComparisonPartial)(realm, searchElement, elementK);

        // iii. If same is true, return k.
        if (same) return new _index.NumberValue(realm, k);
      }

      // c. Decrease k by 1.
      k--;
    }

    // 8. Return -1.
    return new _index.NumberValue(realm, -1);
  });

  // ECMA262 22.1.3.16
  obj.defineNativeMethod("map", 1, (context, [callbackfn, thisArg]) => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
    if (!(0, _index2.IsCallable)(realm, callbackfn)) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "not a function");
    }

    // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
    let T = thisArg || realm.intrinsics.undefined;

    // 5. Let A be ? ArraySpeciesCreate(O, len).
    let A = _singletons.Create.ArraySpeciesCreate(realm, O, len);

    // 6. Let k be 0.
    let k = 0;

    // 7. Repeat, while k < len
    while (k < len) {
      // a. Let Pk be ! To.ToString(k).
      let Pk = new _index.StringValue(realm, k + "");

      // b. Let kPresent be ? HasProperty(O, Pk).
      let kPresent = (0, _index2.HasProperty)(realm, O, Pk);

      // c. If kPresent is true, then
      if (kPresent) {
        // i. Let kValue be ? Get(O, Pk).
        let kValue = (0, _index2.Get)(realm, O, Pk);

        // ii. Let mappedValue be ? Call(callbackfn, T, « kValue, k, O »).
        let mappedValue = (0, _index2.Call)(realm, callbackfn, T, [kValue, new _index.NumberValue(realm, k), O]);

        // iii. Perform ? CreateDataPropertyOrThrow(A, Pk, mappedValue).
        _singletons.Create.CreateDataPropertyOrThrow(realm, A, Pk, mappedValue);
      }

      // d. Increase k by 1.
      k++;
    }

    // 8. Return A.
    return A;
  });

  // ECMA262 22.1.3.17
  obj.defineNativeMethod("pop", 0, context => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // 3. If len is zero, then
    if (len === 0) {
      // a. Perform ? Set(O, "length", 0, true).
      _singletons.Properties.Set(realm, O, "length", realm.intrinsics.zero, true);

      // b. Return undefined.
      return realm.intrinsics.undefined;
    } else {
      // 4. Else len > 0,
      // a. Let newLen be len-1.
      let newLen = len - 1;

      // b. Let indx be ! ToString(newLen).
      let indx = new _index.StringValue(realm, newLen + "");

      // c. Let element be ? Get(O, indx).
      let element = (0, _index2.Get)(realm, O, indx);

      // d. Perform ? DeletePropertyOrThrow(O, indx).
      _singletons.Properties.DeletePropertyOrThrow(realm, O, indx);

      // e. Perform ? Set(O, "length", newLen, true).
      _singletons.Properties.Set(realm, O, "length", new _index.NumberValue(realm, newLen), true);

      // f. Return element.
      return element;
    }
  });

  // ECMA262 22.1.3.18
  obj.defineNativeMethod("push", 1, (context, args, argCount) => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, new _index.StringValue(realm, "length")));

    // 3. Let items be a List whose elements are, in left to right order, the arguments that were passed to realm function invocation.
    let items = argCount > 0 ? args : [];

    // 4. Let argCount be the number of elements in items.
    argCount;

    // 5. If len + argCount > 2^53-1, throw a TypeError exception.
    if (len + argCount > Math.pow(2, 53) - 1) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "Array.prototype");
    }

    // 6. Repeat, while items is not empty
    while (items.length) {
      // a. Remove the first element from items and let E be the value of the element.
      let E = items.shift();

      // b. Perform ? Set(O, ! ToString(len), E, true).
      _singletons.Properties.Set(realm, O, new _index.StringValue(realm, len + ""), E, true);

      // c. Let len be len+1.
      len++;
    }

    // 7. Perform ? Set(O, "length", len, true).
    _singletons.Properties.Set(realm, O, new _index.StringValue(realm, "length"), new _index.NumberValue(realm, len), true);

    // 8. Return len.
    return new _index.NumberValue(realm, len);
  });

  // ECMA262 22.1.3.19
  obj.defineNativeMethod("reduce", 1, (context, [callbackfn, initialValue]) => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
    if (!(0, _index2.IsCallable)(realm, callbackfn)) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "not a function");
    }

    // 4. If len is 0 and initialValue is not present, throw a TypeError exception.
    if (len === 0 && !initialValue) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "Array.prototype");
    }

    // 5. Let k be 0.
    let k = 0;

    // 6. If initialValue is present, then
    let accumulator;
    if (initialValue) {
      // a. Set accumulator to initialValue.
      accumulator = initialValue;
    } else {
      // 7. Else initialValue is not present,
      // a. Let kPresent be false.
      let kPresent = false;

      // b. Repeat, while kPresent is false and k < len
      while (kPresent === false && k < len) {
        // i. Let Pk be ! ToString(k).
        let Pk = new _index.StringValue(realm, k + "");

        // ii. Let kPresent be ? HasProperty(O, Pk).
        kPresent = (0, _index2.HasProperty)(realm, O, Pk);

        // iv. If kPresent is true, then
        if (kPresent) {
          // 1. Let accumulator be ? Get(O, Pk).
          accumulator = (0, _index2.Get)(realm, O, Pk);
        }

        // v. Increase k by 1.
        k++;
      }

      // c. If kPresent is false, throw a TypeError exception.
      if (!kPresent) {
        throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "kPresent is false");
      }

      (0, _invariant2.default)(accumulator);
    }

    // 8. Repeat, while k < len
    while (k < len) {
      // a. Let Pk be ! ToString(k).
      let Pk = new _index.StringValue(realm, k + "");

      // b. Let kPresent be ? HasProperty(O, Pk).
      let kPresent = (0, _index2.HasProperty)(realm, O, Pk);

      // c. If kPresent is true, then
      if (kPresent) {
        // i. Let kValue be ? Get(O, Pk).
        let kValue = (0, _index2.Get)(realm, O, Pk);

        // ii. Let accumulator be ? Call(callbackfn, undefined, « accumulator, kValue, k, O »).
        accumulator = (0, _index2.Call)(realm, callbackfn, realm.intrinsics.undefined, [accumulator, kValue, new _index.NumberValue(realm, k), O]);
      }

      // d. Increase k by 1.
      k++;
    }

    // 9. Return accumulator.
    return accumulator;
  });

  // ECMA262 22.1.3.20
  obj.defineNativeMethod("reduceRight", 1, (context, [callbackfn, initialValue]) => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
    if (!(0, _index2.IsCallable)(realm, callbackfn)) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "not a function");
    }

    // 4. If len is 0 and initialValue is not present, throw a TypeError exception.
    if (len === 0 && !initialValue) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "Array.prototype");
    }

    // 5. Let k be len-1.
    let k = len - 1;

    // 6. If initialValue is present, then
    let accumulator;
    if (initialValue) {
      // 1. Set accumulator to initialValue.
      accumulator = initialValue;
    } else {
      // 7. Else initialValue is not present,
      // a. Let kPresent be false.
      let kPresent = false;

      // b. Repeat, while kPresent is false and k ≥ 0
      while (!kPresent && k >= 0) {
        // i. Let Pk be ! ToString(k).
        let Pk = new _index.StringValue(realm, k + "");

        // ii. Let kPresent be ? HasProperty(O, Pk).
        kPresent = (0, _index2.HasProperty)(realm, O, Pk);

        // iii. If kPresent is true, then
        if (kPresent) {
          // 1. Let accumulator be ? Get(O, Pk).
          accumulator = (0, _index2.Get)(realm, O, Pk);
        }

        // iv. Decrease k by 1.
        k--;
      }

      // c. If kPresent is false, throw a TypeError exception.
      if (!kPresent || !accumulator) {
        throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "Array.prototype");
      }
    }

    // 8. Repeat, while k ≥ 0
    while (k >= 0) {
      // a. Let Pk be ! ToString(k).
      let Pk = new _index.StringValue(realm, k + "");

      // b. Let kPresent be ? HasProperty(O, Pk).
      let kPresent = (0, _index2.HasProperty)(realm, O, Pk);

      // c. If kPresent is true, then
      if (kPresent) {
        // i. Let kValue be ? Get(O, Pk).
        let kValue = (0, _index2.Get)(realm, O, Pk);

        // ii. Let accumulator be ? Call(callbackfn, undefined, « accumulator, kValue, k, O »).
        accumulator = (0, _index2.Call)(realm, callbackfn, realm.intrinsics.undefined, [accumulator, kValue, new _index.NumberValue(realm, k), O]);
      }

      // d. Decrease k by 1.
      k--;
    }

    // 9. Return accumulator.
    return accumulator;
  });

  // ECMA262 22.1.3.21
  obj.defineNativeMethod("reverse", 0, context => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // 3. Let middle be floor(len/2).
    let middle = Math.floor(len / 2);

    // 4. Let lower be 0.
    let lower = 0;

    // 5. Repeat, while lower ≠ middle
    while (lower !== middle) {
      // a. Let upper be len - lower - 1.
      let upper = len - lower - 1;

      // b. Let upperP be ! ToString(upper).
      let upperP = new _index.StringValue(realm, upper + "");

      // c. Let lowerP be ! ToString(lower).
      let lowerP = new _index.StringValue(realm, lower + "");

      // d. Let lowerExists be ? HasProperty(O, lowerP).
      let lowerExists = (0, _index2.HasProperty)(realm, O, lowerP);

      // e. If lowerExists is true, then
      let lowerValue;
      if (lowerExists) {
        // i. Let lowerValue be ? Get(O, lowerP).
        lowerValue = (0, _index2.Get)(realm, O, lowerP);
      }

      // f. Let upperExists be ? HasProperty(O, upperP).
      let upperExists = (0, _index2.HasProperty)(realm, O, upperP);

      // g. If upperExists is true, then
      let upperValue;
      if (upperExists) {
        // i. Let upperValue be ? Get(O, upperP).
        upperValue = (0, _index2.Get)(realm, O, upperP);
      }

      // h. If lowerExists is true and upperExists is true, then
      if (lowerExists && upperExists) {
        (0, _invariant2.default)(lowerValue, "expected lower value to exist");
        (0, _invariant2.default)(upperValue, "expected upper value to exist");

        // i. Perform ? Set(O, lowerP, upperValue, true).
        _singletons.Properties.Set(realm, O, lowerP, upperValue, true);

        // ii. Perform ? Set(O, upperP, lowerValue, true).
        _singletons.Properties.Set(realm, O, upperP, lowerValue, true);
      } else if (!lowerExists && upperExists) {
        // i. Else if lowerExists is false and upperExists is true, then
        (0, _invariant2.default)(upperValue, "expected upper value to exist");

        // i. Perform ? Set(O, lowerP, upperValue, true).
        _singletons.Properties.Set(realm, O, lowerP, upperValue, true);

        // ii. Perform ? DeletePropertyOrThrow(O, upperP).
        _singletons.Properties.DeletePropertyOrThrow(realm, O, upperP);
      } else if (lowerExists && !upperExists) {
        // j. Else if lowerExists is true and upperExists is false, then
        (0, _invariant2.default)(lowerValue, "expected lower value to exist");

        // i. Perform ? DeletePropertyOrThrow(O, lowerP).
        _singletons.Properties.DeletePropertyOrThrow(realm, O, lowerP);

        // ii. Perform ? Set(O, upperP, lowerValue, true).
        _singletons.Properties.Set(realm, O, upperP, lowerValue, true);
      } else {}
      // k. Else both lowerExists and upperExists are false,
      // i. No action is required.


      // l. Increase lower by 1.
      lower++;
    }

    // 6. Return O.
    return O;
  });

  // ECMA262 22.1.3.22
  obj.defineNativeMethod("shift", 0, context => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // 3. If len is zero, then
    if (len === 0) {
      // a. Perform ? Set(O, "length", 0, true).
      _singletons.Properties.Set(realm, O, "length", realm.intrinsics.zero, true);

      // b. Return undefined.
      return realm.intrinsics.undefined;
    }

    // 4. Let first be ? Get(O, "0").
    let first = (0, _index2.Get)(realm, O, "0");

    // 5. Let k be 1.
    let k = 0;

    // 6. Repeat, while k < len
    while (k < len) {
      // a. Let from be ! ToString(k).
      let frm = new _index.StringValue(realm, k + "");

      // b. Let to be ! ToString(k-1).
      let to = new _index.StringValue(realm, k - 1 + "");

      // c. Let fromPresent be ? HasProperty(O, from).
      let fromPresent = (0, _index2.HasProperty)(realm, O, frm);

      // d. If fromPresent is true, then
      if (fromPresent) {
        // i. Let fromVal be ? Get(O, from).
        let fromVal = (0, _index2.Get)(realm, O, frm);

        // ii. Perform ? Set(O, to, fromVal, true).
        _singletons.Properties.Set(realm, O, to, fromVal, true);
      } else {
        // d. Else fromPresent is false,
        // i. Perform ? DeletePropertyOrThrow(O, to).
        _singletons.Properties.DeletePropertyOrThrow(realm, O, to);
      }

      // e. Increase k by 1.
      k++;
    }

    // 7. Perform ? DeletePropertyOrThrow(O, ! ToString(len-1)).
    _singletons.Properties.DeletePropertyOrThrow(realm, O, new _index.StringValue(realm, len - 1 + ""));

    // 8. Perform ? Set(O, "length", len-1, true).
    _singletons.Properties.Set(realm, O, "length", new _index.NumberValue(realm, len - 1), true);

    // 9. Return first.
    return first;
  });

  // ECMA262 22.1.3.23
  obj.defineNativeMethod("slice", 2, (context, [start, end]) => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // 3. Let relativeStart be ? ToInteger(start).
    let relativeStart = _singletons.To.ToInteger(realm, start);

    // 4. If relativeStart < 0, let k be max((len + relativeStart), 0); else let k be min(relativeStart, len).
    let k = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len);

    // 5. If end is undefined, let relativeEnd be len; else let relativeEnd be ? ToInteger(end).
    let relativeEnd = !end || end instanceof _index.UndefinedValue ? len : _singletons.To.ToInteger(realm, end.throwIfNotConcrete());

    // 6. If relativeEnd < 0, let final be max((len + relativeEnd), 0); else let final be min(relativeEnd, len).
    let final = relativeEnd < 0 ? Math.max(len + relativeEnd, 0) : Math.min(relativeEnd, len);

    // 7. Let count be max(final - k, 0).
    let count = Math.max(final - k, 0);

    // 8. Let A be ? ArraySpeciesCreate(O, count).
    let A = _singletons.Create.ArraySpeciesCreate(realm, O, count);

    // 9. Let n be 0.
    let n = 0;

    // 10. Repeat, while k < final
    while (k < final) {
      // a. Let Pk be ! ToString(k).
      let Pk = new _index.StringValue(realm, k + "");

      // b. Let kPresent be ? HasProperty(O, Pk).
      let kPresent = (0, _index2.HasProperty)(realm, O, Pk);

      // c. If kPresent is true, then
      if (kPresent) {
        // i. Let kValue be ? Get(O, Pk).
        let kValue = (0, _index2.Get)(realm, O, Pk);

        // ii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(n), kValue).
        _singletons.Create.CreateDataPropertyOrThrow(realm, A, new _index.StringValue(realm, n + ""), kValue);
      }

      // d. Increase k by 1.
      k++;

      // e. Increase n by 1.
      n++;
    }

    // 11. Perform ? Set(A, "length", n, true).
    _singletons.Properties.Set(realm, A, "length", new _index.NumberValue(realm, n), true);

    // 12. Return A.
    return A;
  });

  // ECMA262 22.1.3.24
  obj.defineNativeMethod("some", 1, (context, [callbackfn, thisArg]) => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // 3. If IsCallable(callbackfn) is false, throw a TypeError exception.
    if (!(0, _index2.IsCallable)(realm, callbackfn)) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "callback passed to Array.prototype.some isn't callable");
    }

    // 4. If thisArg was supplied, let T be thisArg; else let T be undefined.
    let T = thisArg || realm.intrinsics.undefined;

    // 5. Let k be 0.
    let k = 0;

    // 6. Repeat, while k < len
    while (k < len) {
      // a. Let Pk be ! ToString(k).
      let Pk = new _index.StringValue(realm, k + "");

      // b. Let kPresent be ? HasProperty(O, Pk).
      let kPresent = (0, _index2.HasProperty)(realm, O, Pk);

      // c. If kPresent is true, then
      if (kPresent) {
        // i. Let kValue be ? Get(O, Pk).
        let kValue = (0, _index2.Get)(realm, O, Pk);

        // ii. Let testResult be ToBoolean(? Call(callbackfn, T, « kValue, k, O »)).
        let testResult = _singletons.To.ToBooleanPartial(realm, (0, _index2.Call)(realm, callbackfn, T, [kValue, new _index.NumberValue(realm, k), O]));

        // iii. If testResult is true, return true.
        if (testResult) return realm.intrinsics.true;
      }

      // d. Increase k by 1.
      k++;
    }

    // 7. Return false.
    return realm.intrinsics.false;
  });

  // ECMA262 22.1.3.25
  obj.defineNativeMethod("sort", 1, (context, [comparefn]) => {
    // 1. Let obj be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(obj, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // Within this specification of the sort method, an object, obj, is said to be sparse if the following algorithm returns true:
    let isSparse = () => {
      // 1.For each integer i in the range 0≤i< len
      for (let i = 0; i < len; i++) {
        // a.Let elem be obj.[[GetOwnProperty]](! ToString(i)).
        let elem = O.$GetOwnProperty(i.toString());
        // b.If elem is undefined, return true.
        if (elem === undefined) return true;
        _singletons.Properties.ThrowIfMightHaveBeenDeleted(elem.value);
      }
      // 2.Return false.
      return false;
    };
    let sparse = isSparse();

    // Let proto be obj.[[GetPrototypeOf]]().
    let proto = O.$GetPrototypeOf();

    // If proto is not null
    if (!(proto instanceof _index.NullValue)) {
      // and there exists an integer j such that all of the conditions below are satisfied then the sort order is implementation-defined:
      for (let j = 0; j < len; j++) {
        // HasProperty(proto, ToString(j)) is true.
        if ((0, _index2.HasProperty)(realm, proto, j.toString()) &&
        // obj is sparse
        sparse)
          // We abord when the result of the sort is implementation defined.
          throw Error("Implentation defined behavior detected");
      }
    }

    // The sort order is also implementation defined if obj is sparse and any of the following conditions are true:
    if (sparse) {
      // IsExtensible(obj) is false.
      if (!(0, _index2.IsExtensible)(realm, O)) throw Error("Implementation defined behavior, Array is both sparse and extensible");
      // Any integer index property of obj whose name is a nonnegative integer less than len
      for (let j = 0; j < len; j++) {
        // is a data property whose [[Configurable]] attribute is false.
        let prop = O.$GetOwnProperty(j.toString());
        if (prop !== undefined && !prop.configurable) {
          _singletons.Properties.ThrowIfMightHaveBeenDeleted(prop.value);
          throw Error("Implementation defined behavior :  Array is sparse and it's prototype has some numbered properties");
        }
      }
    }

    // Any integer index property of obj whose name is a nonnegative integer less than len
    for (let j = 0; j < len; j++) {
      //is a data property whose [[writable]] attribute is false.
      let prop = O.$GetOwnProperty(j.toString());
      if (prop !== undefined && !prop.writable) {
        _singletons.Properties.ThrowIfMightHaveBeenDeleted(prop.value);
        throw Error("Implementation defined behavior : property " + j.toString() + "is non writable : ");
      }
    }

    // The SortCompare abstract operation is called with two arguments x and y. It also has access to the comparefn
    // argument passed to the current invocation of the sort method. The following steps are taken:

    // 22.1.3.25.1 Runtime Semantics: SortCompare( x, y )#
    let SortCompare = (x, y) => {
      x = x.throwIfNotConcrete();
      y = y.throwIfNotConcrete();
      // 1. If x and y are both undefined, return +0.
      if (x instanceof _index.UndefinedValue && y instanceof _index.UndefinedValue) {
        return realm.intrinsics.zero;
      }
      // 2. If x is undefined, return 1.
      if (x instanceof _index.UndefinedValue) {
        return new _index.NumberValue(realm, 1);
      }
      // 3. If y is undefined, return -1.
      if (y instanceof _index.UndefinedValue) {
        return new _index.NumberValue(realm, -1);
      }
      // 4. If the argument comparefn is not undefined, then
      if (!comparefn.mightBeUndefined()) {
        // a. Let v be ? ToNumber(? Call(comparefn, undefined, « x, y »)).
        let v = _singletons.To.ToNumber(realm, (0, _index2.Call)(realm, comparefn, new _index.UndefinedValue(realm), [x, y]));
        // b. If v is NaN, return +0.
        if (isNaN(v)) return new _index.NumberValue(realm, +0);
        // c. Return v.
        return new _index.NumberValue(realm, v);
      } else {
        comparefn.throwIfNotConcrete();
      }
      // 5. Let xString be ? ToString(x).
      let xString = new _index.StringValue(realm, _singletons.To.ToString(realm, x));
      // 6. Let yString be ? ToString(y).
      let yString = new _index.StringValue(realm, _singletons.To.ToString(realm, y));
      // 7. Let xSmaller be the result of performing Abstract Relational Comparison xString < yString.
      let xSmaller = (0, _abstract.AbstractRelationalComparison)(realm, xString, yString, true, "<");
      // 8. If xSmaller is true, return -1.
      if (xSmaller.value) return new _index.NumberValue(realm, -1);
      // 9. Let ySmaller be the result of performing Abstract Relational Comparison yString < xString.
      let ySmaller = (0, _abstract.AbstractRelationalComparison)(realm, yString, xString, true, "<");
      // 10. If ySmaller is true, return 1.
      if (ySmaller.value) return new _index.NumberValue(realm, 1);
      // 11. Return +0.
      return realm.intrinsics.zero;
    };

    //1. Perform an implementation-dependent sequence of calls to the [[Get]] and [[Set]] internal methods of obj, to the DeletePropertyOrThrow and HasOwnProperty abstract operation with obj as the first argument, and to SortCompare (described below), such that:
    //   The property key argument for each call to [[Get]], [[Set]], HasOwnProperty, or DeletePropertyOrThrow is the string representation of a nonnegative integer less than len.

    // We leverage the underlying implementation sort by copying the element in a temp. array, sorting it, and
    // transfering back the value inside the our array.

    let arr = [];

    // We need to adapt the comparefn function to match the expected types
    let comparefn_ = (x, y) => {
      (0, _invariant2.default)(x instanceof _index.Value, "Unexpected type");
      (0, _invariant2.default)(y instanceof _index.Value, "Unexpected type");

      let result_ = SortCompare(x, y);
      let numb = _singletons.To.ToNumber(realm, result_);
      return numb;
    };

    for (let j = 0; j < len; j++) {
      // The property key argument for each call to [[Get]], [[Set]], HasOwnProperty, or DeletePropertyOrThrow is the string representation of a nonnegative integer less than len.
      if (!(0, _index2.HasOwnProperty)(realm, O, j.toString())) continue;
      // The arguments for calls to SortCompare are values returned by a previous call to the [[Get]] internal method,
      // unless the properties accessed by those previous calls did not exist according to HasOwnProperty.

      // -- Important : We rely on the fact that the underlying sort implementation respect the standard for the following 3 properties
      // If both perspective arguments to SortCompare correspond to non-existent properties,
      // use +0 instead of calling SortCompare. If only the first perspective argument is non-existent use +1.
      // If only the second perspective argument is non-existent use -1.
      let val = O.$Get(j.toString(), O);
      arr[j] = val;
    }

    arr.sort(comparefn_);

    //Apply the permutation back to the original array.
    for (let j = 0; j < len; j++) {
      if (arr.hasOwnProperty(j.toString())) {
        let ok = O.$Set(j.toString(), arr[j], O);
        // If any [[Set]] call returns false a TypeError exception is thrown.
        if (!ok) throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "[[Set]] returned false");
      } else {
        // If obj is not sparse then DeletePropertyOrThrow must not be called.
        (0, _invariant2.default)(sparse);
        _singletons.Properties.DeletePropertyOrThrow(realm, O, j.toString());
      }
    }
    // If an abrupt completion is returned from any of these operations, it is immediately returned as the value of this function.

    // 2. Return obj;
    return context;
  });

  // ECMA262 22.1.3.26
  obj.defineNativeMethod("splice", 2, (context, [start, deleteCount, ...items], argLength) => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // 3. Let relativeStart be ? ToInteger(start).
    let relativeStart = _singletons.To.ToInteger(realm, start);

    // 4. If relativeStart < 0, let actualStart be max((len + relativeStart), 0); else let actualStart be min(relativeStart, len).
    let actualStart = relativeStart < 0 ? Math.max(len + relativeStart, 0) : Math.min(relativeStart, len);

    let insertCount;
    let actualDeleteCount;

    // 5. If the number of actual arguments is 0, then
    if (argLength === 0) {
      // a. Let insertCount be 0.
      insertCount = 0;

      // b. Let actualDeleteCount be 0.
      actualDeleteCount = 0;
    } else if (argLength === 1) {
      // 6. Else if the number of actual arguments is 1, then
      // a. Let insertCount be 0.
      insertCount = 0;

      // b. Let actualDeleteCount be len - actualStart.
      actualDeleteCount = len - actualStart;
    } else {
      // 7. Else,
      // a. Let insertCount be the number of actual arguments minus 2.
      insertCount = argLength - 2;

      // b. Let dc be ? ToInteger(deleteCount).
      let dc = _singletons.To.ToInteger(realm, deleteCount);

      // c. Let actualDeleteCount be min(max(dc, 0), len - actualStart).
      actualDeleteCount = Math.min(Math.max(dc, 0), len - actualStart);
    }

    // 8. If len+insertCount-actualDeleteCount > 2^53-1, throw a TypeError exception.
    if (len + insertCount - actualDeleteCount > Math.pow(2, 53) - 1) {
      throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "the item count is too damn high");
    }

    // 9. Let A be ? ArraySpeciesCreate(O, actualDeleteCount).
    let A = _singletons.Create.ArraySpeciesCreate(realm, O, actualDeleteCount);

    // 10. Let k be 0.
    let k = 0;

    // 11. Repeat, while k < actualDeleteCount
    while (k < actualDeleteCount) {
      // a. Let from be ! ToString(actualStart+k).
      let frm = new _index.StringValue(realm, actualStart + k + "");

      // b. Let fromPresent be ? HasProperty(O, from).
      let fromPresent = (0, _index2.HasProperty)(realm, O, frm);

      // c. If fromPresent is true, then
      if (fromPresent) {
        // i. Let fromValue be ? Get(O, from).
        let fromValue = (0, _index2.Get)(realm, O, frm);

        // ii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(k), fromValue).
        _singletons.Create.CreateDataPropertyOrThrow(realm, A, new _index.StringValue(realm, k + ""), fromValue);
      }

      // d. Increment k by 1.
      k++;
    }

    // 12. Perform ? Set(A, "length", actualDeleteCount, true).
    _singletons.Properties.Set(realm, A, "length", new _index.NumberValue(realm, actualDeleteCount), true);

    // 13. Let items be a List whose elements are, in left to right order, the portion of the actual argument
    //     list starting with the third argument. The list is empty if fewer than three arguments were passed.
    items;

    // 14. Let itemCount be the number of elements in items.
    let itemCount = items.length;

    // 15. If itemCount < actualDeleteCount, then
    if (itemCount < actualDeleteCount) {
      // a. Let k be actualStart.
      k = actualStart;

      // b. Repeat, while k < (len - actualDeleteCount)
      while (k < len - actualDeleteCount) {
        // i. Let from be ! ToString(k+actualDeleteCount).
        let frm = new _index.StringValue(realm, k + actualDeleteCount + "");

        // ii. Let to be ! ToString(k+itemCount).
        let to = new _index.StringValue(realm, k + itemCount + "");

        // iii. Let fromPresent be ? HasProperty(O, from).
        let fromPresent = (0, _index2.HasProperty)(realm, O, frm);

        // iv. If fromPresent is true, then
        if (fromPresent) {
          // 1. Let fromValue be ? Get(O, from).
          let fromValue = (0, _index2.Get)(realm, O, frm);

          // 2. Perform ? Set(O, to, fromValue, true).
          _singletons.Properties.Set(realm, O, to, fromValue, true);
        } else {
          // v. Else fromPresent is false,
          // 1. Perform ? DeletePropertyOrThrow(O, to).
          _singletons.Properties.DeletePropertyOrThrow(realm, O, to);
        }

        // vi. Increase k by 1.
        k++;
      }

      // c. Let k be len.
      k = len;

      // d. Repeat, while k > (len - actualDeleteCount + itemCount)
      while (k > len - actualDeleteCount + itemCount) {
        // i. Perform ? DeletePropertyOrThrow(O, ! ToString(k-1)).
        _singletons.Properties.DeletePropertyOrThrow(realm, O, new _index.StringValue(realm, k - 1 + ""));

        // ii. Decrease k by 1.
        k--;
      }
    } else if (itemCount > actualDeleteCount) {
      // 16. Else if itemCount > actualDeleteCount, then
      // a. Let k be (len - actualDeleteCount).
      k = len - actualDeleteCount;

      // b. Repeat, while k > actualStart
      while (k > actualStart) {
        // i. Let from be ! ToString(k + actualDeleteCount - 1).
        let frm = new _index.StringValue(realm, k + actualDeleteCount - 1 + "");

        // ii. Let to be ! ToString(k + itemCount - 1).
        let to = new _index.StringValue(realm, k + itemCount - 1 + "");

        // iii. Let fromPresent be ? HasProperty(O, from).
        let fromPresent = (0, _index2.HasProperty)(realm, O, frm);

        // iv. If fromPresent is true, then
        if (fromPresent) {
          // 1. Let fromValue be ? Get(O, from).
          let fromValue = (0, _index2.Get)(realm, O, frm);

          // 2. Perform ? Set(O, to, fromValue, true).
          _singletons.Properties.Set(realm, O, to, fromValue, true);
        } else {
          // v. Else fromPresent is false,
          // 1. Perform ? DeletePropertyOrThrow(O, to).
          _singletons.Properties.DeletePropertyOrThrow(realm, O, to);
        }

        // vi. Decrease k by 1.
        k--;
      }
    }

    // 17. Let k be actualStart.
    k = actualStart;

    // 18. Repeat, while items is not empty
    while (items.length) {
      // a. Remove the first element from items and let E be the value of that element.
      let E = items.shift();

      // b. Perform ? Set(O, ! ToString(k), E, true).
      _singletons.Properties.Set(realm, O, new _index.StringValue(realm, k + ""), E, true);

      // c. Increase k by 1.
      k++;
    }

    // 19. Perform ? Set(O, "length", len - actualDeleteCount + itemCount, true).
    _singletons.Properties.Set(realm, O, "length", new _index.NumberValue(realm, len - actualDeleteCount + itemCount), true);

    // 20. Return A.
    return A;
  });

  // ECMA262 22.1.3.27
  obj.defineNativeMethod("toLocaleString", 0, context => {
    // 1. Let array be ? ToObject(this value).
    let array = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(array, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, array, "length"));

    // 3. Let separator be the String value for the list-separator String appropriate for the host environment's
    //    current locale (this is derived in an implementation-defined way).
    let separator = ",";

    // 4. If len is zero, return the empty String.
    if (len === 0) return realm.intrinsics.emptyString;

    // 5. Let firstElement be ? Get(array, "0").
    let firstElement = (0, _index2.Get)(realm, array, "0");

    // 6. If firstElement is undefined or null, then
    let R;
    if ((0, _index2.HasSomeCompatibleType)(firstElement, _index.UndefinedValue, _index.NullValue)) {
      // a. Let R be the empty String.
      R = "";
    } else {
      // 7. Else,
      // a. Let R be ? ToString(? Invoke(firstElement, "toLocaleString")).
      R = _singletons.To.ToStringPartial(realm, (0, _index2.Invoke)(realm, firstElement, "toLocaleString"));
    }

    // 8. Let k be 1.
    let k = 1;

    // 9. Repeat, while k < len
    while (k < len) {
      // a. Let S be a String value produced by concatenating R and separator.
      let S = R + separator;

      // b. Let nextElement be ? Get(array, ! ToString(k)).
      let nextElement = (0, _index2.Get)(realm, array, new _index.StringValue(realm, k + "")).throwIfNotConcrete();

      // c. If nextElement is undefined or null, then
      if ((0, _index2.HasSomeCompatibleType)(nextElement, _index.UndefinedValue, _index.NullValue)) {
        // i. Let R be the empty String.
        R = "";
      } else {
        // d. Else,
        // i. Let R be ? ToString(? Invoke(nextElement, "toLocaleString")).
        R = _singletons.To.ToStringPartial(realm, (0, _index2.Invoke)(realm, nextElement, "toLocaleString"));
      }

      // e. Let R be a String value produced by concatenating S and R.
      R = S + R;

      // f. Increase k by 1.
      k++;
    }

    // 10. Return R.
    return new _index.StringValue(realm, R);
  });

  // ECMA262 22.1.3.28
  obj.defineNativeProperty("toString", realm.intrinsics.ArrayProto_toString);

  // ECMA262 22.1.3.29
  obj.defineNativeMethod("unshift", 1, (context, items, argCount) => {
    // 1. Let O be ? ToObject(this value).
    let O = _singletons.To.ToObject(realm, context.throwIfNotConcrete());

    // 2. Let len be ? ToLength(? Get(O, "length")).
    let len = _singletons.To.ToLength(realm, (0, _index2.Get)(realm, O, "length"));

    // 3. Let argCount be the number of actual arguments.
    argCount;

    // 4. If argCount > 0, then
    if (argCount > 0) {
      // a. If len+argCount > 2^53-1, throw a TypeError exception.
      if (len + argCount > Math.pow(2, 53) - 1) {
        throw realm.createErrorThrowCompletion(realm.intrinsics.TypeError, "too damn high");
      }

      // b. Let k be len.
      let k = len;

      // c. Repeat, while k > 0,
      while (k > 0) {
        // i. Let from be ! ToString(k-1).
        let frm = new _index.StringValue(realm, k - 1 + "");

        // ii. Let to be ! ToString(k+argCount-1).
        let to = new _index.StringValue(realm, k + argCount - 1 + "");

        // iv. Let fromPresent be ? HasProperty(O, from).
        let fromPresent = (0, _index2.HasProperty)(realm, O, frm);

        // v. If fromPresent is true, then
        if (fromPresent) {
          // 1. Let fromValue be ? Get(O, from).
          let fromValue = (0, _index2.Get)(realm, O, frm);

          // 2. Perform ? Set(O, to, fromValue, true).
          _singletons.Properties.Set(realm, O, to, fromValue, true);
        } else {
          // vi. Else fromPresent is false,
          // 1. Perform ? DeletePropertyOrThrow(O, to).
          _singletons.Properties.DeletePropertyOrThrow(realm, O, to);
        }

        // vii. Decrease k by 1.
        k--;
      }

      // e. Let j be 0.
      let j = 0;

      // f. Let items be a List whose elements are, in left to right order, the arguments that were passed to
      //    this function invocation.
      items;

      // g. Repeat, while items is not empty
      while (items.length) {
        // i. Remove the first element from items and let E be the value of that element.
        let E = items.shift();

        // ii. Perform ? Set(O, ! ToString(j), E, true).
        _singletons.Properties.Set(realm, O, new _index.StringValue(realm, j + ""), E, true);

        // iii. Increase j by 1.
        j++;
      }
    }

    // 5. Perform ? Set(O, "length", len+argCount, true).
    _singletons.Properties.Set(realm, O, "length", new _index.NumberValue(realm, len + argCount), true);

    // 6. Return len+argCount.
    return new _index.NumberValue(realm, len + argCount);
  });

  // ECMA262 22.1.3.30
  obj.defineNativeProperty("values", realm.intrinsics.ArrayProto_values);

  // ECMA262 22.1.3.32
  {
    // 1. Let unscopableList be ObjectCreate(null).
    let unscopableList = _singletons.Create.ObjectCreate(realm, realm.intrinsics.null);

    // 2. Perform CreateDataProperty(unscopableList, "copyWithin", true).
    _singletons.Create.CreateDataProperty(realm, unscopableList, "copyWithin", realm.intrinsics.true);

    // 3. Perform CreateDataProperty(unscopableList, "entries", true).
    _singletons.Create.CreateDataProperty(realm, unscopableList, "entries", realm.intrinsics.true);

    // 4. Perform CreateDataProperty(unscopableList, "fill", true).
    _singletons.Create.CreateDataProperty(realm, unscopableList, "fill", realm.intrinsics.true);

    // 5. Perform CreateDataProperty(unscopableList, "find", true).
    _singletons.Create.CreateDataProperty(realm, unscopableList, "find", realm.intrinsics.true);

    // 6. Perform CreateDataProperty(unscopableList, "findIndex", true).
    _singletons.Create.CreateDataProperty(realm, unscopableList, "findIndex", realm.intrinsics.true);

    // 7. Perform CreateDataProperty(unscopableList, "includes", true).
    _singletons.Create.CreateDataProperty(realm, unscopableList, "includes", realm.intrinsics.true);

    // 8. Perform CreateDataProperty(unscopableList, "keys", true).
    _singletons.Create.CreateDataProperty(realm, unscopableList, "keys", realm.intrinsics.true);

    // 9. Perform CreateDataProperty(unscopableList, "values", true).
    _singletons.Create.CreateDataProperty(realm, unscopableList, "values", realm.intrinsics.true);

    // 10. Assert: Each of the above calls will return true.

    // 11. Return unscopableList.
    obj.defineNativeProperty(realm.intrinsics.SymbolUnscopables, unscopableList, {
      writable: false
    });
  }
};

var _index = require("../../values/index.js");

var _invariant = require("../../invariant.js");

var _invariant2 = _interopRequireDefault(_invariant);

var _abstract = require("../../methods/abstract.js");

var _index2 = require("../../methods/index.js");

var _singletons = require("../../singletons.js");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
//# sourceMappingURL=ArrayPrototype.js.map