瀏覽代碼

Add public type Constructor (#1440)

* Add public type Constructor

* Make rest of the possible built-in constructors inherit from Constructor
Marko Lahma 2 年之前
父節點
當前提交
5eb6b82e7f
共有 31 個文件被更改,包括 203 次插入162 次删除
  1. 119 0
      Jint.Tests.PublicInterface/ConstructorTests.cs
  2. 2 3
      Jint.Tests/Runtime/Domain/UuidConstructor.cs
  3. 2 5
      Jint/Native/AggregateError/AggregateErrorConstructor.cs
  4. 3 5
      Jint/Native/Array/ArrayConstructor.cs
  5. 2 8
      Jint/Native/ArrayBuffer/ArrayBufferConstructor.cs
  6. 2 4
      Jint/Native/AsyncFunction/AsyncFunctionConstructor.cs
  7. 2 2
      Jint/Native/BigInt/BigIntConstructor.cs
  8. 2 2
      Jint/Native/Boolean/BooleanConstructor.cs
  9. 20 0
      Jint/Native/Constructor.cs
  10. 2 8
      Jint/Native/DataView/DataViewConstructor.cs
  11. 2 6
      Jint/Native/Date/DateConstructor.cs
  12. 2 5
      Jint/Native/Error/ErrorConstructor.cs
  13. 2 4
      Jint/Native/FinalizationRegistry/FinalizationRegistryConstructor.cs
  14. 2 4
      Jint/Native/Function/FunctionConstructor.cs
  15. 2 8
      Jint/Native/Map/MapConstructor.cs
  16. 2 2
      Jint/Native/Number/NumberConstructor.cs
  17. 2 5
      Jint/Native/Object/ObjectConstructor.cs
  18. 2 8
      Jint/Native/Promise/PromiseConstructor.cs
  19. 2 9
      Jint/Native/Proxy/ProxyConstructor.cs
  20. 3 5
      Jint/Native/RegExp/RegExpConstructor.cs
  21. 3 9
      Jint/Native/Set/SetConstructor.cs
  22. 2 8
      Jint/Native/ShadowRealm/ShadowRealmConstructor.cs
  23. 3 3
      Jint/Native/String/StringConstructor.cs
  24. 3 3
      Jint/Native/Symbol/SymbolConstructor.cs
  25. 3 4
      Jint/Native/TypedArray/IntrinsicTypedArrayConstructor.cs
  26. 2 11
      Jint/Native/TypedArray/TypedArrayConstructor.cs
  27. 2 8
      Jint/Native/WeakMap/WeakMapConstructor.cs
  28. 2 8
      Jint/Native/WeakRef/WeakRefConstructor.cs
  29. 2 8
      Jint/Native/WeakSet/WeakSetConstructor.cs
  30. 3 6
      Jint/Runtime/Interop/TypeReference.cs
  31. 1 1
      Jint/Runtime/Intrinsics.cs

+ 119 - 0
Jint.Tests.PublicInterface/ConstructorTests.cs

@@ -0,0 +1,119 @@
+using Jint.Native;
+using Jint.Native.Object;
+using Jint.Runtime;
+using Jint.Runtime.Interop;
+
+namespace Jint.Tests.PublicInterface;
+
+public class ConstructorTests
+{
+    private readonly Engine _engine;
+
+    public ConstructorTests()
+    {
+        _engine = new Engine();
+        _engine.SetValue("DateOnly", new DateOnlyConstructor(_engine));
+    }
+
+    [Fact]
+    public void CanConstructWithParameters()
+    {
+        var wrapper = (IObjectWrapper) _engine.Evaluate("new DateOnly(1982, 6, 28);");
+        var date = (DateOnly) wrapper.Target;
+        Assert.Equal(1982, date.Year);
+        Assert.Equal(6, date.Month);
+        Assert.Equal(28, date.Day);
+
+        Assert.Equal(1982, _engine.Evaluate("new DateOnly(1982, 6, 28).year").AsNumber());
+        Assert.Equal(6, _engine.Evaluate("new DateOnly(1982, 6, 28).month").AsNumber());
+        Assert.Equal(28, _engine.Evaluate("new DateOnly(1982, 6, 28).day").AsNumber());
+    }
+
+    [Fact]
+    public void CanConstructWithoutParameters()
+    {
+        Assert.Equal(DateTime.Today.Year, _engine.Evaluate("new DateOnly().year").AsNumber());
+        Assert.Equal(DateTime.Today.Month, _engine.Evaluate("new DateOnly().month").AsNumber());
+        Assert.Equal(DateTime.Today.Day, _engine.Evaluate("new DateOnly().day").AsNumber());
+    }
+
+    [Fact]
+    public void CallThrows()
+    {
+        var ex = Assert.Throws<JavaScriptException>(() => _engine.Evaluate("DateOnly(1982, 6, 28);"));
+        Assert.Equal("Constructor DateOnly requires 'new'", ex.Message);
+    }
+
+    [Fact]
+    public void CanThrowTypeError()
+    {
+        var ex = Assert.Throws<JavaScriptException>(() => _engine.Evaluate("new DateOnly(undefined, 1, 1);"));
+        Assert.Equal("Invalid year NaN", ex.Message);
+    }
+}
+
+file sealed class DateOnlyConstructor : Constructor
+{
+    public DateOnlyConstructor(Engine engine) : base(engine, engine.Realm, (JsString) "DateOnly")
+    {
+    }
+
+    public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
+    {
+        DateOnly result;
+        if (arguments.Length == 0)
+        {
+            result = new DateOnly(DateTime.Today);
+        }
+        else if (arguments.Length == 1)
+        {
+            var days = TypeConverter.ToNumber(arguments[0]);
+            var ticks = (long) (days * TimeSpan.TicksPerDay);
+            result = new DateOnly(new DateTime(ticks));
+        }
+        else
+        {
+            var year = TypeConverter.ToNumber(arguments.At(0));
+            var month = TypeConverter.ToNumber(arguments.At(1)) - 1;
+            var day = arguments.Length == 2 ? 0 : TypeConverter.ToNumber(arguments[2]) - 1;
+            if (double.IsNaN(year))
+            {
+                throw new JavaScriptException(_engine.Realm.Intrinsics.TypeError, "Invalid year " + year);
+            }
+
+            if (double.IsNaN(month))
+            {
+                throw new JavaScriptException(_engine.Realm.Intrinsics.TypeError, "Invalid month " + month);
+            }
+
+            if (double.IsNaN(day))
+            {
+                throw new JavaScriptException(_engine.Realm.Intrinsics.TypeError, "Invalid day " + day);
+            }
+
+            var dt = new DateTime((int) year, 1, 1);
+            dt = dt.AddMonths((int) month);
+            dt = dt.AddDays((int) day);
+
+            result = new DateOnly(dt);
+        }
+
+        return (ObjectInstance) FromObject(_engine, result);
+    }
+}
+
+file sealed class DateOnly
+{
+    internal DateOnly(DateTime value)
+    {
+        Year = value.Year;
+        Month = value.Month;
+        Day = value.Day;
+    }
+
+    public JsValue Year { get; set; }
+
+    public JsValue Month { get; set; }
+
+    public JsValue Day { get; set; }
+}

+ 2 - 3
Jint.Tests/Runtime/Domain/UuidConstructor.cs

@@ -1,5 +1,4 @@
 using Jint.Native;
-using Jint.Native.Function;
 using Jint.Native.Object;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
@@ -7,7 +6,7 @@ using Jint.Runtime.Interop;
 
 namespace Jint.Tests.Runtime.Domain
 {
-    internal sealed class UuidConstructor : FunctionInstance, IConstructor
+    internal sealed class UuidConstructor : Constructor
     {
         private static readonly JsString _functionName = new JsString("Uuid");
 
@@ -64,6 +63,6 @@ namespace Jint.Tests.Runtime.Domain
 
         public UuidInstance Construct(JsUuid uuid) => new UuidInstance(Engine) { PrimitiveValue = uuid, _prototype = PrototypeObject };
 
-        public ObjectInstance Construct(JsValue[] arguments, JsValue newTarget) => Construct(Guid.NewGuid());
+        public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget) => Construct(Guid.NewGuid());
     }
 }

