Browse Source

Implement flat and flatMap (#834)

* meta property for new.target
* fix native function syntax
* ensure latest test cases present
Marko Lahma 4 years ago
parent
commit
89ac4fbbc2
47 changed files with 1575 additions and 92 deletions
  1. 5 4
      Jint.Tests.Test262/Test262Test.cs
  2. 4 4
      Jint.Tests.Test262/test/built-ins/Array/prototype/flat/array-like-objects.js
  3. 11 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flat/call-with-boolean.js
  4. 5 3
      Jint.Tests.Test262/test/built-ins/Array/prototype/flat/length.js
  5. 5 3
      Jint.Tests.Test262/test/built-ins/Array/prototype/flat/name.js
  6. 11 11
      Jint.Tests.Test262/test/built-ins/Array/prototype/flat/non-numeric-depth-should-not-throw.js
  7. 5 3
      Jint.Tests.Test262/test/built-ins/Array/prototype/flat/non-object-ctor-throws.js
  8. 29 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flat/not-a-constructor.js
  9. 2 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flat/null-undefined-input-throws.js
  10. 5 4
      Jint.Tests.Test262/test/built-ins/Array/prototype/flat/prop-desc.js
  11. 36 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flat/proxy-access-count.js
  12. 2 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flat/symbol-object-create-null-depth-throws.js
  13. 48 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flat/target-array-non-extensible.js
  14. 48 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flat/target-array-with-non-configurable-property.js
  15. 50 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flat/target-array-with-non-writable-property.js
  16. 68 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/array-like-objects-nested.js
  17. 60 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/array-like-objects-poisoned-length.js
  18. 50 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/array-like-objects-typedarrays.js
  19. 68 18
      Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/array-like-objects.js
  20. 19 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/call-with-boolean.js
  21. 5 3
      Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/length.js
  22. 5 3
      Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/name.js
  23. 41 3
      Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/non-callable-argument-throws.js
  24. 33 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/not-a-constructor.js
  25. 27 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/prop-desc.js
  26. 38 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/proxy-access-count.js
  27. 48 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/target-array-non-extensible.js
  28. 52 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/target-array-with-non-configurable-property.js
  29. 54 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/target-array-with-non-writable-property.js
  30. 74 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/this-value-ctor-non-object.js
  31. 129 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species-bad-throws.js
  32. 58 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species-custom-ctor-poisoned-throws.js
  33. 94 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species-custom-ctor.js
  34. 141 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species.js
  35. 25 0
      Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/this-value-null-undefined-throws.js
  36. 26 13
      Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/thisArg-argument.js
  37. 10 0
      Jint/Engine.cs
  38. 126 2
      Jint/Native/Array/ArrayPrototype.cs
  39. 1 1
      Jint/Native/Function/FunctionInstance.cs
  40. 1 4
      Jint/Runtime/Interop/ClrFunctionInstance.cs
  41. 1 9
      Jint/Runtime/Interpreter/Expressions/JintCallExpression.cs
  42. 1 0
      Jint/Runtime/Interpreter/Expressions/JintExpression.cs
  43. 1 1
      Jint/Runtime/Interpreter/Expressions/JintIdentifierExpression.cs
  44. 25 0
      Jint/Runtime/Interpreter/Expressions/JintMetaPropertyExpression.cs
  45. 1 1
      Jint/Runtime/Interpreter/Expressions/JintSuperExpression.cs
  46. 25 0
      Jint/Runtime/TypeConverter.cs
  47. 2 2
      README.md

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

@@ -44,6 +44,7 @@ namespace Jint.Tests.Test262
                 "sta.js",
                 "assert.js",
                 "arrayContains.js",
+                "isConstructor.js",
                 "propertyHelper.js",
                 "compareArray.js",
                 "decimalToHexString.js",
@@ -231,10 +232,6 @@ namespace Jint.Tests.Test262
                                 skip = true;
                                 reason = "private/public class fields not implemented in esprima";
                                 break;
-                            case "new.target":
-                                skip = true;
-                                reason = "MetaProperty not implemented";
-                                break;
                             case "super":
                                 skip = true;
                                 reason = "super not implemented";
@@ -263,6 +260,10 @@ namespace Jint.Tests.Test262
                                 skip = true;
                                 reason = "TypedArray not implemented";
                                 break;
+                            case "Int32Array":
+                                skip = true;
+                                reason = "Int32Array not implemented";
+                                break;
                         }
                     }
                 }

+ 4 - 4
Jint.Tests.Test262/test/built-ins/Array/prototype/flat/array-like-objects.js

@@ -16,16 +16,16 @@ var a = getArgumentsObject([1], [2]);
 var actual = [].flat.call(a);
 assert.compareArray(actual, [1, 2], 'arguments objects');
 
