/// <summary> /// https://tc39.es/ecma262/#sec-ordinarycallbindthis /// </summary> internal void OrdinaryCallBindThis(ExecutionContext calleeContext, JsValue thisArgument) { var thisMode = _thisMode; if (thisMode == FunctionThisMode.Lexical) { return; } var calleeRealm = _realm; var localEnv = (FunctionEnvironmentRecord)calleeContext.LexicalEnvironment; JsValue thisValue; if (_thisMode == FunctionThisMode.Strict) { thisValue = thisArgument; } else { if (thisArgument is null || thisArgument.IsNullOrUndefined()) { var globalEnv = calleeRealm.GlobalEnv; thisValue = globalEnv.GlobalThisValue; }
public static string ConvertToString(this JsValue self) { if (self.IsNullOrUndefined()) { return(null); } return(TypeConverter.ToString(self)); }
public static double?ConvertToDouble(this JsValue self) { if (self.IsNullOrUndefined()) { return(null); } return(TypeConverter.ToNumber(self)); }
public static long?ConvertToInt64(this JsValue self) { if (self.IsNullOrUndefined()) { return(null); } return((long)TypeConverter.ToInteger(self)); }
public static int?ConvertToInt32(this JsValue self) { if (self.IsNullOrUndefined()) { return(null); } return(TypeConverter.ToInt32(self)); }
public static bool?ConvertToBoolean(this JsValue self) { if (self.IsNullOrUndefined()) { return(null); } return(TypeConverter.ToBoolean(self)); }
private JsValue Fill(JsValue thisObj, JsValue[] arguments) { if (thisObj.IsNullOrUndefined()) { ExceptionHelper.ThrowTypeError(_engine, "Cannot convert undefined or null to object"); } var operations = ArrayOperations.For(thisObj as ObjectInstance); var length = operations.GetLength(); var value = arguments.At(0); var start = ConvertAndCheckForInfinity(arguments.At(1), 0); var relativeStart = TypeConverter.ToInteger(start); uint actualStart; if (relativeStart < 0) { actualStart = (uint)System.Math.Max(length + relativeStart, 0); } else { actualStart = (uint)System.Math.Min(relativeStart, length); } var end = ConvertAndCheckForInfinity(arguments.At(2), length); var relativeEnd = TypeConverter.ToInteger(end); uint actualEnd; if (relativeEnd < 0) { actualEnd = (uint)System.Math.Max(length + relativeEnd, 0); } else { actualEnd = (uint)System.Math.Min(relativeEnd, length); } for (var i = actualStart; i < actualEnd; ++i) { operations.Set(i, value, updateLength: false, throwOnError: false); } return(thisObj); }
private JsValue CopyWithin(JsValue thisObj, JsValue[] arguments) { // Steps 1-2. if (thisObj.IsNullOrUndefined()) { return(ExceptionHelper.ThrowTypeError <JsValue>(_engine, "this is null or not defined")); } JsValue target = arguments.At(0); JsValue start = arguments.At(1); JsValue end = arguments.At(2); var operations = ArrayOperations.For(thisObj as ObjectInstance); var initialLength = operations.GetLength(); var len = ConvertAndCheckForInfinity(initialLength, 0); var relativeTarget = ConvertAndCheckForInfinity(target, 0); var to = relativeTarget < 0 ? System.Math.Max(len + relativeTarget, 0) : System.Math.Min(relativeTarget, len); var relativeStart = ConvertAndCheckForInfinity(start, 0); var from = relativeStart < 0 ? System.Math.Max(len + relativeStart, 0) : System.Math.Min(relativeStart, len); var relativeEnd = ConvertAndCheckForInfinity(end, len); var final = relativeEnd < 0 ? System.Math.Max(len + relativeEnd, 0) : System.Math.Min(relativeEnd, len); var count = System.Math.Min(final - from, len - to); var direction = 1; if (from < to && to < from + count) { direction = -1; from += (uint)count - 1; to += (uint)count - 1; } while (count > 0) { var fromPresent = operations.HasProperty((ulong)from); if (fromPresent) { var fromValue = operations.Get((ulong)from); operations.Set((ulong)to, fromValue, updateLength: true, throwOnError: true); } else { operations.DeletePropertyOrThrow((ulong)to); } from = (uint)(from + direction); to = (uint)(to + direction); count--; } return(thisObj); }
protected override ExpressionResult EvaluateInternal(EvaluationContext context) { JsValue actualThis = null; string baseReferenceName = null; JsValue baseValue = null; var isStrictModeCode = StrictModeScope.IsStrictModeCode; var engine = context.Engine; if (_objectExpression is JintIdentifierExpression identifierExpression) { baseReferenceName = identifierExpression._expressionName.Key.Name; var strict = isStrictModeCode; var env = engine.ExecutionContext.LexicalEnvironment; JintEnvironment.TryGetIdentifierEnvironmentWithBindingValue( env, identifierExpression._expressionName, strict, out _, out baseValue); } else if (_objectExpression is JintThisExpression thisExpression) { baseValue = thisExpression.GetValue(context).Value; } else if (_objectExpression is JintSuperExpression) { var env = (FunctionEnvironmentRecord)engine.ExecutionContext.GetThisEnvironment(); actualThis = env.GetThisBinding(); baseValue = env.GetSuperBase(); } if (baseValue is null) { // fast checks failed var baseReference = _objectExpression.Evaluate(context).Value; if (ReferenceEquals(Undefined.Instance, baseReference)) { return(NormalCompletion(Undefined.Instance)); } if (baseReference is Reference reference) { baseReferenceName = reference.GetReferencedName().ToString(); baseValue = engine.GetValue(reference, false); engine._referencePool.Return(reference); } else { baseValue = engine.GetValue(baseReference, false); } } if (baseValue.IsNullOrUndefined() && (_memberExpression.Optional || _objectExpression._expression.IsOptional())) { return(NormalCompletion(Undefined.Instance)); } var property = _determinedProperty ?? _propertyExpression.GetValue(context).Value; if (baseValue.IsNullOrUndefined()) { // we can use base data types securely, object evaluation can mess things up var referenceName = property.IsPrimitive() ? TypeConverter.ToString(property) : _determinedProperty?.ToString() ?? baseReferenceName; TypeConverter.CheckObjectCoercible(engine, baseValue, _memberExpression.Property, referenceName); } // only convert if necessary var propertyKey = property.IsInteger() && baseValue.IsIntegerIndexedArray ? property : TypeConverter.ToPropertyKey(property); var rent = context.Engine._referencePool.Rent(baseValue, propertyKey, isStrictModeCode, thisValue: actualThis); return(new ExpressionResult( ExpressionCompletionType.Reference, rent, _expression.Location)); }
/// <summary> /// https://tc39.es/ecma262/#sec-ecmascript-function-objects-call-thisargument-argumentslist /// </summary> public override JsValue Call(JsValue thisArgument, JsValue[] arguments) { // ** PrepareForOrdinaryCall ** // var callerContext = _engine.ExecutionContext; // Let calleeRealm be F.[[Realm]]. // Set the Realm of calleeContext to calleeRealm. // Set the ScriptOrModule of calleeContext to F.[[ScriptOrModule]]. var localEnv = LexicalEnvironment.NewFunctionEnvironment(_engine, this, Undefined); // If callerContext is not already suspended, suspend callerContext. // Push calleeContext onto the execution context stack; calleeContext is now the running execution context. // NOTE: Any exception objects produced after this point are associated with calleeRealm. // Return calleeContext. _engine.EnterExecutionContext(localEnv, localEnv); // ** OrdinaryCallBindThis ** JsValue thisValue; if (_thisMode == FunctionThisMode.Strict) { thisValue = thisArgument; } else { if (thisArgument.IsNullOrUndefined()) { var globalEnv = _engine.GlobalEnvironment; var globalEnvRec = (GlobalEnvironmentRecord)globalEnv._record; thisValue = globalEnvRec.GlobalThisValue; } else { thisValue = TypeConverter.ToObject(_engine, thisArgument); } } var envRec = (FunctionEnvironmentRecord)localEnv._record; envRec.BindThisValue(thisValue); // actual call var strict = _thisMode == FunctionThisMode.Strict || _engine._isStrict; using (new StrictModeScope(strict, true)) { try { var argumentsInstance = _engine.FunctionDeclarationInstantiation( functionInstance: this, arguments, localEnv); var result = _function.Execute(); var value = result.GetValueOrDefault().Clone(); argumentsInstance?.FunctionWasCalled(); if (result.Type == CompletionType.Throw) { ExceptionHelper.ThrowJavaScriptException(_engine, value, result); } if (result.Type == CompletionType.Return) { return(value); } } finally { _engine.LeaveExecutionContext(); } return(Undefined); } }