|
@@ -1,6 +1,7 @@
|
|
using Jint.Collections;
|
|
using Jint.Collections;
|
|
using Jint.Native.Array;
|
|
using Jint.Native.Array;
|
|
using Jint.Native.Object;
|
|
using Jint.Native.Object;
|
|
|
|
+using Jint.Native.Symbol;
|
|
using Jint.Runtime;
|
|
using Jint.Runtime;
|
|
using Jint.Runtime.Descriptors;
|
|
using Jint.Runtime.Descriptors;
|
|
using Jint.Runtime.Interop;
|
|
using Jint.Runtime.Interop;
|
|
@@ -12,10 +13,8 @@ namespace Jint.Native.Function
|
|
/// </summary>
|
|
/// </summary>
|
|
public sealed class FunctionPrototype : FunctionInstance
|
|
public sealed class FunctionPrototype : FunctionInstance
|
|
{
|
|
{
|
|
- private static readonly JsString _functionName = new JsString("Function");
|
|
|
|
-
|
|
|
|
private FunctionPrototype(Engine engine)
|
|
private FunctionPrototype(Engine engine)
|
|
- : base(engine, _functionName)
|
|
|
|
|
|
+ : base(engine, JsString.Empty)
|
|
{
|
|
{
|
|
}
|
|
}
|
|
|
|
|
|
@@ -33,57 +32,96 @@ namespace Jint.Native.Function
|
|
|
|
|
|
protected override void Initialize()
|
|
protected override void Initialize()
|
|
{
|
|
{
|
|
- var properties = new PropertyDictionary(5, checkExistingKeys: false)
|
|
|
|
|
|
+ const PropertyFlag propertyFlags = PropertyFlag.Configurable | PropertyFlag.Writable;
|
|
|
|
+ const PropertyFlag lengthFlags = PropertyFlag.Configurable;
|
|
|
|
+ var properties = new PropertyDictionary(7, checkExistingKeys: false)
|
|
{
|
|
{
|
|
["constructor"] = new PropertyDescriptor(Engine.Function, PropertyFlag.NonEnumerable),
|
|
["constructor"] = new PropertyDescriptor(Engine.Function, PropertyFlag.NonEnumerable),
|
|
- ["toString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toString", ToString), true, false, true),
|
|
|
|
- ["apply"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "apply", Apply, 2), true, false, true),
|
|
|
|
- ["call"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "call", CallImpl, 1), true, false, true),
|
|
|
|
- ["bind"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "bind", Bind, 1), true, false, true)
|
|
|
|
|
|
+ ["toString"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "toString", ToString, 0, lengthFlags), propertyFlags),
|
|
|
|
+ ["apply"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "apply", Apply, 2, lengthFlags), propertyFlags),
|
|
|
|
+ ["call"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "call", CallImpl, 1, lengthFlags), propertyFlags),
|
|
|
|
+ ["bind"] = new PropertyDescriptor(new ClrFunctionInstance(Engine, "bind", Bind, 1, PropertyFlag.AllForbidden), propertyFlags),
|
|
|
|
+ ["arguments"] = _engine._callerCalleeArgumentsThrowerConfigurable,
|
|
|
|
+ ["caller"] = _engine._callerCalleeArgumentsThrowerConfigurable
|
|
};
|
|
};
|
|
SetProperties(properties);
|
|
SetProperties(properties);
|
|
|
|
+
|
|
|
|
+ var symbols = new SymbolDictionary(1)
|
|
|
|
+ {
|
|
|
|
+ [GlobalSymbolRegistry.HasInstance] = new PropertyDescriptor(new ClrFunctionInstance(_engine, "[Symbol.hasInstance]", HasInstance, 1, PropertyFlag.Configurable), PropertyFlag.AllForbidden)
|
|
|
|
+ };
|
|
|
|
+ SetSymbols(symbols);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private static JsValue HasInstance(JsValue thisObj, JsValue[] arguments)
|
|
|
|
+ {
|
|
|
|
+ if (!(thisObj is FunctionInstance f))
|
|
|
|
+ {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return f.HasInstance(arguments.At(0));
|
|
}
|
|
}
|
|
|
|
|
|
private JsValue Bind(JsValue thisObj, JsValue[] arguments)
|
|
private JsValue Bind(JsValue thisObj, JsValue[] arguments)
|
|
{
|
|
{
|
|
- var target = thisObj.TryCast<ICallable>(x =>
|
|
|
|
|
|
+ if (!(thisObj is ICallable))
|
|
{
|
|
{
|
|
- ExceptionHelper.ThrowTypeError(Engine);
|
|
|
|
- });
|
|
|
|
|
|
+ ExceptionHelper.ThrowTypeError(Engine, "Bind must be called on a function");
|
|
|
|
+ }
|
|
|
|
|
|
var thisArg = arguments.At(0);
|
|
var thisArg = arguments.At(0);
|
|
var f = new BindFunctionInstance(Engine)
|
|
var f = new BindFunctionInstance(Engine)
|
|
{
|
|
{
|
|
TargetFunction = thisObj,
|
|
TargetFunction = thisObj,
|
|
- BoundThis = thisArg,
|
|
|
|
|
|
+ BoundThis = thisObj is ArrowFunctionInstance ? Undefined : thisArg,
|
|
BoundArgs = arguments.Skip(1),
|
|
BoundArgs = arguments.Skip(1),
|
|
- _prototype = Engine.Function.PrototypeObject
|
|
|
|
|
|
+ _prototype = Engine.Function.PrototypeObject,
|
|
};
|
|
};
|
|
|
|
|
|
- if (target is FunctionInstance functionInstance)
|
|
|
|
|
|
+ JsNumber l;
|
|
|
|
+ var targetHasLength = thisObj.HasOwnProperty(CommonProperties.Length);
|
|
|
|
+ if (targetHasLength)
|
|
{
|
|
{
|
|
- var l = TypeConverter.ToNumber(functionInstance.Get(CommonProperties.Length, functionInstance)) - (arguments.Length - 1);
|
|
|
|
- f.SetOwnProperty(CommonProperties.Length, new PropertyDescriptor(System.Math.Max(l, 0), PropertyFlag.AllForbidden));
|
|
|
|
|
|
+ var targetLen = thisObj.Get(CommonProperties.Length);
|
|
|
|
+ if (!targetLen.IsNumber())
|
|
|
|
+ {
|
|
|
|
+ l = JsNumber.PositiveZero;
|
|
|
|
+ }
|
|
|
|
+ else
|
|
|
|
+ {
|
|
|
|
+ targetLen = TypeConverter.ToInteger(targetLen);
|
|
|
|
+ // first argument is target
|
|
|
|
+ var argumentsLength = System.Math.Max(0, arguments.Length - 1);
|
|
|
|
+ l = JsNumber.Create((uint) System.Math.Max(((JsNumber) targetLen)._value - argumentsLength, 0));
|
|
|
|
+ }
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
- f.SetOwnProperty(CommonProperties.Length, PropertyDescriptor.AllForbiddenDescriptor.NumberZero);
|
|
|
|
|
|
+ l = JsNumber.PositiveZero;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ f._length = new PropertyDescriptor(l, PropertyFlag.Configurable);
|
|
|
|
+
|
|
|
|
+ var targetName = thisObj.Get(CommonProperties.Name);
|
|
|
|
+ if (!targetName.IsString())
|
|
|
|
+ {
|
|
|
|
+ targetName = JsString.Empty;
|
|
}
|
|
}
|
|
|
|
|
|
- f.DefineOwnProperty(CommonProperties.Caller, _engine._getSetThrower);
|
|
|
|
- f.DefineOwnProperty(CommonProperties.Arguments, _engine._getSetThrower);
|
|
|
|
|
|
+ f.SetFunctionName(targetName, "bound");
|
|
|
|
|
|
return f;
|
|
return f;
|
|
}
|
|
}
|
|
|
|
|
|
private JsValue ToString(JsValue thisObj, JsValue[] arguments)
|
|
private JsValue ToString(JsValue thisObj, JsValue[] arguments)
|
|
{
|
|
{
|
|
- if (!(thisObj is FunctionInstance))
|
|
|
|
|
|
+ if (thisObj.IsObject() && thisObj.IsCallable)
|
|
{
|
|
{
|
|
- return ExceptionHelper.ThrowTypeError<FunctionInstance>(_engine, "Function object expected.");
|
|
|
|
|
|
+ return thisObj.ToString();
|
|
}
|
|
}
|
|
|
|
|
|
- return "function() {{ ... }}";
|
|
|
|
|
|
+ return ExceptionHelper.ThrowTypeError<FunctionInstance>(_engine, "Function.prototype.toString requires that 'this' be a Function");
|
|
}
|
|
}
|
|
|
|
|
|
internal JsValue Apply(JsValue thisObject, JsValue[] arguments)
|
|
internal JsValue Apply(JsValue thisObject, JsValue[] arguments)
|