-var a = {
+a = {
   length: 1,
   0: [1],
 };
-var actual = [].flat.call(a);
+actual = [].flat.call(a);
 assert.compareArray(actual, [1], 'array-like objects');
 
-var a = {
+a = {
   length: undefined,
   0: [1],
 };
-var actual = [].flat.call(a);
+actual = [].flat.call(a);
 assert.compareArray(actual, [], 'array-like objects; undefined length');

+ 11 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flat/call-with-boolean.js

@@ -0,0 +1,11 @@
+// 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.flat
+description: Array.prototype.flat applied to boolean primitive
+includes: [compareArray.js]
+---*/
+
+assert.compareArray(Array.prototype.flat.call(true), [], 'Array.prototype.flat.call(true) must return []');
+assert.compareArray(Array.prototype.flat.call(false), [], 'Array.prototype.flat.call(false) must return []');

+ 5 - 3
Jint.Tests.Test262/test/built-ins/Array/prototype/flat/length.js

@@ -14,6 +14,8 @@ assert.sameValue(
   'The value of `Array.prototype.flat.length` is `0`'
 );
 
-verifyNotEnumerable(Array.prototype.flat, 'length');
-verifyNotWritable(Array.prototype.flat, 'length');
-verifyConfigurable(Array.prototype.flat, 'length');
+verifyProperty(Array.prototype.flat, 'length', {
+  enumerable: false,
+  writable: false,
+  configurable: true,
+});

+ 5 - 3
Jint.Tests.Test262/test/built-ins/Array/prototype/flat/name.js

@@ -15,6 +15,8 @@ assert.sameValue(
   'The value of `Array.prototype.flat.name` is `"flat"`'
 );
 
-verifyNotEnumerable(Array.prototype.flat, 'name');
-verifyNotWritable(Array.prototype.flat, 'name');
-verifyConfigurable(Array.prototype.flat, 'name');
+verifyProperty(Array.prototype.flat, 'name', {
+  enumerable: false,
+  writable: false,
+  configurable: true,
+});

+ 11 - 11
Jint.Tests.Test262/test/built-ins/Array/prototype/flat/non-numeric-depth-should-not-throw.js

@@ -17,27 +17,27 @@ var actual = a.flat(depthNum);
 assert(compareArray(actual, expected), 'non integral string depthNum');
 
 // object type depthNum is converted to 0
-var depthNum = {};
-var actual = a.flat(depthNum);
+depthNum = {};
+actual = a.flat(depthNum);
 assert(compareArray(actual, expected), 'object type depthNum');
 
 // negative infinity depthNum is converted to 0
-var depthNum = Number.NEGATIVE_INFINITY;
-var actual = a.flat(depthNum);
+depthNum = Number.NEGATIVE_INFINITY;
+actual = a.flat(depthNum);
 assert(compareArray(actual, expected), 'negative infinity depthNum');
 
 // positive zero depthNum is converted to 0
-var depthNum = +0;
-var actual = a.flat(depthNum);
+depthNum = +0;
+actual = a.flat(depthNum);
 assert(compareArray(actual, expected), 'positive zero depthNum');
 
 // negative zero depthNum is converted to 0
-var depthNum = -0;
-var actual = a.flat(depthNum);
+depthNum = -0;
+actual = a.flat(depthNum);
 assert(compareArray(actual, expected), 'negative zero depthNum');
 
 // integral string depthNum is converted to an integer
-var depthNum = '1';
-var actual = a.flat(depthNum);
-var expected = [1, 2]
+depthNum = '1';
+actual = a.flat(depthNum);
+expected = [1, 2]
 assert(compareArray(actual, expected), 'integral string depthNum');

+ 5 - 3
Jint.Tests.Test262/test/built-ins/Array/prototype/flat/non-object-ctor-throws.js

@@ -8,25 +8,27 @@ description: >
 features: [Array.prototype.flat]
 ---*/
 
+assert.sameValue(typeof Array.prototype.flat, 'function');
+
 var a = [];
 a.constructor = null;
 assert.throws(TypeError, function() {
   a.flat();
 }, 'null value');
 
-var a = [];
+a = [];
 a.constructor = 1;
 assert.throws(TypeError, function() {
   a.flat();
 }, 'number value');
 
-var a = [];
+a = [];
 a.constructor = 'string';
 assert.throws(TypeError, function() {
   a.flat();
 }, 'string value');
 
-var a = [];
+a = [];
 a.constructor = true;
 assert.throws(TypeError, function() {
   a.flat();

+ 29 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flat/not-a-constructor.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-ecmascript-standard-built-in-objects
+description: >
+  Array.prototype.flat does not implement [[Construct]], is not new-able
+info: |
+  ECMAScript Function Objects
+
+  Built-in function objects that are not identified as constructors do not
+  implement the [[Construct]] internal method unless otherwise specified in
+  the description of a particular function.
+
+  sec-evaluatenew
+
+  ...
+  7. If IsConstructor(constructor) is false, throw a TypeError exception.
+  ...
+includes: [isConstructor.js]
+features: [Reflect.construct, arrow-function]
+---*/
+
+assert.sameValue(isConstructor(Array.prototype.flat), false, 'isConstructor(Array.prototype.flat) must return false');
+
+assert.throws(TypeError, () => {
+  new Array.prototype.flat();
+}, '`new Array.prototype.flat()` throws TypeError');
+

+ 2 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flat/null-undefined-input-throws.js

@@ -7,6 +7,8 @@ description: >
 features: [Array.prototype.flat]
 ---*/
 
+assert.sameValue(typeof Array.prototype.flat, 'function');
+
 assert.throws(TypeError, function() {
   [].flat.call(null);
 }, 'null value');

+ 5 - 4
Jint.Tests.Test262/test/built-ins/Array/prototype/flat/prop-desc.js

@@ -2,7 +2,6 @@
 // This code is governed by the BSD license found in the LICENSE file.
 /*---
 esid: sec-array.prototype.flat
-es6id: 22.1.3
 description: Property type and descriptor.
 info: >
   17 ECMAScript Standard Built-in Objects
@@ -16,6 +15,8 @@ assert.sameValue(
   '`typeof Array.prototype.flat` is `function`'
 );
 
-verifyNotEnumerable(Array.prototype, 'flat');
-verifyWritable(Array.prototype, 'flat');
-verifyConfigurable(Array.prototype, 'flat');
+verifyProperty(Array.prototype, 'flat', {
+  enumerable: false,
+  writable: true,
+  configurable: true,
+});

+ 36 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flat/proxy-access-count.js

@@ -0,0 +1,36 @@
+// Copyright (C) 2018 Richard Lawrence. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-array.prototype.flat
+description: >
+  properties are accessed correct number of times by .flat
+info: |
+  Array.prototype.flat( [ depth ] )
+
+  ...
+  6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, depthNum).
+
+  FlattenIntoArray (target, source, sourceLen, start, depth [ , mapperFunction, thisArg ])
+
+  3. Repeat, while sourceIndex < sourceLen
+    a. Let P be ! ToString(sourceIndex).
+    b. Let exists be ? HasProperty(source, P).
+    c. If exists is true, then
+      i. Let element be ? Get(source, P).
+features: [Array.prototype.flat]
+includes: [compareArray.js]
+---*/
+
+const getCalls = [], hasCalls = [];
+const handler = {
+  get : function (t, p, r) { getCalls.push(p); return Reflect.get(t, p, r); },
+  has : function (t, p, r) { hasCalls.push(p); return Reflect.has(t, p, r); }
+}
+
+const tier2 = new Proxy([4, 3], handler);
+const tier1 = new Proxy([2, [3, [4, 2], 2], 5, tier2, 6], handler);
+
+Array.prototype.flat.call(tier1, 3);
+
+assert.compareArray(getCalls, ["length", "constructor", "0", "1", "2", "3", "length", "0", "1", "4"], 'getProperty by .flat should occur exactly once per property and once for length and constructor');
+assert.compareArray(hasCalls, ["0", "1", "2", "3", "0", "1", "4"], 'hasProperty by .flat should occur exactly once per property');

+ 2 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flat/symbol-object-create-null-depth-throws.js

@@ -7,6 +7,8 @@ description: >
 features: [Array.prototype.flat]
 ---*/
 
+assert.sameValue(typeof Array.prototype.flat, 'function');
+
 assert.throws(TypeError, function() {
   [].flat(Symbol());
 }, 'symbol value');

+ 48 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flat/target-array-non-extensible.js

@@ -0,0 +1,48 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-array.prototype.flat
+description: >
+  TypeError is thrown if CreateDataProperty fails.
+  (result object is non-extensible, source array is not flattened)
+info: |
+  Array.prototype.flat ( [ depth ] )
+
+  [...]
+  6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, depthNum).
+
+  FlattenIntoArray ( target, source, sourceLen, start, depth [ , mapperFunction, thisArg ] )
+
+  [...]
+  9. Repeat, while sourceIndex < sourceLen
+    [...]
+    c. If exists is true, then
+      [...]
+      v. If shouldFlatten is true, then
+        [...]
+      vi. Else,
+        [...]
+        2. Perform ? CreateDataPropertyOrThrow(target, ! ToString(targetIndex), element).
+      [...]
+
+  CreateDataPropertyOrThrow ( O, P, V )
+
+  [...]
+  3. Let success be ? CreateDataProperty(O, P, V).
+  4. If success is false, throw a TypeError exception.
+features: [Symbol.species]
+---*/
+
+var A = function(_length) {
+  this.length = 0;
+  Object.preventExtensions(this);
+};
+
+var arr = [1];
+arr.constructor = {};
+arr.constructor[Symbol.species] = A;
+
+assert.throws(TypeError, function() {
+  arr.flat(1);
+});

+ 48 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flat/target-array-with-non-configurable-property.js

@@ -0,0 +1,48 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-array.prototype.flat
+description: >
+  TypeError is thrown if CreateDataProperty fails.
+  (result object's "0" is non-configurable, source array gets flattened)
+info: |
+  Array.prototype.flat ( [ depth ] )
+
+  [...]
+  6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, depthNum).
+
+  FlattenIntoArray ( target, source, sourceLen, start, depth [ , mapperFunction, thisArg ] )
+
+  [...]
+  9. Repeat, while sourceIndex < sourceLen
+    [...]
+    c. If exists is true, then
+      [...]
+      v. If shouldFlatten is true, then
+        [...]
+        2. Set targetIndex to ? FlattenIntoArray(target, element, elementLen, targetIndex, depth - 1).
+      [...]
+
+  CreateDataPropertyOrThrow ( O, P, V )
+
+  [...]
+  3. Let success be ? CreateDataProperty(O, P, V).
+  4. If success is false, throw a TypeError exception.
+features: [Symbol.species]
+---*/
+
+var A = function(_length) {
+  Object.defineProperty(this, "0", {
+    set: function(_value) {},
+    configurable: false,
+  });
+};
+
+var arr = [[1]];
+arr.constructor = {};
+arr.constructor[Symbol.species] = A;
+
+assert.throws(TypeError, function() {
+  arr.flat(1);
+});

+ 50 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flat/target-array-with-non-writable-property.js

@@ -0,0 +1,50 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-array.prototype.flat
+description: >
+  Non-writable properties are overwritten by CreateDataProperty.
+  (result object's "0" is non-writable, source array gets flattened)
+info: |
+  Array.prototype.flat ( [ depth ] )
+
+  [...]
+  6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, depthNum).
+
+  FlattenIntoArray ( target, source, sourceLen, start, depth [ , mapperFunction, thisArg ] )
+
+  [...]
+  9. Repeat, while sourceIndex < sourceLen
+    [...]
+    c. If exists is true, then
+      [...]
+      v. If shouldFlatten is true, then
+        [...]
+        2. Set targetIndex to ? FlattenIntoArray(target, element, elementLen, targetIndex, depth - 1).
+      [...]
+features: [Symbol.species]
+includes: [propertyHelper.js]
+---*/
+
+var A = function(_length) {
+  Object.defineProperty(this, "0", {
+    value: 1,
+    writable: false,
+    enumerable: false,
+    configurable: true,
+  });
+};
+
+var arr = [[2]];
+arr.constructor = {};
+arr.constructor[Symbol.species] = A;
+
+var res = arr.flat(1);
+
+verifyProperty(res, "0", {
+  value: 2,
+  writable: true,
+  enumerable: true,
+  configurable: true,
+});

+ 68 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/array-like-objects-nested.js

@@ -0,0 +1,68 @@
+// Copyright (C) 2018 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-array.prototype.flatMap
+description: >
+  Does not flatten array-like objects nested into the main array
+info: |
+  FlattenIntoArray(target, source, sourceLen, start, depth [ , mapperFunction, thisArg ])
+
+  1. Let targetIndex be start.
+  2. Let sourceIndex be 0.
+  3. Repeat, while sourceIndex < sourceLen
+    a. Let P be ! ToString(sourceIndex).
+    b. Let exists be ? HasProperty(source, P).
+    c. If exists is true, then
+      i. Let element be ? Get(source, P).
+      ii. If mapperFunction is present, then
+        1. Assert: thisArg is present.
+        2. Set element to ? Call(mapperFunction, thisArg , « element, sourceIndex, source »).
+      iii. Let shouldFlatten be false.
+      iv. If depth > 0, then
+        1. Set shouldFlatten to ? IsArray(element).
+      v. If shouldFlatten is true, then
+        1. Let elementLen be ? ToLength(? Get(element, "length")).
+        2. Set targetIndex to ? FlattenIntoArray(target, element, elementLen, targetIndex, depth - 1).
+      vi. Else,
+        1. If targetIndex ≥ 253-1, throw a TypeError exception.
+        2. Perform ? CreateDataPropertyOrThrow(target, ! ToString(targetIndex), element).
+        3. Increase targetIndex by 1.
+includes: [compareArray.js]
+features: [Array.prototype.flatMap, Int32Array]
+---*/
+
+function fn(e) {
+  return e;
+}
+
+var obj1 = {
+  length: 1,
+  0: 'a',
+  toString() { return 'obj1'; }
+};
+
+var obj2 = new Int32Array(2);
+
+var obj3 = {
+  get length() { throw "should not even consider the length property" },
+  toString() { return 'obj3'; }
+};
+
+var arr = [obj1, obj2, obj3];
+var actual = arr.flatMap(fn);
+assert.compareArray(actual, arr, 'returns a similar array');
+assert.notSameValue(actual, arr, 'not the same array');
+
+var arrLike = {
+  length: 4,
+  0: obj1,
+  1: obj2,
+  2: obj3,
+  get 3() { return arrLike },
+  toString() { return 'obj4'; }
+};
+
+actual = [].flatMap.call(arrLike, fn);
+assert.compareArray(actual, [obj1, obj2, obj3, arrLike], 'returns a similar array');
+assert.notSameValue(actual, arrLike, 'not the same object');
+assert.sameValue(Object.getPrototypeOf(actual), Array.prototype);

+ 60 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/array-like-objects-poisoned-length.js

@@ -0,0 +1,60 @@
+// Copyright (C) 2018 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-array.prototype.flatMap
+description: >
+  Observe abrupt completion in poisoned lengths of array-like objects
+info: |
+  Array.prototype.flatMap ( mapperFunction [ , thisArg ] )
+
+  1. Let O be ? ToObject(this value).
+  2. Let sourceLen be ? ToLength(? Get(O, "length")).
+features: [Array.prototype.flatMap, Symbol.toPrimitive]
+---*/
+
+assert.sameValue(typeof Array.prototype.flatMap, 'function');
+
+function fn(e) {
+  return e;
+}
+
+var arr = {
+  length: Symbol(),
+};
+assert.throws(TypeError, function() {
+  [].flatMap.call(arr, fn);
+}, 'length is a symbol');
+
+arr = {
+  get length() { throw new Test262Error() }
+};
+assert.throws(Test262Error, function() {
+  [].flatMap.call(arr, fn);
+}, 'custom get error');
+
+arr = {
+  length: {
+    valueOf() { throw new Test262Error() }
+  }
+};
+assert.throws(Test262Error, function() {
+  [].flatMap.call(arr, fn);
+}, 'custom valueOf error');
+
+arr = {
+  length: {
+    toString() { throw new Test262Error() }
+  }
+};
+assert.throws(Test262Error, function() {
+  [].flatMap.call(arr, fn);
+}, 'custom toString error');
+
+arr = {
+  length: {
+    [Symbol.toPrimitive]() { throw new Test262Error() }
+  }
+};
+assert.throws(Test262Error, function() {
+  [].flatMap.call(arr, fn);
+}, 'custom Symbol.toPrimitive error');

+ 50 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/array-like-objects-typedarrays.js

@@ -0,0 +1,50 @@
+// Copyright (C) 2018 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-array.prototype.flatMap
+description: >
+  array-like objects can be flattened (typedArrays)
+info: |
+  Array.prototype.flatMap ( mapperFunction [ , thisArg ] )
+
+  1. Let O be ? ToObject(this value).
+  2. Let sourceLen be ? ToLength(? Get(O, "length")).
+  ...
+  5. Let A be ? ArraySpeciesCreate(O, 0).
+  ...
+
+  ArraySpeciesCreate ( originalArray, length )
+
+  3. Let isArray be ? IsArray(originalArray).
+  4. If isArray is false, return ? ArrayCreate(length).
+  5. Let C be ? Get(originalArray, "constructor").
+includes: [compareArray.js]
+features: [Array.prototype.flatMap, Int32Array]
+---*/
+
+function same(e) {
+  return e;
+}
+
+var ta;
+var actual;
+
+ta = new Int32Array([1, 0, 42]);
+
+Object.defineProperty(ta, 'constructor', {
+  get() { throw "it should not object the typedarray ctor"; }
+});
+actual = [].flatMap.call(ta, same);
+assert.compareArray(actual, [1, 0, 42], 'compare returned array');
+assert.sameValue(Object.getPrototypeOf(actual), Array.prototype, 'returned object is an array #1');
+assert.sameValue(actual instanceof Int32Array, false, 'returned object is not an instance of Int32Array #1');
+
+ta = new Int32Array(0);
+
+Object.defineProperty(ta, 'constructor', {
+  get() { throw "it should not object the typedarray ctor"; }
+});
+actual = [].flatMap.call(ta, same);
+assert.compareArray(actual, [], 'compare returned empty array');
+assert.sameValue(Object.getPrototypeOf(actual), Array.prototype, 'returned object is an array #2');
+assert.sameValue(actual instanceof Int32Array, false, 'returned object is not an instance of Int32Array #2');

+ 68 - 18
Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/array-like-objects.js

@@ -3,33 +3,83 @@
 /*---
 esid: sec-array.prototype.flatMap
 description: >
-    array-like objects can be flattened
+  array-like objects can be flattened
+info: |
+  Array.prototype.flatMap ( mapperFunction [ , thisArg ] )
+
+  1. Let O be ? ToObject(this value).
+  2. Let sourceLen be ? ToLength(? Get(O, "length")).
+  ...
+  5. Let A be ? ArraySpeciesCreate(O, 0).
+  ...
+
+  ArraySpeciesCreate ( originalArray, length )
+
+  3. Let isArray be ? IsArray(originalArray).
+  4. If isArray is false, return ? ArrayCreate(length).
+
+  FlattenIntoArray(target, source, sourceLen, start, depth [ , mapperFunction, thisArg ])
+
+  1. Let targetIndex be start.
+  2. Let sourceIndex be 0.
+  3. Repeat, while sourceIndex < sourceLen
+    a. Let P be ! ToString(sourceIndex).
+    b. Let exists be ? HasProperty(source, P).
+    c. If exists is true, then
+      ...
+    ** Skip if property does not exist **
 includes: [compareArray.js]
 features: [Array.prototype.flatMap]
 ---*/
 
-function getArgumentsObject() {
-  return arguments;
-}
-
-function double(e) {
-  return [e * 2];
+function fn(e) {
+  return [39, e * 2]; // returns an array to observe it being flattened after
 }
 
-var a = getArgumentsObject(1, 2);
-var actual = [].flatMap.call(a, double);
-assert.compareArray(actual, [2, 4], 'arguments objects');
+var a;
+var actual;
 
-var a = {
-  length: 1,
+a = {
+  length: 3,
   0: 1,
+  // property 1 will be fully skipped
+  2: 21,
+  get 3() { throw 'it should not get this property'; }
 };
-var actual = [].flatMap.call(a, double);
-assert.compareArray(actual, [2], 'array-like objects');
+actual = [].flatMap.call(a, fn);
+assert.compareArray(actual, [39, 2, 39, 42], 'array-like flattened object, number length');
+assert.sameValue(Object.getPrototypeOf(actual), Array.prototype, 'returned object is an array #1');
 
-var a = {
-  length: void 0,
-  0: 1,
+a = {
+  length: undefined,
+  get 0() { throw 'it should not get this property'; },
 };
-var actual = [].flatMap.call(a, double);
+actual = [].flatMap.call(a, fn);
 assert.compareArray(actual, [], 'array-like objects; undefined length');
+assert.sameValue(Object.getPrototypeOf(actual), Array.prototype, 'returned object is an array #2');
+
+var called = false;
+a = {
+  get length() {
+    if (!called) {
+      called = true;
+      return 2;
+    } else {
+      throw 'is should get the length only once';
+    }
+  },
+  0: 21,
+  1: 19.5,
+  get 2() { throw 'it should not get this property'; },
+};
+actual = [].flatMap.call(a, fn);
+assert.compareArray(actual, [39, 42, 39, 39], 'array-like flattened objects; custom get length');
+assert.sameValue(Object.getPrototypeOf(actual), Array.prototype, 'returned object is an array #3');
+
+a = {
+  length: 10001,
+  [10000]: 7,
+};
+actual = [].flatMap.call(a, fn);
+assert.compareArray(actual, [39, 14], 'array-like flattened object, long length simulating shallow array');
+assert.sameValue(Object.getPrototypeOf(actual), Array.prototype, 'returned object is an array #4');

+ 19 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/call-with-boolean.js

@@ -0,0 +1,19 @@
+// 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.flatMap
+description: Array.prototype.flatMap applied to boolean primitive
+includes: [compareArray.js]
+---*/
+
+assert.compareArray(
+  Array.prototype.flatMap.call(true, () => {}),
+  [],
+  'Array.prototype.flatMap.call(true, () => {}) must return []'
+);
+assert.compareArray(
+  Array.prototype.flatMap.call(false, () => {}),
+  [],
+  'Array.prototype.flatMap.call(false, () => {}) must return []'
+);

+ 5 - 3
Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/length.js

@@ -14,6 +14,8 @@ assert.sameValue(
   'The value of `Array.prototype.flatmap.length` is `1`'
 );
 
-verifyNotEnumerable(Array.prototype.flatMap, 'length');
-verifyNotWritable(Array.prototype.flatMap, 'length');
-verifyConfigurable(Array.prototype.flatMap, 'length');
+verifyProperty(Array.prototype.flatMap, 'length', {
+  enumerable: false,
+  writable: false,
+  configurable: true,
+});

+ 5 - 3
Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/name.js

@@ -14,6 +14,8 @@ assert.sameValue(
   'The value of `Array.prototype.flatMap.name` is `"flatMap"`'
 );
 
-verifyNotEnumerable(Array.prototype.flatMap, 'name');
-verifyNotWritable(Array.prototype.flatMap, 'name');
-verifyConfigurable(Array.prototype.flatMap, 'name');
+verifyProperty(Array.prototype.flatMap, 'name', {
+  enumerable: false,
+  writable: false,
+  configurable: true,
+});

+ 41 - 3
Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/non-callable-argument-throws.js

@@ -3,10 +3,48 @@
 /*---
 esid: sec-array.prototype.flatMap
 description: >
-    non callable argument should throw TypeError Exception
-features: [Array.prototype.flatMap]
+  non callable argument should throw TypeError Exception
+info: |
+  Array.prototype.flatMap ( mapperFunction [ , thisArg ] )
+
+  1. Let O be ? ToObject(this value).
+  2. Let sourceLen be ? ToLength(? Get(O, "length")).
+  3. If IsCallable(mapperFunction) is false, throw a TypeError exception.
+  ...
+features: [Array.prototype.flatMap, Symbol]
 ---*/
 
+assert.sameValue(typeof Array.prototype.flatMap, "function");
+
 assert.throws(TypeError, function() {
   [].flatMap({});
-}, 'non callable argument');
+}, 'non callable argument, object');
+
+assert.throws(TypeError, function() {
+  [].flatMap(0);
+}, 'non callable argument, number');
+
+assert.throws(TypeError, function() {
+  [].flatMap();
+}, 'non callable argument, implict undefined');
+
+assert.throws(TypeError, function() {
+  [].flatMap(undefined);
+}, 'non callable argument, undefined');
+
+assert.throws(TypeError, function() {
+  [].flatMap(null);
+}, 'non callable argument, null');
+
+assert.throws(TypeError, function() {
+  [].flatMap(false);
+}, 'non callable argument, boolean');
+
+assert.throws(TypeError, function() {
+  [].flatMap('');
+}, 'non callable argument, string');
+
+var s = Symbol();
+assert.throws(TypeError, function() {
+  [].flatMap(s);
+}, 'non callable argument, symbol');

+ 33 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/not-a-constructor.js

@@ -0,0 +1,33 @@
+// Copyright (C) 2020 Rick Waldron. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-ecmascript-standard-built-in-objects
+description: >
+  Array.prototype.flatMap does not implement [[Construct]], is not new-able
+info: |
+  ECMAScript Function Objects
+
+  Built-in function objects that are not identified as constructors do not
+  implement the [[Construct]] internal method unless otherwise specified in
+  the description of a particular function.
+
+  sec-evaluatenew
+
+  ...
+  7. If IsConstructor(constructor) is false, throw a TypeError exception.
+  ...
+includes: [isConstructor.js]
+features: [Reflect.construct, Array.prototype.flatMap, arrow-function]
+---*/
+
+assert.sameValue(
+  isConstructor(Array.prototype.flatMap),
+  false,
+  'isConstructor(Array.prototype.flatMap) must return false'
+);
+
+assert.throws(TypeError, () => {
+  new Array.prototype.flatMap(() => {});
+}, '`new Array.prototype.flatMap(() => {})` throws TypeError');
+

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

@@ -0,0 +1,27 @@
+// Copyright (C) 2018 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-array.prototype.flatMap
+description: Property type and descriptor.
+info: >
+  17 ECMAScript Standard Built-in Objects
+
+  Every other data property described in clauses 18 through 26 and in Annex B.2
+  has the attributes { [[Writable]]: true, [[Enumerable]]: false,
+  [[Configurable]]: true } unless otherwise specified.
+includes: [propertyHelper.js]
+features: [Array.prototype.flatMap]
+---*/
+
+assert.sameValue(
+  typeof Array.prototype.flatMap,
+  'function',
+  '`typeof Array.prototype.flatMap` is `function`'
+);
+
+verifyProperty(Array.prototype, 'flatMap', {
+  enumerable: false,
+  writable: true,
+  configurable: true,
+});

+ 38 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/proxy-access-count.js

@@ -0,0 +1,38 @@
+// Copyright (C) 2018 Richard Lawrence. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-array.prototype.flatMap
+description: >
+  properties are accessed correct number of times by .flatMap
+info: |
+  Array.prototype.flatMap ( mapperFunction [ , thisArg ] )
+
+  ...
+  6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T).
+
+  FlattenIntoArray (target, source, sourceLen, start, depth [ , mapperFunction, thisArg ])
+
+  3. Repeat, while sourceIndex < sourceLen
+    a. Let P be ! ToString(sourceIndex).
+    b. Let exists be ? HasProperty(source, P).
+    c. If exists is true, then
+      i. Let element be ? Get(source, P).
+features: [Array.prototype.flatMap]
+includes: [compareArray.js]
+---*/
+
+assert.sameValue(typeof Array.prototype.flatMap, 'function');
+
+const getCalls = [], hasCalls = [];
+const handler = {
+  get : function (t, p, r) { getCalls.push(p); return Reflect.get(t, p, r); },
+  has : function (t, p, r) { hasCalls.push(p); return Reflect.has(t, p, r); }
+}
+
+const tier2 = new Proxy([4, 3], handler);
+const tier1 = new Proxy([2, [3, 4, 2, 2], 5, tier2, 6], handler);
+
+Array.prototype.flatMap.call(tier1, function(a){ return a; });
+
+assert.compareArray(getCalls, ["length", "constructor", "0", "1", "2", "3", "length", "0", "1", "4"], 'getProperty by .flatMap should occur exactly once per property and once for length and constructor');
+assert.compareArray(hasCalls, ["0", "1", "2", "3", "0", "1", "4"], 'hasProperty by .flatMap should occur exactly once per property');

+ 48 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/target-array-non-extensible.js

@@ -0,0 +1,48 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-array.prototype.flatmap
+description: >
+  TypeError is thrown if CreateDataProperty fails.
+  (result object is non-extensible, source array gets flattened)
+info: |
+  Array.prototype.flatMap ( mapperFunction [ , thisArg ] )
+
+  [...]
+  6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, depthNum).
+
+  FlattenIntoArray ( target, source, sourceLen, start, depth [ , mapperFunction, thisArg ] )
+
+  [...]
+  9. Repeat, while sourceIndex < sourceLen
+    [...]
+    c. If exists is true, then
+      [...]
+      v. If shouldFlatten is true, then
+        [...]
+        2. Set targetIndex to ? FlattenIntoArray(target, element, elementLen, targetIndex, depth - 1).
+      [...]
+
+  CreateDataPropertyOrThrow ( O, P, V )
+
+  [...]
+  3. Let success be ? CreateDataProperty(O, P, V).
+  4. If success is false, throw a TypeError exception.
+features: [Symbol.species]
+---*/
+
+var A = function(_length) {
+  this.length = 0;
+  Object.preventExtensions(this);
+};
+
+var arr = [[1]];
+arr.constructor = {};
+arr.constructor[Symbol.species] = A;
+
+assert.throws(TypeError, function() {
+  arr.flatMap(function(item) {
+    return item;
+  });
+});

+ 52 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/target-array-with-non-configurable-property.js

@@ -0,0 +1,52 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-array.prototype.flatmap
+description: >
+  TypeError is thrown if CreateDataProperty fails.
+  (result object's "0" is non-configurable, source array is not flattened)
+info: |
+  Array.prototype.flatMap ( mapperFunction [ , thisArg ] )
+
+  [...]
+  6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, depthNum).
+
+  FlattenIntoArray ( target, source, sourceLen, start, depth [ , mapperFunction, thisArg ] )
+
+  [...]
+  9. Repeat, while sourceIndex < sourceLen
+    [...]
+    c. If exists is true, then
+      [...]
+      v. If shouldFlatten is true, then
+        [...]
+      vi. Else,
+        [...]
+        2. Perform ? CreateDataPropertyOrThrow(target, ! ToString(targetIndex), element).
+      [...]
+
+  CreateDataPropertyOrThrow ( O, P, V )
+
+  [...]
+  3. Let success be ? CreateDataProperty(O, P, V).
+  4. If success is false, throw a TypeError exception.
+features: [Symbol.species]
+---*/
+
+var A = function(_length) {
+  Object.defineProperty(this, "0", {
+    writable: true,
+    configurable: false,
+  });
+};
+
+var arr = [1];
+arr.constructor = {};
+arr.constructor[Symbol.species] = A;
+
+assert.throws(TypeError, function() {
+  arr.flatMap(function(item) {
+    return item;
+  });
+});

+ 54 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/target-array-with-non-writable-property.js

@@ -0,0 +1,54 @@
+// Copyright (C) 2020 Alexey Shvayka. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-array.prototype.flatmap
+description: >
+  Non-writable properties are overwritten by CreateDataProperty.
+  (result object's "0" is non-writable, source array is not flattened)
+info: |
+  Array.prototype.flatMap ( mapperFunction [ , thisArg ] )
+
+  [...]
+  6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, depthNum).
+
+  FlattenIntoArray ( target, source, sourceLen, start, depth [ , mapperFunction, thisArg ] )
+
+  [...]
+  9. Repeat, while sourceIndex < sourceLen
+    [...]
+    c. If exists is true, then
+      [...]
+      v. If shouldFlatten is true, then
+        [...]
+      vi. Else,
+        [...]
+        2. Perform ? CreateDataPropertyOrThrow(target, ! ToString(targetIndex), element).
+      [...]
+features: [Symbol.species]
+includes: [propertyHelper.js]
+---*/
+
+var A = function(_length) {
+  Object.defineProperty(this, "0", {
+    value: 1,
+    writable: false,
+    enumerable: false,
+    configurable: true,
+  });
+};
+
+var arr = [2];
+arr.constructor = {};
+arr.constructor[Symbol.species] = A;
+
+var res = arr.flatMap(function(item) {
+  return item;
+});
+
+verifyProperty(res, "0", {
+  value: 2,
+  writable: true,
+  enumerable: true,
+  configurable: true,
+});

+ 74 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/this-value-ctor-non-object.js

@@ -0,0 +1,74 @@
+// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-array.prototype.flatMap
+description: >
+  Assert behavior if this value has a custom non-object constructor property
+info: |
+  Array.prototype.flatMap ( mapperFunction [ , thisArg ] )
+
+  1. Let O be ? ToObject(this value).
+  2. Let sourceLen be ? ToLength(? Get(O, "length")).
+  ...
+  5. Let A be ? ArraySpeciesCreate(O, 0).
+  ...
+
+  ArraySpeciesCreate ( originalArray, length )
+
+  3. Let isArray be ? IsArray(originalArray).
+  4. If isArray is false, return ? ArrayCreate(length).
+  5. Let C be ? Get(originalArray, "constructor").
+  6. If IsConstructor(C) is true, then
+    a. Let thisRealm be the current Realm Record.
+    b. Let realmC be ? GetFunctionRealm(C).
+    c. If thisRealm and realmC are not the same Realm Record, then
+      i. If SameValue(C, realmC.[[Intrinsics]].[[%Array%]]) is true, set C to undefined.
+  7. If Type(C) is Object, then
+    a. Set C to ? Get(C, @@species).
+    b. If C is null, set C to undefined.
+  8. If C is undefined, return ? ArrayCreate(length).
+  9. If IsConstructor(C) is false, throw a TypeError exception.
+features: [Array.prototype.flatMap, Symbol]
+includes: [compareArray.js]
+---*/
+
+assert.sameValue(typeof Array.prototype.flatMap, 'function');
+
+var a = [];
+var mapperFn = function() {};
+
+a.constructor = null;
+assert.throws(TypeError, function() {
+  a.flatMap(mapperFn);
+}, 'null value');
+
+a = [];
+a.constructor = 1;
+assert.throws(TypeError, function() {
+  a.flatMap(mapperFn);
+}, 'number value');
+
+a = [];
+a.constructor = 'string';
+assert.throws(TypeError, function() {
+  a.flatMap(mapperFn);
+}, 'string value');
+
+a = [];
+a.constructor = true;
+assert.throws(TypeError, function() {
+  a.flatMap(mapperFn);
+}, 'boolean value');
+
+a = [];
+a.constructor = Symbol();
+assert.throws(TypeError, function() {
+  a.flatMap(mapperFn);
+}, 'symbol value');
+
+a = [];
+a.constructor = undefined;
+var actual = a.flatMap(mapperFn);
+assert.compareArray(actual, [], 'undefined value does not throw');
+assert.sameValue(Object.getPrototypeOf(actual), Array.prototype);
+assert.notSameValue(actual, a, 'returns a new array');

+ 129 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species-bad-throws.js

@@ -0,0 +1,129 @@
+// Copyright (C) 2018 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-array.prototype.flatMap
+description: >
+  Assert behavior if this value has a custom object constructor property species
+info: |
+  Array.prototype.flatMap ( mapperFunction [ , thisArg ] )
+
+  1. Let O be ? ToObject(this value).
+  2. Let sourceLen be ? ToLength(? Get(O, "length")).
+  ...
+  5. Let A be ? ArraySpeciesCreate(O, 0).
+  ...
+
+  ArraySpeciesCreate ( originalArray, length )
+
+  3. Let isArray be ? IsArray(originalArray).
+  4. If isArray is false, return ? ArrayCreate(length).
+  5. Let C be ? Get(originalArray, "constructor").
+  6. If IsConstructor(C) is true, then
+    a. Let thisRealm be the current Realm Record.
+    b. Let realmC be ? GetFunctionRealm(C).
+    c. If thisRealm and realmC are not the same Realm Record, then
+      i. If SameValue(C, realmC.[[Intrinsics]].[[%Array%]]) is true, set C to undefined.
+  7. If Type(C) is Object, then
+    a. Set C to ? Get(C, @@species).
+    b. If C is null, set C to undefined.
+  8. If C is undefined, return ? ArrayCreate(length).
+  9. If IsConstructor(C) is false, throw a TypeError exception.
+  10. Return ? Construct(C, « length »).
+features: [Array.prototype.flatMap, Symbol, Symbol.species]
+includes: [compareArray.js]
+---*/
+
+assert.sameValue(typeof Array.prototype.flatMap, 'function');
+
+var arr = [[42, 1], [42, 2]];
+var mapperFn = function(e) { return e; };
+
+arr.constructor = {};
+var actual = arr.flatMap(mapperFn);
+assert.compareArray(actual, [42, 1, 42, 2], 'undefined species does not throw');
+assert.sameValue(Object.getPrototypeOf(actual), Array.prototype);
+
+var called = 0;
+arr.constructor = {
+  get [Symbol.species]() {
+    called++;
+    return 0;
+  }
+};
+assert.throws(TypeError, function() {
+  arr.flatMap(mapperFn);
+}, 'throw TypeError if @@species is a number');
+assert.sameValue(called, 1, 'got species once');
+
+called = 0;
+arr.constructor = {
+  get [Symbol.species]() {
+    called++;
+    return '';
+  }
+};
+assert.throws(TypeError, function() {
+  arr.flatMap(mapperFn);
+}, 'throw TypeError if @@species is a string');
+assert.sameValue(called, 1, 'got species once');
+
+called = 0;
+arr.constructor = {
+  get [Symbol.species]() {
+    called++;
+    return false;
+  }
+};
+assert.throws(TypeError, function() {
+  arr.flatMap(mapperFn);
+}, 'throw TypeError if @@species is a boolean');
+assert.sameValue(called, 1, 'got species once');
+
+called = 0;
+arr.constructor = {
+  get [Symbol.species]() {
+    called++;
+    return {};
+  }
+};
+assert.throws(TypeError, function() {
+  arr.flatMap(mapperFn);
+}, 'throw TypeError if @@species is an object');
+assert.sameValue(called, 1, 'got species once');
+
+called = 0;
+arr.constructor = {
+  get [Symbol.species]() {
+    called++;
+    return [];
+  }
+};
+assert.throws(TypeError, function() {
+  arr.flatMap(mapperFn);
+}, 'throw TypeError if @@species is an array');
+assert.sameValue(called, 1, 'got species once');
+
+called = 0;
+arr.constructor = {
+  get [Symbol.species]() {
+    called++;
+    return Symbol();
+  }
+};
+assert.throws(TypeError, function() {
+  arr.flatMap(mapperFn);
+}, 'throw TypeError if @@species is a symbol');
+assert.sameValue(called, 1, 'got species once');
+
+called = 0;
+arr.constructor = {
+  get [Symbol.species]() {
+    called++;
+    throw new Test262Error
+  }
+};
+assert.throws(Test262Error, function() {
+  arr.flatMap(mapperFn);
+}, 'Return abrupt completion from getting the @@species');
+assert.sameValue(called, 1, 'got species once');

+ 58 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species-custom-ctor-poisoned-throws.js

@@ -0,0 +1,58 @@
+// Copyright (C) 2018 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-array.prototype.flatMap
+description: >
+  Assert behavior if this value has a poisoned custom species constructor
+info: |
+  Array.prototype.flatMap ( mapperFunction [ , thisArg ] )
+
+  1. Let O be ? ToObject(this value).
+  2. Let sourceLen be ? ToLength(? Get(O, "length")).
+  ...
+  5. Let A be ? ArraySpeciesCreate(O, 0).
+  6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T).
+  7. Return A.
+
+  ArraySpeciesCreate ( originalArray, length )
+
+  3. Let isArray be ? IsArray(originalArray).
+  4. If isArray is false, return ? ArrayCreate(length).
+  5. Let C be ? Get(originalArray, "constructor").
+  6. If IsConstructor(C) is true, then
+    ...
+  7. If Type(C) is Object, then
+    a. Set C to ? Get(C, @@species).
+    b. If C is null, set C to undefined.
+  8. If C is undefined, return ? ArrayCreate(length).
+  9. If IsConstructor(C) is false, throw a TypeError exception.
+  10. Return ? Construct(C, « length »).
+features: [Array.prototype.flatMap, Symbol, Symbol.species]
+---*/
+
+assert.sameValue(typeof Array.prototype.flatMap, 'function');
+
+var arr = [];
+var mapperFn = function(e) { return e; };
+
+var called = 0;
+var ctorCalled = 0;
+function ctor(len) {
+  assert.sameValue(new.target, ctor, 'new target is defined');
+  assert.sameValue(len, 0, 'first argument is always 0');
+  ctorCalled++;
+  throw new Test262Error();
+}
+
+arr.constructor = {
+  get [Symbol.species]() {
+    called++;
+    return ctor;
+  }
+};
+assert.throws(Test262Error, function() {
+  arr.flatMap(mapperFn);
+}, 'Return abrupt completion from species custom ctor');
+assert.sameValue(called, 1, 'got species once');
+assert.sameValue(ctorCalled, 1, 'called custom ctor once');

+ 94 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species-custom-ctor.js

@@ -0,0 +1,94 @@
+// Copyright (C) 2018 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-array.prototype.flatMap
+description: >
+  Assert behavior if this value has a custom species constructor
+info: |
+  Array.prototype.flatMap ( mapperFunction [ , thisArg ] )
+
+  1. Let O be ? ToObject(this value).
+  2. Let sourceLen be ? ToLength(? Get(O, "length")).
+  ...
+  5. Let A be ? ArraySpeciesCreate(O, 0).
+  6. Perform ? FlattenIntoArray(A, O, sourceLen, 0, 1, mapperFunction, T).
+  7. Return A.
+
+  ArraySpeciesCreate ( originalArray, length )
+
+  3. Let isArray be ? IsArray(originalArray).
+  4. If isArray is false, return ? ArrayCreate(length).
+  5. Let C be ? Get(originalArray, "constructor").
+  6. If IsConstructor(C) is true, then
+    ...
+  7. If Type(C) is Object, then
+    a. Set C to ? Get(C, @@species).
+    b. If C is null, set C to undefined.
+  8. If C is undefined, return ? ArrayCreate(length).
+  9. If IsConstructor(C) is false, throw a TypeError exception.
+  10. Return ? Construct(C, « length »).
+
+  FlattenIntoArray(target, source, sourceLen, start, depth [ , mapperFunction, thisArg ])
+
+  3. Repeat, while sourceIndex < sourceLen
+    a. Let P be ! ToString(sourceIndex).
+    b. Let exists be ? HasProperty(source, P).
+    c. If exists is true, then
+      ...
+      vi. Else,
+        ...
+        2. Perform ? CreateDataPropertyOrThrow(target, ! ToString(targetIndex), element).
+features: [Array.prototype.flatMap, Symbol, Symbol.species]
+includes: [propertyHelper.js]
+---*/
+
+assert.sameValue(typeof Array.prototype.flatMap, 'function');
+
+var arr = [[42, 1], [42, 2]];
+var mapperFn = function(e) { return e; };
+
+var called = 0;
+var ctorCalled = 0;
+function ctor(len) {
+  assert.sameValue(new.target, ctor, 'new target is defined');
+  assert.sameValue(len, 0, 'first argument is always 0');
+  ctorCalled++;
+}
+
+arr.constructor = {
+  get [Symbol.species]() {
+    called++;
+    return ctor;
+  }
+};
+var actual = arr.flatMap(mapperFn);
+assert(actual instanceof ctor, 'returned value is an instance of custom ctor');
+assert.sameValue(called, 1, 'got species once');
+assert.sameValue(ctorCalled, 1, 'called custom ctor once');
+
+assert.sameValue(Object.prototype.hasOwnProperty.call(actual, 'length'), false, 'it does not define an own length property');
+verifyProperty(actual, '0', {
+  configurable: true,
+  writable: true,
+  enumerable: true,
+  value: 42
+});
+verifyProperty(actual, '1', {
+  configurable: true,
+  writable: true,
+  enumerable: true,
+  value: 1
+});
+verifyProperty(actual, '2', {
+  configurable: true,
+  writable: true,
+  enumerable: true,
+  value: 42
+});
+verifyProperty(actual, '3', {
+  configurable: true,
+  writable: true,
+  enumerable: true,
+  value: 2
+});

+ 141 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/this-value-ctor-object-species.js

@@ -0,0 +1,141 @@
+// Copyright (C) 2018 Leo Balter. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+
+/*---
+esid: sec-array.prototype.flatMap
+description: >
+  Assert behavior if this value has a custom object constructor property
+info: |
+  Array.prototype.flatMap ( mapperFunction [ , thisArg ] )
+
+  1. Let O be ? ToObject(this value).
+  2. Let sourceLen be ? ToLength(? Get(O, "length")).
+  ...
+  5. Let A be ? ArraySpeciesCreate(O, 0).
+  ...
+
+  ArraySpeciesCreate ( originalArray, length )
+
+  3. Let isArray be ? IsArray(originalArray).
+  4. If isArray is false, return ? ArrayCreate(length).
+  5. Let C be ? Get(originalArray, "constructor").
+  6. If IsConstructor(C) is true, then
+    a. Let thisRealm be the current Realm Record.
+    b. Let realmC be ? GetFunctionRealm(C).
+    c. If thisRealm and realmC are not the same Realm Record, then
+      i. If SameValue(C, realmC.[[Intrinsics]].[[%Array%]]) is true, set C to undefined.
+  7. If Type(C) is Object, then
+    a. Set C to ? Get(C, @@species).
+    b. If C is null, set C to undefined.
+  8. If C is undefined, return ? ArrayCreate(length).
+  9. If IsConstructor(C) is false, throw a TypeError exception.
+  10. Return ? Construct(C, « length »).
+features: [Array.prototype.flatMap, Symbol, Symbol.species]
+includes: [compareArray.js]
+---*/
+
+assert.sameValue(typeof Array.prototype.flatMap, 'function');
+
+var arr = [[42, 1], [42, 2]];
+var mapperFn = function(e) { return e; };
+
+arr.constructor = {};
+var actual = arr.flatMap(mapperFn);
+assert.compareArray(actual, [42, 1, 42, 2], 'undefined species does not throw');
+assert.sameValue(Object.getPrototypeOf(actual), Array.prototype);
+
+var called = 0;
+arr.constructor = {
+  get [Symbol.species]() {
+    called++;
+    return null;
+  }
+};
+actual = arr.flatMap(mapperFn);
+assert.compareArray(actual, [42, 1, 42, 2], 'null species value does not throw');
+assert.sameValue(Object.getPrototypeOf(actual), Array.prototype);
+assert.sameValue(called, 1, 'got species once');
+
+called = 0;
+arr.constructor = {
+  get [Symbol.species]() {
+    called++;
+    return undefined;
+  }
+};
+actual = arr.flatMap(mapperFn);
+assert.compareArray(actual, [42, 1, 42, 2], 'undefined species value does not throw');
+assert.sameValue(Object.getPrototypeOf(actual), Array.prototype);
+assert.sameValue(called, 1, 'got species once');
+
+called = 0;
+arr.constructor = {
+  get [Symbol.species]() {
+    called++;
+    return 0;
+  }
+};
+assert.throws(TypeError, function() {
+  arr.flatMap(mapperFn);
+}, 'throw TypeError if @@species is a number');
+assert.sameValue(called, 1, 'got species once');
+
+called = 0;
+arr.constructor = {
+  get [Symbol.species]() {
+    called++;
+    return '';
+  }
+};
+assert.throws(TypeError, function() {
+  arr.flatMap(mapperFn);
+}, 'throw TypeError if @@species is a string');
+assert.sameValue(called, 1, 'got species once');
+
+called = 0;
+arr.constructor = {
+  get [Symbol.species]() {
+    called++;
+    return false;
+  }
+};
+assert.throws(TypeError, function() {
+  arr.flatMap(mapperFn);
+}, 'throw TypeError if @@species is a boolean');
+assert.sameValue(called, 1, 'got species once');
+
+called = 0;
+arr.constructor = {
+  get [Symbol.species]() {
+    called++;
+    return {};
+  }
+};
+assert.throws(TypeError, function() {
+  arr.flatMap(mapperFn);
+}, 'throw TypeError if @@species is an object');
+assert.sameValue(called, 1, 'got species once');
+
+called = 0;
+arr.constructor = {
+  get [Symbol.species]() {
+    called++;
+    return [];
+  }
+};
+assert.throws(TypeError, function() {
+  arr.flatMap(mapperFn);
+}, 'throw TypeError if @@species is an array');
+assert.sameValue(called, 1, 'got species once');
+
+called = 0;
+arr.constructor = {
+  get [Symbol.species]() {
+    called++;
+    return Symbol();
+  }
+};
+assert.throws(TypeError, function() {
+  arr.flatMap(mapperFn);
+}, 'throw TypeError if @@species is a symbol');
+assert.sameValue(called, 1, 'got species once');

+ 25 - 0
Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/this-value-null-undefined-throws.js

@@ -0,0 +1,25 @@
+// Copyright (C) 2018 Shilpi Jain and Michael Ficarra. All rights reserved.
+// This code is governed by the BSD license found in the LICENSE file.
+/*---
+esid: sec-array.prototype.flatMap
+description: >
+  Throw a TypeError if this value is null or undefined
+info: |
+  Array.prototype.flatMap ( mapperFunction [ , thisArg ] )
+
+  1. Let O be ? ToObject(this value).
+  ...
+features: [Array.prototype.flatMap]
+---*/
+
+assert.sameValue(typeof Array.prototype.flatMap, 'function');
+
+var mapperFn = function() {};
+
+assert.throws(TypeError, function() {
+  [].flatMap.call(null, mapperFn);
+}, 'null value');
+
+assert.throws(TypeError, function() {
+  [].flatMap.call(undefined, mapperFn);
+}, 'undefined');

+ 26 - 13
Jint.Tests.Test262/test/built-ins/Array/prototype/flatMap/thisArg-argument.js

@@ -5,28 +5,41 @@ esid: sec-array.prototype.flatMap
 description: >
     Behavior when thisArg is provided
     Array.prototype.flatMap ( mapperFunction [ , thisArg ] )
-includes: [compareArray.js]
 flags: [onlyStrict]
+includes: [compareArray.js]
 features: [Array.prototype.flatMap]
 ---*/
 
 var a = {};
+var actual;
 
-assert(compareArray([1].flatMap(function() {
+actual = [1].flatMap(function() {
   return [this];
-}, "TestString"), ["TestString"]));
-assert(compareArray([1].flatMap(function() {
+}, "TestString");
+assert.compareArray(actual, ["TestString"]);
+
+actual = [1].flatMap(function() {
   return [this];
-}, 1), [1]));
-assert(compareArray([1].flatMap(function() {
+}, 1);
+assert.compareArray(actual, [1]);
+
+actual = [1].flatMap(function() {
   return [this];
-}, null), [null]));
-assert(compareArray([1].flatMap(function() {
+}, null);
+assert.compareArray(actual, [null]);
+
+actual = [1].flatMap(function() {
   return [this];
-}, true), [true]));
-assert(compareArray([1].flatMap(function() {
+}, true);
+assert.compareArray(actual, [true]);
+
+actual = [1].flatMap(function() {
   return [this];
-}, a), [a]));
-assert(compareArray([1].flatMap(function() {
+}, a);
+assert.compareArray(actual, [a]);
+
+actual = [1].flatMap(function() {
   return [this];
-}, void 0), [undefined]));
+}, void 0);
+assert.compareArray(actual, [undefined]);
+

+ 10 - 0
Jint/Engine.cs

@@ -714,6 +714,16 @@ namespace Jint
             return GetIdentifierReference(env._outer, name, strict);
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-getnewtarget
+        /// </summary>
+        internal JsValue GetNewTarget(EnvironmentRecord thisEnvironment = null)
+        {
+            // we can take as argument if caller site has already determined the value, otherwise resolve
+            thisEnvironment ??= GetThisEnvironment();
+            return thisEnvironment.NewTarget;
+        }
+        
         /// <summary>
         /// https://tc39.es/ecma262/#sec-getthisenvironment
         /// </summary>

+ 126 - 2
Jint/Native/Array/ArrayPrototype.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.Linq;
 using Jint.Collections;
 using Jint.Native.Number;
@@ -57,7 +58,7 @@ namespace Jint.Native.Array
             unscopables.SetDataProperty("values", JsBoolean.True);
             
             const PropertyFlag propertyFlags = PropertyFlag.Writable | PropertyFlag.Configurable;
-            var properties = new PropertyDictionary(30, checkExistingKeys: false)
+            var properties = new PropertyDictionary(32, checkExistingKeys: false)
             {
                 ["constructor"] = new PropertyDescriptor(_arrayConstructor, PropertyFlag.NonEnumerable),
                 ["toString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toString", ToString, 0, PropertyFlag.Configurable), propertyFlags),
@@ -88,7 +89,9 @@ namespace Jint.Native.Array
                 ["find"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "find", Find, 1, PropertyFlag.Configurable), propertyFlags),
                 ["findIndex"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "findIndex", FindIndex, 1, PropertyFlag.Configurable), propertyFlags),
                 ["keys"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "keys", Keys, 0, PropertyFlag.Configurable), propertyFlags),