+ 2 - 5
Jint/Native/AggregateError/AggregateErrorConstructor.cs

@@ -1,5 +1,4 @@
 using Jint.Native.Error;
-using Jint.Native.Function;
 using Jint.Native.Object;
 using Jint.Native.TypedArray;
 using Jint.Runtime;
@@ -10,7 +9,7 @@ namespace Jint.Native.AggregateError;
 /// <summary>
 /// https://tc39.es/ecma262/#sec-aggregate-error-constructor
 /// </summary>
-internal sealed class AggregateErrorConstructor : FunctionInstance, IConstructor
+internal sealed class AggregateErrorConstructor : Constructor
 {
     private static readonly JsString _name = new("AggregateError");
 
@@ -33,12 +32,10 @@ internal sealed class AggregateErrorConstructor : FunctionInstance, IConstructor
         return Construct(arguments, this);
     }
 
-    ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget) => Construct(arguments, newTarget);
-
     /// <summary>
     /// https://tc39.es/ecma262/#sec-nativeerror
     /// </summary>
-    private ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
+    public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
     {
         var errors = arguments.At(0);
         var message = arguments.At(1);

+ 3 - 5
Jint/Native/Array/ArrayConstructor.cs

@@ -10,7 +10,7 @@ using Jint.Runtime.Interop;
 
 namespace Jint.Native.Array
 {
-    public sealed class ArrayConstructor : FunctionInstance, IConstructor
+    public sealed class ArrayConstructor : Constructor
     {
         private static readonly JsString _functionName = new JsString("Array");
 
@@ -277,12 +277,10 @@ namespace Jint.Native.Array
 
         public JsArray Construct(JsValue[] arguments)
         {
-            return Construct(arguments, this);
+            return (JsArray) Construct(arguments, this);
         }
 
-        ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget) => Construct(arguments, newTarget);
-
-        internal JsArray Construct(JsValue[] arguments, JsValue newTarget)
+        public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
         {
             if (newTarget.IsUndefined())
             {

+ 2 - 8
Jint/Native/ArrayBuffer/ArrayBufferConstructor.cs

@@ -13,7 +13,7 @@ namespace Jint.Native.ArrayBuffer
     /// <summary>
     /// https://tc39.es/ecma262/#sec-properties-of-the-arraybuffer-constructor
     /// </summary>
-    internal sealed class ArrayBufferConstructor : FunctionInstance, IConstructor
+    internal sealed class ArrayBufferConstructor : Constructor
     {
         private static readonly JsString _functionName = new("ArrayBuffer");
 
@@ -65,13 +65,7 @@ namespace Jint.Native.ArrayBuffer
             return thisObject;
         }
 
-        protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
-        {
-            ExceptionHelper.ThrowTypeError(_realm, "Constructor ArrayBuffer requires 'new'");
-            return Undefined;
-        }
-
-        ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget)
+        public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
         {
             if (newTarget.IsUndefined())
             {

+ 2 - 4
Jint/Native/AsyncFunction/AsyncFunctionConstructor.cs

@@ -8,7 +8,7 @@ namespace Jint.Native.AsyncFunction;
 /// <summary>
 /// https://tc39.es/ecma262/#sec-async-function-constructor
 /// </summary>
-internal sealed class AsyncFunctionConstructor : FunctionInstance, IConstructor
+internal sealed class AsyncFunctionConstructor : Constructor
 {
     private static readonly JsString _functionName = new("AsyncFunction");
 
@@ -27,9 +27,7 @@ internal sealed class AsyncFunctionConstructor : FunctionInstance, IConstructor
         return Construct(arguments, thisObject);
     }
 
-    ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget) => Construct(arguments, newTarget);
-
-    private ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
+    public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
     {
         var function = CreateDynamicFunction(
             this,

+ 2 - 2
Jint/Native/BigInt/BigIntConstructor.cs

@@ -11,7 +11,7 @@ namespace Jint.Native.BigInt;
 /// <summary>
 /// https://tc39.es/ecma262/#sec-properties-of-the-bigint-constructor
 /// </summary>
-internal sealed class BigIntConstructor : FunctionInstance, IConstructor
+internal sealed class BigIntConstructor : Constructor
 {
     private static readonly JsString _functionName = new("BigInt");
 
@@ -101,7 +101,7 @@ internal sealed class BigIntConstructor : FunctionInstance, IConstructor
     /// <summary>
     /// https://tc39.es/ecma262/#sec-bigint-constructor-number-value
     /// </summary>
-    ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget)
+    public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
     {
         var value = arguments.Length > 0
             ? JsBigInt.Create(arguments[0].ToBigInteger(_engine))

+ 2 - 2
Jint/Native/Boolean/BooleanConstructor.cs

@@ -5,7 +5,7 @@ using Jint.Runtime.Descriptors;
 
 namespace Jint.Native.Boolean
 {
-    internal sealed class BooleanConstructor : FunctionInstance, IConstructor
+    internal sealed class BooleanConstructor : Constructor
     {
         private static readonly JsString _functionName = new JsString("Boolean");
 
@@ -37,7 +37,7 @@ namespace Jint.Native.Boolean
         /// <summary>
         /// https://tc39.es/ecma262/#sec-boolean-constructor-boolean-value
         /// </summary>
-        ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget)
+        public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
         {
             var b = TypeConverter.ToBoolean(arguments.At(0))
                 ? JsBoolean.True

+ 20 - 0
Jint/Native/Constructor.cs

@@ -0,0 +1,20 @@
+using Jint.Native.Function;
+using Jint.Native.Object;
+using Jint.Runtime;
+
+namespace Jint.Native;
+
+public abstract class Constructor : FunctionInstance, IConstructor
+{
+    protected Constructor(Engine engine, Realm realm, JsString name) : base(engine, realm, name)
+    {
+    }
+
+    protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
+    {
+        ExceptionHelper.ThrowTypeError(_realm, $"Constructor {_nameDescriptor?.Value} requires 'new'");
+        return null;
+    }
+
+    public abstract ObjectInstance Construct(JsValue[] arguments, JsValue newTarget);
+}

+ 2 - 8
Jint/Native/DataView/DataViewConstructor.cs

@@ -9,7 +9,7 @@ namespace Jint.Native.DataView
     /// <summary>
     /// https://tc39.es/ecma262/#sec-dataview-constructor
     /// </summary>
-    internal sealed class DataViewConstructor : FunctionInstance, IConstructor
+    internal sealed class DataViewConstructor : Constructor
     {
         private static readonly JsString _functionName = new("DataView");
 
@@ -28,13 +28,7 @@ namespace Jint.Native.DataView
 
         public DataViewPrototype PrototypeObject { get; }
 
-        protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
-        {
-            ExceptionHelper.ThrowTypeError(_realm, "Constructor DataView requires 'new'");
-            return Undefined;
-        }
-
-        ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget)
+        public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
         {
             if (newTarget.IsUndefined())
             {

+ 2 - 6
Jint/Native/Date/DateConstructor.cs

@@ -1,5 +1,4 @@
 using System.Globalization;
-using System.Runtime.CompilerServices;
 using Jint.Collections;
 using Jint.Native.Function;
 using Jint.Native.Object;
@@ -12,7 +11,7 @@ namespace Jint.Native.Date;
 /// <summary>
 /// https://tc39.es/ecma262/#sec-date-constructor
 /// </summary>
-internal sealed class DateConstructor : FunctionInstance, IConstructor
+internal sealed class DateConstructor : Constructor
 {
     internal static readonly DateTime Epoch = new(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
 
@@ -165,13 +164,10 @@ internal sealed class DateConstructor : FunctionInstance, IConstructor
         return PrototypeObject.ToString(Construct(Arguments.Empty, thisObject), Arguments.Empty);
     }
 
-    ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget) => Construct(arguments, newTarget);
-
     /// <summary>
     /// https://tc39.es/ecma262/#sec-date
     /// </summary>
-    [MethodImpl(MethodImplOptions.AggressiveInlining)]
-    private ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
+    public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
     {
         // fast path is building default, new Date()
         if (arguments.Length == 0 || newTarget.IsUndefined())

+ 2 - 5
Jint/Native/Error/ErrorConstructor.cs

@@ -1,11 +1,10 @@
-using Jint.Native.Function;
 using Jint.Native.Object;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
 
 namespace Jint.Native.Error
 {
-    public sealed class ErrorConstructor : FunctionInstance, IConstructor
+    public sealed class ErrorConstructor : Constructor
     {
         private readonly Func<Intrinsics, ObjectInstance> _intrinsicDefaultProto;
 
@@ -36,12 +35,10 @@ namespace Jint.Native.Error
             return Construct(message != null ? new JsValue[]{ message } : System.Array.Empty<JsValue>(), this);
         }
 
-        ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget) => Construct(arguments, newTarget);
-
         /// <summary>
         /// https://tc39.es/ecma262/#sec-nativeerror
         /// </summary>
-        private ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
+        public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
         {
             var o = OrdinaryCreateFromConstructor(
                 newTarget,

+ 2 - 4
Jint/Native/FinalizationRegistry/FinalizationRegistryConstructor.cs

@@ -8,7 +8,7 @@ namespace Jint.Native.FinalizationRegistry;
 /// <summary>
 /// https://tc39.es/ecma262/#sec-finalization-registry-constructor
 /// </summary>
-internal sealed class FinalizationRegistryConstructor : FunctionInstance, IConstructor
+internal sealed class FinalizationRegistryConstructor : Constructor
 {
     private static readonly JsString _functionName = new("FinalizationRegistry");
 
@@ -31,9 +31,7 @@ internal sealed class FinalizationRegistryConstructor : FunctionInstance, IConst
         return Construct(arguments, thisObject);
     }
 
-    ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget) => Construct(arguments, newTarget);
-
-    private ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
+    public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
     {
         if (newTarget.IsUndefined())
         {

+ 2 - 4
Jint/Native/Function/FunctionConstructor.cs

@@ -9,7 +9,7 @@ namespace Jint.Native.Function
     /// <summary>
     /// https://tc39.es/ecma262/#sec-function-constructor
     /// </summary>
-    public sealed class FunctionConstructor : FunctionInstance, IConstructor
+    public sealed class FunctionConstructor : Constructor
     {
         private static readonly JsString _functionName = new JsString("Function");
 
@@ -32,9 +32,7 @@ namespace Jint.Native.Function
             return Construct(arguments, thisObject);
         }
 
-        ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget) => Construct(arguments, newTarget);
-
-        private ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
+        public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
         {
             var function = CreateDynamicFunction(
                 this,

+ 2 - 8
Jint/Native/Map/MapConstructor.cs

@@ -9,7 +9,7 @@ using Jint.Runtime.Interop;
 
 namespace Jint.Native.Map;
 
-internal sealed class MapConstructor : FunctionInstance, IConstructor
+internal sealed class MapConstructor : Constructor
 {
     private static readonly JsString _functionName = new("Map");
 
@@ -42,16 +42,10 @@ internal sealed class MapConstructor : FunctionInstance, IConstructor
         return thisObject;
     }
 
-    protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
-    {
-        ExceptionHelper.ThrowTypeError(_realm, "Constructor Map requires 'new'");
-        return null;
-    }
-
     /// <summary>
     /// https://tc39.es/ecma262/#sec-map-iterable
     /// </summary>
-    ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget)
+    public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
     {
         if (newTarget.IsUndefined())
         {

+ 2 - 2
Jint/Native/Number/NumberConstructor.cs

@@ -11,7 +11,7 @@ namespace Jint.Native.Number
     /// <summary>
     /// https://tc39.es/ecma262/#sec-number-constructor
     /// </summary>
-    internal sealed class NumberConstructor : FunctionInstance, IConstructor
+    internal sealed class NumberConstructor : Constructor
     {
         private static readonly JsString _functionName = new JsString("Number");
 
@@ -121,7 +121,7 @@ namespace Jint.Native.Number
         /// <summary>
         /// https://tc39.es/ecma262/#sec-number-constructor-number-value
         /// </summary>
-        ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget)
+        public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
         {
             var n = ProcessFirstParameter(arguments);
 

+ 2 - 5
Jint/Native/Object/ObjectConstructor.cs

@@ -1,5 +1,4 @@
 using Jint.Collections;
-using Jint.Native.Function;
 using Jint.Native.Iterator;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
@@ -7,7 +6,7 @@ using Jint.Runtime.Interop;
 
 namespace Jint.Native.Object
 {
-    public sealed class ObjectConstructor : FunctionInstance, IConstructor
+    public sealed class ObjectConstructor : Constructor
     {
         private static readonly JsString _name = new JsString("Object");
 
@@ -153,9 +152,7 @@ namespace Jint.Native.Object
             return Construct(arguments, this);
         }
 
-        ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget) => Construct(arguments, newTarget);
-
-        private ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
+        public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
         {
             if (!ReferenceEquals(this, newTarget) && !newTarget.IsUndefined())
             {

+ 2 - 8
Jint/Native/Promise/PromiseConstructor.cs

@@ -17,7 +17,7 @@ namespace Jint.Native.Promise
         JsValue ResolveObj
     );
 
-    internal sealed class PromiseConstructor : FunctionInstance, IConstructor
+    internal sealed class PromiseConstructor : Constructor
     {
         private static readonly JsString _functionName = new JsString("Promise");
 
@@ -60,16 +60,10 @@ namespace Jint.Native.Promise
             SetSymbols(symbols);
         }
 
-        protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
-        {
-            ExceptionHelper.ThrowTypeError(_realm, "Constructor Promise requires 'new'");
-            return null;
-        }
-
         /// <summary>
         /// https://tc39.es/ecma262/#sec-promise-executor
         /// </summary>
-        ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget)
+        public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
         {
             if (newTarget.IsUndefined())
             {

+ 2 - 9
Jint/Native/Proxy/ProxyConstructor.cs

@@ -1,5 +1,4 @@
 using Jint.Collections;
-using Jint.Native.Function;
 using Jint.Native.Object;
 using Jint.Runtime;
 using Jint.Runtime.Descriptors;
@@ -10,7 +9,7 @@ namespace Jint.Native.Proxy
     /// <summary>
     /// https://tc39.es/ecma262/#sec-proxy-constructor
     /// </summary>
-    internal sealed class ProxyConstructor : FunctionInstance, IConstructor
+    internal sealed class ProxyConstructor : Constructor
     {
         private static readonly JsString _name = new JsString("Proxy");
         private static readonly JsString PropertyProxy = new JsString("proxy");
@@ -33,13 +32,7 @@ namespace Jint.Native.Proxy
             SetProperties(properties);
         }
 
-        protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
-        {
-            ExceptionHelper.ThrowTypeError(_realm, "Constructor Proxy requires 'new'");
-            return null;
-        }
-
-        ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget)
+        public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
         {
             if (newTarget.IsUndefined())
             {

+ 3 - 5
Jint/Native/RegExp/RegExpConstructor.cs

@@ -10,7 +10,7 @@ using Jint.Runtime.Interop;
 
 namespace Jint.Native.RegExp
 {
-    public sealed class RegExpConstructor : FunctionInstance, IConstructor
+    public sealed class RegExpConstructor : Constructor
     {
         private static readonly JsString _functionName = new JsString("RegExp");
 
@@ -19,7 +19,7 @@ namespace Jint.Native.RegExp
             Realm realm,
             FunctionPrototype functionPrototype,
             ObjectPrototype objectPrototype)
-            : base(engine, realm, _functionName, FunctionThisMode.Global)
+            : base(engine, realm, _functionName)
         {
             _prototype = functionPrototype;
             PrototypeObject = new RegExpPrototype(engine, realm, this, objectPrototype);
@@ -48,12 +48,10 @@ namespace Jint.Native.RegExp
             return Construct(arguments, this);
         }
 
-        ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget) => Construct(arguments, newTarget);
-
         /// <summary>
         /// https://tc39.es/ecma262/#sec-regexp-pattern-flags
         /// </summary>
-        private ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
+        public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
         {
             var pattern = arguments.At(0);
             var flags = arguments.At(1);

+ 3 - 9
Jint/Native/Set/SetConstructor.cs

@@ -8,7 +8,7 @@ using Jint.Runtime.Interop;
 
 namespace Jint.Native.Set;
 
-internal sealed class SetConstructor : FunctionInstance, IConstructor
+internal sealed class SetConstructor : Constructor
 {
     private static readonly JsString _functionName = new("Set");
 
@@ -17,7 +17,7 @@ internal sealed class SetConstructor : FunctionInstance, IConstructor
         Realm realm,
         FunctionPrototype functionPrototype,
         ObjectPrototype objectPrototype)
-        : base(engine, realm, _functionName, FunctionThisMode.Global)
+        : base(engine, realm, _functionName)
     {
         _prototype = functionPrototype;
         PrototypeObject = new SetPrototype(engine, realm, this, objectPrototype);
@@ -42,16 +42,10 @@ internal sealed class SetConstructor : FunctionInstance, IConstructor
         return thisObject;
     }
 
-    protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
-    {
-        ExceptionHelper.ThrowTypeError(_engine.Realm, "Constructor Set requires 'new'");
-        return null;
-    }
-
     /// <summary>
     /// https://tc39.es/ecma262/#sec-set-iterable
     /// </summary>
-    ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget)
+    public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
     {
         if (newTarget.IsUndefined())
         {

+ 2 - 8
Jint/Native/ShadowRealm/ShadowRealmConstructor.cs

@@ -9,7 +9,7 @@ namespace Jint.Native.ShadowRealm;
 /// <summary>
 /// https://tc39.es/proposal-shadowrealm/#sec-properties-of-the-shadowRealm-constructor
 /// </summary>
-public sealed class ShadowRealmConstructor : FunctionInstance, IConstructor
+public sealed class ShadowRealmConstructor : Constructor
 {
     private static readonly JsString _functionName = new("ShadowRealm");
 
@@ -28,12 +28,6 @@ public sealed class ShadowRealmConstructor : FunctionInstance, IConstructor
 
     private ShadowRealmPrototype PrototypeObject { get; }
 
-    protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
-    {
-        ExceptionHelper.ThrowTypeError(_realm, "Constructor ShadowRealm requires 'new'");
-        return null;
-    }
-
     public ShadowRealm Construct()
     {
         return Construct(PrototypeObject);
@@ -70,7 +64,7 @@ public sealed class ShadowRealmConstructor : FunctionInstance, IConstructor
     }
 
 
-    ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget)
+    public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
     {
         if (newTarget.IsUndefined())
         {

+ 3 - 3
Jint/Native/String/StringConstructor.cs

@@ -13,7 +13,7 @@ namespace Jint.Native.String
     /// <summary>
     /// https://tc39.es/ecma262/#sec-string-constructor
     /// </summary>
-    internal sealed class StringConstructor : FunctionInstance, IConstructor
+    internal sealed class StringConstructor : Constructor
     {
         private static readonly JsString _functionName = new JsString("String");
 
@@ -22,7 +22,7 @@ namespace Jint.Native.String
             Realm realm,
             FunctionPrototype functionPrototype,
             ObjectPrototype objectPrototype)
-            : base(engine, realm, _functionName, FunctionThisMode.Global)
+            : base(engine, realm, _functionName)
         {
             _prototype = functionPrototype;
             PrototypeObject = new StringPrototype(engine, realm, this, objectPrototype);
@@ -165,7 +165,7 @@ namespace Jint.Native.String
         /// <summary>
         /// https://tc39.es/ecma262/#sec-string-constructor-string-value
         /// </summary>
-        ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget)
+        public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
         {
             JsString s;
             if (arguments.Length == 0)

+ 3 - 3
Jint/Native/Symbol/SymbolConstructor.cs

@@ -11,7 +11,7 @@ namespace Jint.Native.Symbol
     /// 19.4
     /// http://www.ecma-international.org/ecma-262/6.0/index.html#sec-symbol-objects
     /// </summary>
-    internal sealed class SymbolConstructor : FunctionInstance, IConstructor
+    internal sealed class SymbolConstructor : Constructor
     {
         private static readonly JsString _functionName = new JsString("Symbol");
 
@@ -20,7 +20,7 @@ namespace Jint.Native.Symbol
             Realm realm,
             FunctionPrototype functionPrototype,
             ObjectPrototype objectPrototype)
-            : base(engine, realm, _functionName, FunctionThisMode.Global)
+            : base(engine, realm, _functionName)
         {
             _prototype = functionPrototype;
             PrototypeObject = new SymbolPrototype(engine, realm, this, objectPrototype);
@@ -107,7 +107,7 @@ namespace Jint.Native.Symbol
             return Undefined;
         }
 
-        ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget)
+        public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
         {
             ExceptionHelper.ThrowTypeError(_realm, "Symbol is not a constructor");
             return null;

+ 3 - 4
Jint/Native/TypedArray/IntrinsicTypedArrayConstructor.cs

@@ -1,5 +1,4 @@
 using Jint.Collections;
-using Jint.Native.Function;
 using Jint.Native.Object;
 using Jint.Native.Symbol;
 using Jint.Runtime;
@@ -11,7 +10,7 @@ namespace Jint.Native.TypedArray
     /// <summary>
     /// https://tc39.es/ecma262/#sec-%typedarray%-intrinsic-object
     /// </summary>
-    internal sealed class IntrinsicTypedArrayConstructor : FunctionInstance, IConstructor
+    internal sealed class IntrinsicTypedArrayConstructor : Constructor
     {
         internal IntrinsicTypedArrayConstructor(
             Engine engine,
@@ -185,11 +184,11 @@ namespace Jint.Native.TypedArray
 
         protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
         {
-            ExceptionHelper.ThrowTypeError(_realm, "Abstract class TypedArray not directly constructable");
+            ExceptionHelper.ThrowTypeError(_realm, "Abstract class TypedArray not directly callable");
             return Undefined;
         }
 
-        ObjectInstance IConstructor.Construct(JsValue[] args, JsValue newTarget)
+        public override ObjectInstance Construct(JsValue[] args, JsValue newTarget)
         {
             ExceptionHelper.ThrowTypeError(_realm, "Abstract class TypedArray not directly constructable");
             return null;

+ 2 - 11
Jint/Native/TypedArray/TypedArrayConstructor.cs

@@ -1,7 +1,6 @@
 using Jint.Collections;
 using Jint.Native.Array;
 using Jint.Native.ArrayBuffer;
-using Jint.Native.Function;
 using Jint.Native.Object;
 using Jint.Native.Symbol;
 using Jint.Runtime;
@@ -12,7 +11,7 @@ namespace Jint.Native.TypedArray
     /// <summary>
     /// https://tc39.es/ecma262/#sec-typedarray-constructors
     /// </summary>
-    public abstract class TypedArrayConstructor : FunctionInstance, IConstructor
+    public abstract class TypedArrayConstructor : Constructor
     {
         private readonly TypedArrayElementType _arrayElementType;
 
@@ -42,15 +41,7 @@ namespace Jint.Native.TypedArray
             SetProperties(properties);
         }
 
-        protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
-        {
-            ExceptionHelper.ThrowTypeError(_realm, "Abstract class TypedArray not directly constructable");
-            return Undefined;
-        }
-
-        ObjectInstance IConstructor.Construct(JsValue[] args, JsValue newTarget) => Construct(args, newTarget);
-
-        internal ObjectInstance Construct(JsValue[] args, JsValue newTarget)
+        public override ObjectInstance Construct(JsValue[] args, JsValue newTarget)
         {
             if (newTarget.IsUndefined())
             {

+ 2 - 8
Jint/Native/WeakMap/WeakMapConstructor.cs

@@ -6,7 +6,7 @@ using Jint.Runtime.Descriptors;
 
 namespace Jint.Native.WeakMap
 {
-    internal sealed class WeakMapConstructor : FunctionInstance, IConstructor
+    internal sealed class WeakMapConstructor : Constructor
     {
         private static readonly JsString _functionName = new JsString("WeakMap");
 
@@ -25,13 +25,7 @@ namespace Jint.Native.WeakMap
 
         public WeakMapPrototype PrototypeObject { get; }
 
-        protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
-        {
-            ExceptionHelper.ThrowTypeError(_realm, "Constructor WeakMap requires 'new'");
-            return null;
-        }
-
-        ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget)
+        public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
         {
             if (newTarget.IsUndefined())
             {

+ 2 - 8
Jint/Native/WeakRef/WeakRefConstructor.cs

@@ -8,7 +8,7 @@ namespace Jint.Native.WeakRef;
 /// <summary>
 /// https://tc39.es/ecma262/#sec-weak-ref-constructor
 /// </summary>
-internal sealed class WeakRefConstructor : FunctionInstance, IConstructor
+internal sealed class WeakRefConstructor : Constructor
 {
     private static readonly JsString _functionName = new("WeakRef");
 
@@ -27,13 +27,7 @@ internal sealed class WeakRefConstructor : FunctionInstance, IConstructor
 
     private WeakRefPrototype PrototypeObject { get; }
 
-    protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
-    {
-        ExceptionHelper.ThrowTypeError(_realm, "Constructor WeakRef requires 'new'");
-        return null;
-    }
-
-    ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget)
+    public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
     {
         if (newTarget.IsUndefined())
         {

+ 2 - 8
Jint/Native/WeakSet/WeakSetConstructor.cs

@@ -5,7 +5,7 @@ using Jint.Runtime.Descriptors;
 
 namespace Jint.Native.WeakSet
 {
-    internal sealed class WeakSetConstructor : FunctionInstance, IConstructor
+    internal sealed class WeakSetConstructor : Constructor
     {
         private static readonly JsString _functionName = new("WeakSet");
 
@@ -24,13 +24,7 @@ namespace Jint.Native.WeakSet
 
         private WeakSetPrototype PrototypeObject { get; }
 
-        protected internal override JsValue Call(JsValue thisObject, JsValue[] arguments)
-        {
-            ExceptionHelper.ThrowTypeError(_realm, "Constructor WeakSet requires 'new'");
-            return null;
-        }
-
-        ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget)
+        public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
         {
             if (newTarget.IsUndefined())
             {

+ 3 - 6
Jint/Runtime/Interop/TypeReference.cs

@@ -2,14 +2,13 @@ using System.Collections.Concurrent;
 using System.Reflection;
 using Jint.Collections;
 using Jint.Native;
-using Jint.Native.Function;
 using Jint.Native.Object;
 using Jint.Runtime.Descriptors;
 using Jint.Runtime.Interop.Reflection;
 
 namespace Jint.Runtime.Interop
 {
-    public sealed class TypeReference : FunctionInstance, IConstructor, IObjectWrapper
+    public sealed class TypeReference : Constructor, IObjectWrapper
     {
         private static readonly JsString _name = new("typereference");
         private static readonly ConcurrentDictionary<Type, MethodDescriptor[]> _constructorCache = new();
@@ -18,7 +17,7 @@ namespace Jint.Runtime.Interop
         private readonly record struct MemberAccessorKey(Type Type, string PropertyName);
 
         private TypeReference(Engine engine, Type type)
-            : base(engine, engine.Realm, _name, FunctionThisMode.Global)
+            : base(engine, engine.Realm, _name)
         {
             ReferenceType = type;
 
@@ -49,9 +48,7 @@ namespace Jint.Runtime.Interop
             return Construct(arguments, Undefined);
         }
 
-        ObjectInstance IConstructor.Construct(JsValue[] arguments, JsValue newTarget) => Construct(arguments, newTarget);
-
-        private ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
+        public override ObjectInstance Construct(JsValue[] arguments, JsValue newTarget)
         {
             static ObjectInstance ObjectCreator(Engine engine, Realm realm, ObjectCreateState state)
             {

+ 1 - 1
Jint/Runtime/Intrinsics.cs

@@ -256,7 +256,7 @@ namespace Jint.Runtime
         internal ErrorConstructor SyntaxError =>
             _syntaxError ??= new ErrorConstructor(_engine, _realm, Error, Error.PrototypeObject, _syntaxErrorFunctionName, static intrinsics => intrinsics.SyntaxError.PrototypeObject);
 
-        internal ErrorConstructor TypeError =>
+        public ErrorConstructor TypeError =>
             _typeError ??= new ErrorConstructor(_engine, _realm, Error, Error.PrototypeObject, _typeErrorFunctionName, static intrinsics => intrinsics.TypeError.PrototypeObject);
 
         internal ErrorConstructor RangeError =>