Prechádzať zdrojové kódy

Implement relative indexing proposal [at() method] (#985)

* add test262 tests for relative indexing
* implement relative indexing
Gökhan Kurt 3 rokov pred
rodič
commit
57b9b3c79b
26 zmenil súbory, kde vykonal 710 pridanie a 7 odobranie
  1. 0 4
      Jint.Tests.Test262/Test262Test.cs
  2. 31 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/at/index-argument-tointeger.js
  3. 24 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/at/index-non-numeric-argument-tointeger-invalid.js
  4. 30 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/at/index-non-numeric-argument-tointeger.js
  5. 28 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/at/length.js
  6. 30 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/at/name.js
  7. 30 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/at/prop-desc.js
  8. 26 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/at/return-abrupt-from-this.js
  9. 34 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/at/returns-item-relative-index.js
  10. 35 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/at/returns-item.js
  11. 43 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/at/returns-undefined-for-holes-in-sparse-arrays.js
  12. 24 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/at/returns-undefined-for-out-of-range-index.js
  13. 27 0
      Jint.Tests.Test262/test/built-ins/String/prototype/at/index-argument-tointeger.js
  14. 20 0
      Jint.Tests.Test262/test/built-ins/String/prototype/at/index-non-numeric-argument-tointeger-invalid.js
  15. 26 0
      Jint.Tests.Test262/test/built-ins/String/prototype/at/index-non-numeric-argument-tointeger.js
  16. 24 0
      Jint.Tests.Test262/test/built-ins/String/prototype/at/length.js
  17. 26 0
      Jint.Tests.Test262/test/built-ins/String/prototype/at/name.js
  18. 26 0
      Jint.Tests.Test262/test/built-ins/String/prototype/at/prop-desc.js
  19. 22 0
      Jint.Tests.Test262/test/built-ins/String/prototype/at/return-abrupt-from-this.js
  20. 30 0
      Jint.Tests.Test262/test/built-ins/String/prototype/at/returns-code-unit.js
  21. 29 0
      Jint.Tests.Test262/test/built-ins/String/prototype/at/returns-item-relative-index.js
  22. 30 0
      Jint.Tests.Test262/test/built-ins/String/prototype/at/returns-item.js
  23. 20 0
      Jint.Tests.Test262/test/built-ins/String/prototype/at/returns-undefined-for-out-of-range-index.js
  24. 30 1
      Jint/Native/Array/ArrayPrototype.cs
  25. 33 1
      Jint/Native/String/StringPrototype.cs
  26. 32 1
      Jint/Native/TypedArray/IntrinsicTypedArrayPrototype.cs

+ 0 - 4
Jint.Tests.Test262/Test262Test.cs

@@ -295,10 +295,6 @@ namespace Jint.Tests.Test262
                                 skip = true;
                                 reason = "resizable-arraybuffer not implemented";
                                 break;
-                            case "TypedArray.prototype.at":
-                                skip = true;
-                                reason = "TypedArray.prototype.at not implemented";
-                                break;
                         }
                     }
                 }

+ 31 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/at/index-argument-tointeger.js

@@ -0,0 +1,31 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-array.prototype.at
+description: >
+  Property type and descriptor.
+info: |
+  Array.prototype.at( index )
+
+  Let relativeIndex be ? ToInteger(index).
+
+features: [Array.prototype.at]
+---*/
+assert.sameValue(
+  typeof Array.prototype.at,
+  'function',
+  'The value of `typeof Array.prototype.at` is expected to be "function"'
+);
+
+let valueOfCallCount = 0;
+let index = {
+  valueOf() {
+    valueOfCallCount++;
+    return 1;
+  }
+};
+
+let a = [0,1,2,3];
+
+assert.sameValue(a.at(index), 1, 'a.at({valueOf() {valueOfCallCount++; return 1;}}) must return 1');
+assert.sameValue(valueOfCallCount, 1, 'The value of valueOfCallCount is expected to be 1');

+ 24 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/at/index-non-numeric-argument-tointeger-invalid.js

@@ -0,0 +1,24 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-array.prototype.at
+description: >
+  Property type and descriptor.
+info: |
+  Array.prototype.at( index )
+
+  Let relativeIndex be ? ToInteger(index).
+
+features: [Array.prototype.at]
+---*/
+assert.sameValue(
+  typeof Array.prototype.at,
+  'function',
+  'The value of `typeof Array.prototype.at` is expected to be "function"'
+);
+
+let a = [0,1,2,3];
+
+assert.throws(TypeError, () => {
+  a.at(Symbol());
+}, 'a.at(Symbol()) throws a TypeError exception');