-                ["values"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "values", Values, 0, PropertyFlag.Configurable), propertyFlags)
+                ["values"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "values", Values, 0, PropertyFlag.Configurable), propertyFlags),
+                ["flat"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "values", Flat, 0, PropertyFlag.Configurable), propertyFlags),
+                ["flatMap"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "values", FlatMap, 0, PropertyFlag.Configurable), propertyFlags),
             };
             SetProperties(properties);
 
@@ -441,6 +444,127 @@ namespace Jint.Native.Array
             return a.Target;
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-array.prototype.flat
+        /// </summary>
+        private JsValue Flat(JsValue thisObj, JsValue[] arguments)
+        {
+            var O = TypeConverter.ToObject(_engine, thisObj);
+            var operations = ArrayOperations.For(O);
+            var sourceLen = operations.GetLength();
+            double depthNum = 1;
+            var depth = arguments.At(0);
+            if (!depth.IsUndefined())
+            {
+                depthNum = TypeConverter.ToIntegerOrInfinity(depth);
+            }
+
+            if (depthNum < 0)
+            {
+                depthNum = 0;
+            }
+
+            var A = _engine.Array.ArraySpeciesCreate(O, 0);
+            FlattenIntoArray(A, O, sourceLen, 0, depthNum);
+            return A;
+        }
+        
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-array.prototype.flatmap
+        /// </summary>
+        private JsValue FlatMap(JsValue thisObj, JsValue[] arguments)
+        {
+            var O = TypeConverter.ToObject(_engine, thisObj);
+            var mapperFunction = arguments.At(0);
+            var thisArg = arguments.At(1);
+            
+            var sourceLen = O.Length;
+
+            if (!mapperFunction.IsCallable)
+            {
+                ExceptionHelper.ThrowTypeError(_engine, "flatMap mapper function is not callable");
+            }
+            
+            var A = _engine.Array.ArraySpeciesCreate(O, 0);
+            FlattenIntoArray(A, O, sourceLen, 0, 1, (ICallable) mapperFunction, thisArg);
+            return A;
+        }
+
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-flattenintoarray
+        /// </summary>
+        private long FlattenIntoArray(
+            ObjectInstance target,
+            ObjectInstance source,
+            uint sourceLen,
+            long start, 
+            double depth, 
+            ICallable mapperFunction = null,
+            JsValue thisArg = null)
+        {
+            var targetIndex = start;
+            var sourceIndex = 0;
+
+            var callArguments = System.Array.Empty<JsValue>();
+            if (mapperFunction is not null)
+            {
+                callArguments = _engine._jsValueArrayPool.RentArray(3);
+                callArguments[2] = source;
+            }
+
+            while (sourceIndex < sourceLen)
+            {
+                var P = TypeConverter.ToString(sourceIndex);
+                var exists = source.HasProperty(P);
+                if (exists)
+                {
+                    var element = source.Get(P);
+                    if (mapperFunction is not null)
+                    {
+                        callArguments[0] = element;
+                        callArguments[1] = JsNumber.Create(sourceIndex);
+                        mapperFunction.Call(thisArg, callArguments);
+                    }
+
+                    var shouldFlatten = false;
+                    if (depth > 0)
+                    {
+                        shouldFlatten = element.IsArray();
+                    }
+
+                    if (shouldFlatten)
+                    {
+                        var newDepth = double.IsPositiveInfinity(depth)
+                            ? depth
+                            : depth - 1;
+
+                        var objectInstance = (ObjectInstance) element;
+                        var elementLen = objectInstance.Length;
+                        targetIndex = FlattenIntoArray(target, objectInstance, elementLen, targetIndex, newDepth);
+                    }
+                    else
+                    {
+                        if (targetIndex >= NumberConstructor.MaxSafeInteger)
+                        {
+                            ExceptionHelper.ThrowTypeError(_engine);
+                        }
+
+                        target.CreateDataPropertyOrThrow(targetIndex, element);
+                        targetIndex += 1;
+                    }
+                }
+
+                sourceIndex++;
+            }
+
+            if (mapperFunction is not null)
+            {
+                _engine._jsValueArrayPool.ReturnArray(callArguments);
+            }
+
+            return targetIndex;
+        }
+
         private JsValue ForEach(JsValue thisObj, JsValue[] arguments)
         {
             var callbackfn = arguments.At(0);

+ 1 - 1
Jint/Native/Function/FunctionInstance.cs

@@ -354,7 +354,7 @@ namespace Jint.Native.Function
             {
                 name = TypeConverter.ToString(nameValue);
             }
-            return "function " + name + "() {{[native code]}}";
+            return "function " + name + "() { [native code] }";
         }
     }
 }

