public override Completion GetValue(EvaluationContext context)
        {
            // need to notify correct node when taking shortcut
            context.LastSyntaxNode = _expression;

            if (_calculatedValue is not null)
            {
                return(Completion.Normal(_calculatedValue, _expression.Location));
            }

            var strict = StrictModeScope.IsStrictModeCode;
            var engine = context.Engine;
            var env    = engine.ExecutionContext.LexicalEnvironment;

            if (JintEnvironment.TryGetIdentifierEnvironmentWithBindingValue(
                    env,
                    _expressionName,
                    strict,
                    out _,
                    out var value))
            {
                if (value is null)
                {
                    ExceptionHelper.ThrowReferenceError(engine.Realm, _expressionName.Key.Name + " has not been initialized");
                }
            }
            else
            {
                var reference = engine._referencePool.Rent(JsValue.Undefined, _expressionName.StringValue, strict, thisValue: null);
                value = engine.GetValue(reference, true);
            }

            // make sure arguments access freezes state
            if (value is ArgumentsInstance argumentsInstance)
            {
                argumentsInstance.Materialize();
            }

            return(Completion.Normal(value, _expression.Location));
        }
        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));
        }
        private JsValue UpdateIdentifier(EvaluationContext context)
        {
            var strict = StrictModeScope.IsStrictModeCode;
            var name   = _leftIdentifier._expressionName;
            var engine = context.Engine;
            var env    = engine.ExecutionContext.LexicalEnvironment;

            if (JintEnvironment.TryGetIdentifierEnvironmentWithBindingValue(
                    env,
                    name,
                    strict,
                    out var environmentRecord,
                    out var value))
            {
                if (strict && _evalOrArguments)
                {
                    ExceptionHelper.ThrowSyntaxError(engine.Realm);
                }

                var isInteger = value._type == InternalTypes.Integer;

                JsValue newValue = null;

                var operatorOverloaded = false;
                if (context.OperatorOverloadingAllowed)
                {
                    if (JintUnaryExpression.TryOperatorOverloading(context, _argument.GetValue(context).Value, _change > 0 ? "op_Increment" : "op_Decrement", out var result))
                    {
                        operatorOverloaded = true;
                        newValue           = result;
                    }
                }

                if (!operatorOverloaded)
                {
                    if (isInteger)
                    {
                        newValue = JsNumber.Create(value.AsInteger() + _change);
                    }
                    else if (value._type != InternalTypes.BigInt)
                    {
                        newValue = JsNumber.Create(TypeConverter.ToNumber(value) + _change);
                    }
                    else
                    {
                        newValue = JsBigInt.Create(TypeConverter.ToBigInt(value) + _change);
                    }
                }

                environmentRecord.SetMutableBinding(name.Key.Name, newValue, strict);
                if (_prefix)
                {
                    return(newValue);
                }

                if (!value.IsBigInt() && !value.IsNumber() && !operatorOverloaded)
                {
                    return(JsNumber.Create(TypeConverter.ToNumber(value)));
                }

                return(value);
            }

            return(null);
        }