+ 30 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/at/index-non-numeric-argument-tointeger.js

@@ -0,0 +1,30 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-array.prototype.at
+description: >
+  Property type and descriptor.
+info: |
+  Array.prototype.at( index )
+
+  Let relativeIndex be ? ToInteger(index).
+
+features: [Array.prototype.at]
+---*/
+assert.sameValue(
+  typeof Array.prototype.at,
+  'function',
+  'The value of `typeof Array.prototype.at` is expected to be "function"'
+);
+
+let a = [0,1,2,3];
+
+assert.sameValue(a.at(false), 0, 'a.at(false) must return 0');
+assert.sameValue(a.at(null), 0, 'a.at(null) must return 0');
+assert.sameValue(a.at(undefined), 0, 'a.at(undefined) must return 0');
+assert.sameValue(a.at(""), 0, 'a.at("") must return 0');
+assert.sameValue(a.at(function() {}), 0, 'a.at(function() {}) must return 0');
+assert.sameValue(a.at([]), 0, 'a.at([]) must return 0');
+
+assert.sameValue(a.at(true), 1, 'a.at(true) must return 1');
+assert.sameValue(a.at("1"), 1, 'a.at("1") must return 1');

+ 28 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/at/length.js

@@ -0,0 +1,28 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-array.prototype.at
+description: >
+  Array.prototype.at.length value and descriptor.
+info: |
+  Array.prototype.at( index )
+
+  17 ECMAScript Standard Built-in Objects
+
+includes: [propertyHelper.js]
+features: [Array.prototype.at]
+---*/
+assert.sameValue(
+  typeof Array.prototype.at,
+  'function',
+  'The value of `typeof Array.prototype.at` is expected to be "function"'
+);
+
+assert.sameValue(
+  Array.prototype.at.length, 1,
+  'The value of Array.prototype.at.length is expected to be 1'
+);
+
+verifyNotEnumerable(Array.prototype.at, 'length');
+verifyNotWritable(Array.prototype.at, 'length');
+verifyConfigurable(Array.prototype.at, 'length');

+ 30 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/at/name.js

@@ -0,0 +1,30 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-array.prototype.at
+description: >
+  Array.prototype.at.name value and descriptor.
+info: |
+  Array.prototype.at( index )
+
+  17 ECMAScript Standard Built-in Objects
+
+includes: [propertyHelper.js]
+features: [Array.prototype.at]
+---*/
+assert.sameValue(
+  typeof Array.prototype.at,
+  'function',
+  'The value of `typeof Array.prototype.at` is expected to be "function"'
+);
+
+assert.sameValue(
+  Array.prototype.at.name, 'at',
+  'The value of Array.prototype.at.name is expected to be "at"'
+);
+
+verifyProperty(Array.prototype.at, 'name', {
+  enumerable: false,
+  writable: false,
+  configurable: true
+});

+ 30 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/at/prop-desc.js

@@ -0,0 +1,30 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-array.prototype.at
+description: >
+  Property type and descriptor.
+info: |
+  Array.prototype.at( index )
+
+  17 ECMAScript Standard Built-in Objects
+includes: [propertyHelper.js]
+features: [Array.prototype.at]
+---*/
+assert.sameValue(
+  typeof Array.prototype.at,
+  'function',
+  'The value of `typeof Array.prototype.at` is expected to be "function"'
+);
+
+assert.sameValue(
+  typeof Array.prototype.at,
+  'function',
+  'The value of `typeof Array.prototype.at` is expected to be "function"'
+);
+
+verifyProperty(Array.prototype, 'at', {
+  enumerable: false,
+  writable: true,
+  configurable: true
+});

+ 26 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/at/return-abrupt-from-this.js

@@ -0,0 +1,26 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-array.prototype.at
+description: >
+  Return abrupt from ToObject(this value).
+info: |
+  Array.prototype.at( index )
+
+  Let O be ? ToObject(this value).
+
+features: [Array.prototype.at]
+---*/
+assert.sameValue(
+  typeof Array.prototype.at,
+  'function',
+  'The value of `typeof Array.prototype.at` is expected to be "function"'
+);
+
+assert.throws(TypeError, () => {
+  Array.prototype.at.call(undefined);
+}, 'Array.prototype.at.call(undefined) throws a TypeError exception');
+
+assert.throws(TypeError, () => {
+  Array.prototype.at.call(null);
+}, 'Array.prototype.at.call(null) throws a TypeError exception');

