using System.Runtime.CompilerServices;
using Esprima.Ast;
using Jint.Runtime;
using Jint.Runtime.Descriptors;
using Jint.Runtime.Descriptors.Specialized;
using Jint.Runtime.Environments;
using Jint.Runtime.Interpreter;
namespace Jint.Native.Function
{
public sealed class ArrowFunctionInstance : FunctionInstance
{
private readonly JintFunctionDefinition _function;
///
/// http://www.ecma-international.org/ecma-262/6.0/#sec-arrow-function-definitions
///
public ArrowFunctionInstance(
Engine engine,
IFunction functionDeclaration,
LexicalEnvironment scope,
bool strict)
: this(engine, new JintFunctionDefinition(engine, functionDeclaration), scope, strict)
{
}
internal ArrowFunctionInstance(
Engine engine,
JintFunctionDefinition function,
LexicalEnvironment scope,
bool strict)
: base(engine, function, scope, strict ? FunctionThisMode.Strict : FunctionThisMode.Lexical)
{
_function = function;
PreventExtensions();
_prototype = Engine.Function.PrototypeObject;
_length = new LazyPropertyDescriptor(() => JsNumber.Create(function.Initialize(engine, this).Length), PropertyFlag.Configurable);
}
// for example RavenDB wants to inspect this
public IFunction FunctionDeclaration => _function.Function;
///
/// http://www.ecma-international.org/ecma-262/5.1/#sec-13.2.1
///
public override JsValue Call(JsValue thisArg, JsValue[] arguments)
{
var strict = Strict || _engine._isStrict;
using (new StrictModeScope(strict, true))
{
var localEnv = LexicalEnvironment.NewFunctionEnvironment(_engine, this, Undefined);
_engine.EnterExecutionContext(localEnv, localEnv);
try
{
_engine.FunctionDeclarationInstantiation(
functionInstance: this,
arguments,
localEnv);
var result = _function.Body.Execute();
var value = result.GetValueOrDefault().Clone();
if (result.Type == CompletionType.Throw)
{
ExceptionHelper.ThrowJavaScriptException(_engine, value, result);
}
if (result.Type == CompletionType.Return)
{
return value;
}
}
finally
{
_engine.LeaveExecutionContext();
}
return Undefined;
}
}
public override bool Set(JsValue property, JsValue value, JsValue receiver)
{
AssertValidPropertyName(property);
return base.Set(property, value, receiver);
}
public override JsValue Get(JsValue property, JsValue receiver)
{
AssertValidPropertyName(property);
return base.Get(property, receiver);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void AssertValidPropertyName(JsValue property)
{
if (property == CommonProperties.Caller
|| property == CommonProperties.Callee
|| property == CommonProperties.Arguments)
{
ExceptionHelper.ThrowTypeError(_engine, "'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them");
}
}
}
}