using System.Runtime.CompilerServices; using Esprima.Ast; using Jint.Runtime; using Jint.Runtime.Descriptors; using Jint.Runtime.Environments; using Jint.Runtime.Interpreter; namespace Jint.Native.Function { public sealed class ArrowFunctionInstance : FunctionInstance { private readonly JintFunctionDefinition _function; private readonly JsValue _thisBinding; /// /// 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, (string) null, function._parameterNames, scope, strict) { _function = function; Extensible = false; Prototype = Engine.Function.PrototypeObject; _length = new PropertyDescriptor(JsNumber.Create(function._length), PropertyFlag.Configurable); _thisBinding = _engine.ExecutionContext.ThisBinding; } // 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 localEnv = LexicalEnvironment.NewDeclarativeEnvironment(_engine, _scope); var strict = Strict || _engine._isStrict; using (new StrictModeScope(strict, true)) { _engine.EnterExecutionContext( localEnv, localEnv, _thisBinding); try { var argumentInstanceRented = _engine.DeclarationBindingInstantiation( DeclarationBindingType.FunctionCode, _function._hoistingScope, functionInstance: this, arguments); var result = _function._body.Execute(); var value = result.GetValueOrDefault(); if (argumentInstanceRented) { _engine.ExecutionContext.LexicalEnvironment?._record?.FunctionWasCalled(); _engine.ExecutionContext.VariableEnvironment?._record?.FunctionWasCalled(); } if (result.Type == CompletionType.Throw) { ExceptionHelper.ThrowJavaScriptException(_engine, value, result); } if (result.Type == CompletionType.Return) { return value; } } finally { _engine.LeaveExecutionContext(); } return Undefined; } } public override void Put(in Key propertyName, JsValue value, bool throwOnError) { AssertValidPropertyName(propertyName); base.Put(propertyName, value, throwOnError); } public override JsValue Get(in Key propertyName) { AssertValidPropertyName(propertyName); return base.Get(propertyName); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void AssertValidPropertyName(in Key propertyName) { if (propertyName == KnownKeys.Caller || propertyName == KnownKeys.Callee || propertyName == KnownKeys.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"); } } } }