+ 34 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/at/returns-item-relative-index.js

@@ -0,0 +1,34 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-array.prototype.at
+description: >
+  Returns the item value at the specified relative index
+info: |
+  Array.prototype.at ( )
+
+  Let O be ? ToObject(this value).
+  Let len be ? LengthOfArrayLike(O).
+  Let relativeIndex be ? ToInteger(index).
+  If relativeIndex ≥ 0, then
+    Let k be relativeIndex.
+  Else,
+    Let k be len + relativeIndex.
+  If k < 0 or k ≥ len, then return undefined.
+  Return ? Get(O, ! ToString(k)).
+
+features: [Array.prototype.at]
+---*/
+assert.sameValue(
+  typeof Array.prototype.at,
+  'function',
+  'The value of `typeof Array.prototype.at` is expected to be "function"'
+);
+
+let a = [1, 2, 3, 4, ,5];
+
+assert.sameValue(a.at(0), 1, 'a.at(0) must return 1');
+assert.sameValue(a.at(-1), 5, 'a.at(-1) must return 5');
+assert.sameValue(a.at(-2), undefined, 'a.at(-2) returns undefined');
+assert.sameValue(a.at(-3), 4, 'a.at(-3) must return 4');
+assert.sameValue(a.at(-4), 3, 'a.at(-4) must return 3');

+ 35 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/at/returns-item.js

@@ -0,0 +1,35 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-array.prototype.at
+description: >
+  Returns the item value at the specified index
+info: |
+  Array.prototype.at ( )
+
+  Let O be ? ToObject(this value).
+  Let len be ? LengthOfArrayLike(O).
+  Let relativeIndex be ? ToInteger(index).
+  If relativeIndex ≥ 0, then
+    Let k be relativeIndex.
+  Else,
+    Let k be len + relativeIndex.
+  If k < 0 or k ≥ len, then return undefined.
+  Return ? Get(O, ! ToString(k)).
+
+features: [Array.prototype.at]
+---*/
+assert.sameValue(
+  typeof Array.prototype.at,
+  'function',
+  'The value of `typeof Array.prototype.at` is expected to be "function"'
+);
+
+let a = [1, 2, 3, 4,,5];
+
+assert.sameValue(a.at(0), 1, 'a.at(0) must return 1');
+assert.sameValue(a.at(1), 2, 'a.at(1) must return 2');
+assert.sameValue(a.at(2), 3, 'a.at(2) must return 3');
+assert.sameValue(a.at(3), 4, 'a.at(3) must return 4');
+assert.sameValue(a.at(4), undefined, 'a.at(4) returns undefined');
+assert.sameValue(a.at(5), 5, 'a.at(5) must return 5');

+ 43 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/at/returns-undefined-for-holes-in-sparse-arrays.js

@@ -0,0 +1,43 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-array.prototype.at
+description: >
+  Returns the item value at the specified index, respecting holes in sparse arrays.
+info: |
+  Array.prototype.at ( )
+
+  Let O be ? ToObject(this value).
+  Let len be ? LengthOfArrayLike(O).
+  Let relativeIndex be ? ToInteger(index).
+  If relativeIndex ≥ 0, then
+    Let k be relativeIndex.
+  Else,
+    Let k be len + relativeIndex.
+  If k < 0 or k ≥ len, then return undefined.
+  Return ? Get(O, ! ToString(k)).
+
+features: [Array.prototype.at]
+---*/
+assert.sameValue(
+  typeof Array.prototype.at,
+  'function',
+  'The value of `typeof Array.prototype.at` is expected to be "function"'
+);
+
+let a = [0, 1, , 3, 4, , 6];
+
+assert.sameValue(a.at(0), 0, 'a.at(0) must return 0');
+assert.sameValue(a.at(1), 1, 'a.at(1) must return 1');
+assert.sameValue(a.at(2), undefined, 'a.at(2) returns undefined');
+assert.sameValue(a.at(3), 3, 'a.at(3) must return 3');
+assert.sameValue(a.at(4), 4, 'a.at(4) must return 4');
+assert.sameValue(a.at(5), undefined, 'a.at(5) returns undefined');
+assert.sameValue(a.at(6), 6, 'a.at(6) must return 6');
+assert.sameValue(a.at(-0), 0, 'a.at(-0) must return 0');
+assert.sameValue(a.at(-1), 6, 'a.at(-1) must return 6');
+assert.sameValue(a.at(-2), undefined, 'a.at(-2) returns undefined');
+assert.sameValue(a.at(-3), 4, 'a.at(-3) must return 4');
+assert.sameValue(a.at(-4), 3, 'a.at(-4) must return 3');
+assert.sameValue(a.at(-5), undefined, 'a.at(-5) returns undefined');
+assert.sameValue(a.at(-6), 1, 'a.at(-6) must return 1');