+ 1 - 4
Jint/Runtime/Interop/ClrFunctionInstance.cs

@@ -68,9 +68,6 @@ namespace Jint.Runtime.Interop
             return false;
         }
 
-        public override string ToString()
-        {
-            return $"function {_name}() {{ [native code] }}";
-        }
+        public override string ToString() => "function " + _name + "() { [native code] }";
     }
 }

+ 1 - 9
Jint/Runtime/Interpreter/Expressions/JintCallExpression.cs

@@ -77,7 +77,7 @@ namespace Jint.Runtime.Interpreter.Expressions
         private object SuperCall()
         {
             var thisEnvironment = (FunctionEnvironmentRecord) _engine.GetThisEnvironment();
-            var newTarget = GetNewTarget(thisEnvironment);
+            var newTarget = _engine.GetNewTarget(thisEnvironment);
             var func = GetSuperConstructor(thisEnvironment);
             if (!func.IsConstructor)
             {
@@ -101,14 +101,6 @@ namespace Jint.Runtime.Interpreter.Expressions
             return superConstructor;
         }
 
-        /// <summary>
-        /// https://tc39.es/ecma262/#sec-getnewtarget
-        /// </summary>
-        private JsValue GetNewTarget(FunctionEnvironmentRecord thisEnvironment)
-        {
-            return thisEnvironment.NewTarget;
-        }
-
         private object Call()
         {
             var callee = _calleeExpression.Evaluate();

+ 1 - 0
Jint/Runtime/Interpreter/Expressions/JintExpression.cs

@@ -121,6 +121,7 @@ namespace Jint.Runtime.Interpreter.Expressions
                 Nodes.TaggedTemplateExpression => new JintTaggedTemplateExpression(engine, (TaggedTemplateExpression) expression),
                 Nodes.ClassExpression => new JintClassExpression(engine, (ClassExpression) expression),
                 Nodes.Super => new JintSuperExpression(engine, (Super) expression),
+                Nodes.MetaProperty => new JintMetaPropertyExpression(engine, (MetaProperty) expression),
                 _ => ExceptionHelper.ThrowArgumentOutOfRangeException<JintExpression>(nameof(expression), $"unsupported expression type '{expression.Type}'")
             };
         }