+ 24 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/at/returns-undefined-for-out-of-range-index.js

@@ -0,0 +1,24 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-array.prototype.at
+description: >
+  Returns undefined if the specified index less than or greater than the available index range.
+info: |
+  Array.prototype.at( index )
+
+  If k < 0 or k ≥ len, then return undefined.
+features: [Array.prototype.at]
+---*/
+assert.sameValue(
+  typeof Array.prototype.at,
+  'function',
+  'The value of `typeof Array.prototype.at` is expected to be "function"'
+);
+
+let a = [];
+
+assert.sameValue(a.at(-2), undefined, 'a.at(-2) returns undefined'); // wrap around the end
+assert.sameValue(a.at(0), undefined, 'a.at(0) returns undefined');
+assert.sameValue(a.at(1), undefined, 'a.at(1) returns undefined');
+

+ 27 - 0
Jint.Tests.Test262/test/built-ins/String/prototype/at/index-argument-tointeger.js

@@ -0,0 +1,27 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-string.prototype.at
+description: >
+  Property type and descriptor.
+info: |
+  String.prototype.at( index )
+
+  Let relativeIndex be ? ToInteger(index).
+
+features: [String.prototype.at]
+---*/
+assert.sameValue(typeof String.prototype.at, 'function');
+
+let valueOfCallCount = 0;
+let index = {
+  valueOf() {
+    valueOfCallCount++;
+    return 1;
+  }
+};
+
+let s = "01";
+
+assert.sameValue(s.at(index), '1', 's.at({valueOf() {valueOfCallCount++; return 1;}}) must return 1');
+assert.sameValue(valueOfCallCount, 1, 'The value of `valueOfCallCount` is 1');

+ 20 - 0
Jint.Tests.Test262/test/built-ins/String/prototype/at/index-non-numeric-argument-tointeger-invalid.js

@@ -0,0 +1,20 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-string.prototype.at
+description: >
+  Property type and descriptor.
+info: |
+  String.prototype.at( index )
+
+  Let relativeIndex be ? ToInteger(index).
+
+features: [String.prototype.at]
+---*/
+assert.sameValue(typeof String.prototype.at, 'function');
+
+let s = "01";
+
+assert.throws(TypeError, () => {
+  s.at(Symbol());
+}, '`s.at(Symbol())` throws TypeError');

+ 26 - 0
Jint.Tests.Test262/test/built-ins/String/prototype/at/index-non-numeric-argument-tointeger.js

@@ -0,0 +1,26 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-string.prototype.at
+description: >
+  Property type and descriptor.
+info: |
+  String.prototype.at( index )
+
+  Let relativeIndex be ? ToInteger(index).
+
+features: [String.prototype.at]
+---*/
+assert.sameValue(typeof String.prototype.at, 'function');
+
+let s = "01";
+
+assert.sameValue(s.at(false), '0', 's.at(false) must return 0');
+assert.sameValue(s.at(null), '0', 's.at(null) must return 0');
+assert.sameValue(s.at(undefined), '0', 's.at(undefined) must return 0');
+assert.sameValue(s.at(""), '0', 's.at("") must return 0');
+assert.sameValue(s.at(function() {}), '0', 's.at(function() {}) must return 0');
+assert.sameValue(s.at([]), '0', 's.at([]) must return 0');
+
+assert.sameValue(s.at(true), '1', 's.at(true) must return 1');
+assert.sameValue(s.at("1"), '1', 's.at("1") must return 1');

+ 24 - 0
Jint.Tests.Test262/test/built-ins/String/prototype/at/length.js

@@ -0,0 +1,24 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-string.prototype.at
+description: >
+  String.prototype.at.length value and descriptor.
+info: |
+  String.prototype.at( index )
+
+  17 ECMAScript Standard Built-in Objects
+
+includes: [propertyHelper.js]
+features: [String.prototype.at]
+---*/
+assert.sameValue(typeof String.prototype.at, 'function');
+
+assert.sameValue(
+  String.prototype.at.length, 1,
+  'The value of String.prototype.at.length is 1'
+);
+
+verifyNotEnumerable(String.prototype.at, 'length');
+verifyNotWritable(String.prototype.at, 'length');
+verifyConfigurable(String.prototype.at, 'length');

+ 26 - 0
Jint.Tests.Test262/test/built-ins/String/prototype/at/name.js

@@ -0,0 +1,26 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-string.prototype.at
+description: >
+  String.prototype.at.name value and descriptor.
+info: |
+  String.prototype.at( index )
+
+  17 ECMAScript Standard Built-in Objects
+
+includes: [propertyHelper.js]
+features: [String.prototype.at]
+---*/
+assert.sameValue(typeof String.prototype.at, 'function');
+
+assert.sameValue(
+  String.prototype.at.name, 'at',
+  'The value of String.prototype.at.name is "at"'
+);
+
+verifyProperty(String.prototype.at, 'name', {
+  enumerable: false,
+  writable: false,
+  configurable: true
+});

+ 26 - 0
Jint.Tests.Test262/test/built-ins/String/prototype/at/prop-desc.js

@@ -0,0 +1,26 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-string.prototype.at
+description: >
+  Property type and descriptor.
+info: |
+  String.prototype.at( index )
+
+  17 ECMAScript Standard Built-in Objects
+includes: [propertyHelper.js]
+features: [String.prototype.at]
+---*/
+assert.sameValue(typeof String.prototype.at, 'function');
+
+assert.sameValue(
+  typeof String.prototype.at,
+  'function',
+  'The value of `typeof String.prototype.at` is "function"'
+);
+
+verifyProperty(String.prototype, 'at', {
+  enumerable: false,
+  writable: true,
+  configurable: true
+});

+ 22 - 0
Jint.Tests.Test262/test/built-ins/String/prototype/at/return-abrupt-from-this.js

@@ -0,0 +1,22 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-string.prototype.at
+description: >
+  Return abrupt from RequireObjectCoercible(this value).
+info: |
+  String.prototype.at( index )
+
+  Let O be ? RequireObjectCoercible(this value).
+
+features: [String.prototype.at]
+---*/
+assert.sameValue(typeof String.prototype.at, 'function');
+
+assert.throws(TypeError, () => {
+  String.prototype.at.call(undefined);
+}, '`String.prototype.at.call(undefined)` throws TypeError');
+
+assert.throws(TypeError, () => {
+  String.prototype.at.call(null);
+}, '`String.prototype.at.call(null)` throws TypeError');

+ 30 - 0
Jint.Tests.Test262/test/built-ins/String/prototype/at/returns-code-unit.js

@@ -0,0 +1,30 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-String.prototype.at
+description: >
+  The method should return an Iterator instance.
+info: |
+  String.prototype.at ( )
+
+  Let O be ? ToObject(this value).
+  Let len be ? LengthOfStringLike(O).
+  Let relativeIndex be ? ToInteger(index).
+  If relativeIndex ≥ 0, then
+    Let k be relativeIndex.
+  Else,
+    Let k be len + relativeIndex.
+  If k < 0 or k ≥ len, then return undefined.
+  Return ? Get(O, ! ToString(k)).
+
+features: [String.prototype.at]
+---*/
+assert.sameValue(typeof String.prototype.at, 'function');
+
+let s = "12\uD80034";
+
+assert.sameValue(s.at(0), "1", 's.at(0) must return "1"');
+assert.sameValue(s.at(1), "2", 's.at(1) must return "2"');
+assert.sameValue(s.at(2), "\uD800", 's.at(2) must return "\\uD800"');
+assert.sameValue(s.at(3), "3", 's.at(3) must return "3"');
+assert.sameValue(s.at(4), "4", 's.at(4) must return "4"');

+ 29 - 0
Jint.Tests.Test262/test/built-ins/String/prototype/at/returns-item-relative-index.js