+ 1 - 1
Jint/Runtime/Interpreter/Expressions/JintIdentifierExpression.cs

@@ -19,7 +19,7 @@ namespace Jint.Runtime.Interpreter.Expressions
         }
 
         public bool HasEvalOrArguments
-            => _expressionName.StringValue._value == KnownKeys.Eval || _expressionName.Key == KnownKeys.Arguments;
+            => _expressionName.Key == KnownKeys.Eval || _expressionName.Key == KnownKeys.Arguments;
 
         protected override object EvaluateInternal()
         {

+ 25 - 0
Jint/Runtime/Interpreter/Expressions/JintMetaPropertyExpression.cs

@@ -0,0 +1,25 @@
+using Esprima.Ast;
+
+namespace Jint.Runtime.Interpreter.Expressions
+{
+    internal sealed class JintMetaPropertyExpression : JintExpression
+    {
+        private readonly bool _newTarget;
+
+        public JintMetaPropertyExpression(Engine engine, MetaProperty expression) : base(engine, expression)
+        {
+            _newTarget = expression.Meta.Name == "new" && expression.Property.Name == "target";
+        }
+
+        protected override object EvaluateInternal()
+        {
+            if (_newTarget)
+            {
+                return _engine.GetNewTarget();
+            }
+            
+            ExceptionHelper.ThrowNotImplementedException();
+            return null;
+        }
+    }
+}

+ 1 - 1
Jint/Runtime/Interpreter/Expressions/JintSuperExpression.cs

@@ -3,7 +3,7 @@ using Jint.Runtime.Environments;
 
 namespace Jint.Runtime.Interpreter.Expressions
 {
-    internal class JintSuperExpression : JintExpression
+    internal sealed class JintSuperExpression : JintExpression
     {
         public JintSuperExpression(Engine engine, Super expression) : base(engine, expression)
         {

+ 25 - 0
Jint/Runtime/TypeConverter.cs

@@ -312,6 +312,31 @@ namespace Jint.Runtime
             return (ulong) Math.Min(len, NumberConstructor.MaxSafeInteger);
         }
 
+        /// <summary>
+        /// https://tc39.es/ecma262/#sec-tointegerorinfinity
+        /// </summary>
+        public static double ToIntegerOrInfinity(JsValue argument)
+        {
+            var number = ToNumber(argument);
+            if (double.IsNaN(number) || number == 0)
+            {
+                return 0;
+            }
+
+            if (double.IsInfinity(number))
+            {
+                return number;
+            }
+
+            var integer = (long) Math.Floor(Math.Abs(number));
+            if (number < 0)
+            {
+                integer *= -1;
+            }
+
+            return integer;
+        }
+        
         /// <summary>
         /// https://tc39.es/ecma262/#sec-tointeger
         /// </summary>

+ 2 - 2
README.md

@@ -1,7 +1,7 @@
 [![Build status](https://ci.appveyor.com/api/projects/status/xh2lsliy6usk60o5?svg=true)](https://ci.appveyor.com/project/SebastienRos/jint)
 [![NuGet](https://img.shields.io/nuget/v/Jint.svg)](https://www.nuget.org/packages/Jint)
 [![NuGet](https://img.shields.io/nuget/vpre/Jint.svg)](https://www.nuget.org/packages/Jint)
-[![MyGet](https://img.shields.io/myget/jint/v/jint.svg)](https://www.myget.org/feed/Packages/jint)
+[![MyGet](https://img.shields.io/myget/jint/vpre/jint.svg)](https://www.myget.org/feed/Packages/Jint)
 [![Join the chat at https://gitter.im/sebastienros/jint](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/sebastienros/jint)
 
 # Jint
@@ -62,7 +62,7 @@ The entire execution engine was rebuild with performance in mind, in many cases
 
 #### ECMAScript 2019
 
--  `Array.prototype.flat`, `Array.prototype.flatMap`
+-  `Array.prototype.flat`, `Array.prototype.flatMap`
 
 #### ECMAScript 2020