@@ -0,0 +1,29 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-String.prototype.at
+description: >
+  Returns the item value at the specified relative index
+info: |
+  String.prototype.at ( )
+
+  Let O be ? ToObject(this value).
+  Let len be ? LengthOfStringLike(O).
+  Let relativeIndex be ? ToInteger(index).
+  If relativeIndex ≥ 0, then
+    Let k be relativeIndex.
+  Else,
+    Let k be len + relativeIndex.
+  If k < 0 or k ≥ len, then return undefined.
+  Return ? Get(O, ! ToString(k)).
+
+features: [String.prototype.at]
+---*/
+assert.sameValue(typeof String.prototype.at, 'function');
+
+let s = "12345";
+
+assert.sameValue(s.at(0), "1", 's.at(0) must return "1"');
+assert.sameValue(s.at(-1), "5", 's.at(-1) must return "5"');
+assert.sameValue(s.at(-3), "3", 's.at(-3) must return "3"');
+assert.sameValue(s.at(-4), "2", 's.at(-4) must return "2"');

+ 30 - 0
Jint.Tests.Test262/test/built-ins/String/prototype/at/returns-item.js

@@ -0,0 +1,30 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-String.prototype.at
+description: >
+  Returns the item value at the specified index
+info: |
+  String.prototype.at ( )
+
+  Let O be ? ToObject(this value).
+  Let len be ? LengthOfStringLike(O).
+  Let relativeIndex be ? ToInteger(index).
+  If relativeIndex ≥ 0, then
+    Let k be relativeIndex.
+  Else,
+    Let k be len + relativeIndex.
+  If k < 0 or k ≥ len, then return undefined.
+  Return ? Get(O, ! ToString(k)).
+
+features: [String.prototype.at]
+---*/
+assert.sameValue(typeof String.prototype.at, 'function');
+
+let s = "12345";
+
+assert.sameValue(s.at(0), "1", 's.at(0) must return "1"');
+assert.sameValue(s.at(1), "2", 's.at(1) must return "2"');
+assert.sameValue(s.at(2), "3", 's.at(2) must return "3"');
+assert.sameValue(s.at(3), "4", 's.at(3) must return "4"');
+assert.sameValue(s.at(4), "5", 's.at(4) must return "5"');

+ 20 - 0
Jint.Tests.Test262/test/built-ins/String/prototype/at/returns-undefined-for-out-of-range-index.js

@@ -0,0 +1,20 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-string.prototype.at
+description: >
+  Creates an iterator from a custom object.
+info: |
+  String.prototype.at( index )
+
+  If k < 0 or k ≥ len, then return undefined.
+features: [String.prototype.at]
+---*/
+assert.sameValue(typeof String.prototype.at, 'function');
+
+let s = "";
+
+assert.sameValue(s.at(-2), undefined, 's.at(-2) must return undefined'); // wrap around the end
+assert.sameValue(s.at(0), undefined, 's.at(0) must return undefined');
+assert.sameValue(s.at(1), undefined, 's.at(1) must return undefined');
+

+ 30 - 1
Jint/Native/Array/ArrayPrototype.cs

@@ -44,6 +44,7 @@ namespace Jint.Native.Array
                 _prototype = null
             };
 
+            unscopables.SetDataProperty("at", JsBoolean.True);
             unscopables.SetDataProperty("copyWithin", JsBoolean.True);
             unscopables.SetDataProperty("entries", JsBoolean.True);
             unscopables.SetDataProperty("fill", JsBoolean.True);
@@ -90,6 +91,7 @@ namespace Jint.Native.Array
                 ["values"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "values", Values, 0, PropertyFlag.Configurable), propertyFlags),
                 ["flat"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "flat", Flat, 0, PropertyFlag.Configurable), propertyFlags),
                 ["flatMap"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "flatMap", FlatMap, 1, PropertyFlag.Configurable), propertyFlags),
+                ["at"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "at", At, 1, PropertyFlag.Configurable), propertyFlags),
             };
             SetProperties(properties);
 
@@ -748,6 +750,33 @@ namespace Jint.Native.Array
             return -1;
         }
 
+        /// <summary>
+        /// https://tc39.es/proposal-relative-indexing-method/#sec-array-prototype-additions
+        /// </summary>
+        private JsValue At(JsValue thisObj, JsValue[] arguments)
+        {
+            var target = TypeConverter.ToObject(_realm, thisObj);
+            var len = target.Length;
+            var relativeIndex = TypeConverter.ToInteger(arguments.At(0));
+
+            ulong actualIndex;
+            if (relativeIndex < 0)
+            {
+                actualIndex = (ulong) (len + relativeIndex);
+            }
+            else
+            {
+                actualIndex = (ulong) relativeIndex;
+            }
+
+            if (actualIndex < 0 || actualIndex >= len)
+            {
+                return Undefined;
+            }
+
+            return target.Get(actualIndex);
+        }
+
         private JsValue Splice(JsValue thisObj, JsValue[] arguments)
         {
             var start = arguments.At(0);
@@ -1456,4 +1485,4 @@ namespace Jint.Native.Array
         }
     }
 
-}
+}

+ 33 - 1
Jint/Native/String/StringPrototype.cs

@@ -77,7 +77,8 @@ namespace Jint.Native.String
                 ["padEnd"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "padEnd", PadEnd, 1, lengthFlags), propertyFlags),
                 ["includes"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "includes", Includes, 1, lengthFlags), propertyFlags),
                 ["normalize"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "normalize", Normalize, 0, lengthFlags), propertyFlags),
-                ["repeat"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "repeat", Repeat, 1, lengthFlags), propertyFlags)
+                ["repeat"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "repeat", Repeat, 1, lengthFlags), propertyFlags),
+                ["at"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "at", At, 1, lengthFlags), propertyFlags),
             };
             SetProperties(properties);
 
@@ -404,6 +405,37 @@ namespace Jint.Native.String
             return a;
         }
 
+        /// <summary>
+        /// https://tc39.es/proposal-relative-indexing-method/#sec-string-prototype-additions
+        /// </summary>
+        private JsValue At(JsValue thisObj, JsValue[] arguments)
+        {
+            TypeConverter.CheckObjectCoercible(_engine, thisObj);
+            var start = arguments.At(0);
+
+            var o = thisObj.ToString();
+            long len = o.Length;
+
+            var relativeIndex = TypeConverter.ToInteger(start);
+            int k;
+
+            if (relativeIndex < 0)
+            {
+                k = (int) (len + relativeIndex);
+            }
+            else
+            {
+                k = (int) relativeIndex;
+            }
+
+            if (k < 0 || k >= len)
+            {
+                return Undefined;
+            }
+
+            return o[k];
+        }
+
         private JsValue Slice(JsValue thisObj, JsValue[] arguments)
         {
             TypeConverter.CheckObjectCoercible(Engine, thisObj);

+ 32 - 1
Jint/Native/TypedArray/IntrinsicTypedArrayPrototype.cs

@@ -71,7 +71,8 @@ namespace Jint.Native.TypedArray
                 ["subarray"] = new(new ClrFunctionInstance(Engine, "subarray", Subarray, 2, PropertyFlag.Configurable), propertyFlags),
                 ["toLocaleString"] = new(new ClrFunctionInstance(Engine, "toLocaleString", ToLocaleString, 0, PropertyFlag.Configurable), propertyFlags),
                 ["toString"] = new(new ClrFunctionInstance(Engine, "toLocaleString", _realm.Intrinsics.Array.PrototypeObject.ToString, 0, PropertyFlag.Configurable), propertyFlags),
-                ["values"] = new(new ClrFunctionInstance(Engine, "values", Values, 0, PropertyFlag.Configurable), propertyFlags)
+                ["values"] = new(new ClrFunctionInstance(Engine, "values", Values, 0, PropertyFlag.Configurable), propertyFlags),
+                ["at"] = new(new ClrFunctionInstance(Engine, "at", At, 1, PropertyFlag.Configurable), propertyFlags),
             };
             SetProperties(properties);
 
@@ -979,6 +980,36 @@ namespace Jint.Native.TypedArray
             }
         }
 
+        /// <summary>
+        /// https://tc39.es/proposal-relative-indexing-method/#sec-%typedarray.prototype%-additions
+        /// </summary>
+        private JsValue At(JsValue thisObj, JsValue[] arguments)
+        {
+            var start = arguments.At(0);
+
+            var o = thisObj.ValidateTypedArray(_realm);
+            long len = o.Length;
+
+            var relativeStart = TypeConverter.ToInteger(start);
+            int k;
+
+            if (relativeStart < 0)
+            {
+                k = (int) (len + relativeStart);
+            }
+            else
+            {
+                k = (int) relativeStart;
+            }
+
+            if(k < 0 || k >= len)
+            {
+                return Undefined;
+            }
+
+            return o.Get(k);
+        }
+
         /// <summary>
         /// https://tc39.es/ecma262/#sec-%typedarray%.prototype.slice
         /// </summary>