/// <inheritdoc />
        protected override EvaluationResult DoEval(Context context, ModuleLiteral env, EvaluationStackFrame frame)
        {
            Contract.Assume(frame.Length > Index);

            // By construction, the above preconditions should hold.
            try
            {
                // All operations should be in the checked context to fail on overflow!
                checked
                {
                    var oldValue = Converter.ExpectNumber(frame[Index], position: 0);
                    switch (OperatorKind)
                    {
                    case IncrementDecrementOperator.PrefixIncrement:
                    {
                        var newValue = NumberLiteral.Box(oldValue + 1);
                        frame[Index] = newValue;
                        return(newValue);
                    }

                    case IncrementDecrementOperator.PostfixIncrement:
                    {
                        var newValue = NumberLiteral.Box(oldValue + 1);
                        frame[Index] = newValue;
                        return(EvaluationResult.Create(oldValue));
                    }

                    case IncrementDecrementOperator.PrefixDecrement:
                    {
                        var newValue = NumberLiteral.Box(oldValue - 1);
                        frame[Index] = newValue;
                        return(newValue);
                    }

                    case IncrementDecrementOperator.PostfixDecrement:
                    {
                        var newValue = NumberLiteral.Box(oldValue - 1);
                        frame[Index] = newValue;
                        return(EvaluationResult.Create(oldValue));
                    }

                    default:
                        var message = I($"Unknown operator kind '{OperatorKind}'");
                        Contract.Assert(false, message);
                        throw new InvalidOperationException(message);
                    }
                }
            }
            catch (OverflowException)
            {
                context.Logger.ReportArithmeticOverflow(context.LoggingContext, LocationForLogging(context, env), this.ToDisplayString(context));
            }
            catch (ConvertException exception)
            {
                context.Errors.ReportUnexpectedValueTypeForName(env, Operand, exception.ExpectedTypesToString(context), exception.Value, Location);
            }

            return(EvaluationResult.Error);
        }
Esempio n. 2
0
        /// <inheritdoc />
        protected override EvaluationResult DoEval(Context context, ModuleLiteral env, EvaluationStackFrame frame)
        {
            Contract.Assume(frame.Length > Index);

            // By construction, the above preconditions should hold.
            var value = RightExpression.Eval(context, env, frame);

            if (value.IsErrorValue)
            {
                return(EvaluationResult.Error);
            }

            if (OperatorKind == AssignmentOperator.Assignment)
            {
                frame[Index] = value;
                return(frame[Index]);
            }

            try
            {
                // All operations should be in the checked context to fail on overflow!
                checked
                {
                    var arg = frame[Index];

                    switch (OperatorKind)
                    {
                    case AssignmentOperator.AdditionAssignment:
                        if (Converter.TryGet <int>(arg, out int lIntValue) && Converter.TryGet <int>(value, out int rIntValue))
                        {
                            frame[Index] = NumberLiteral.Box(lIntValue + rIntValue);
                            break;
                        }
                        else if (Converter.TryGet <string>(arg, out string lStrValue) && Converter.TryGet <string>(value, out string rStrValue))
                        {
                            frame[Index] = EvaluationResult.Create(lStrValue + rStrValue);
                            break;
                        }

                        throw Converter.CreateException <int>(value, context: new ConversionContext(pos: Index));

                    case AssignmentOperator.SubtractionAssignment:
                        frame[Index] = NumberLiteral.Box(Converter.ExpectNumber(arg, position: 0) - Converter.ExpectNumber(value, position: 1));
                        break;

                    case AssignmentOperator.MultiplicationAssignment:
                        frame[Index] = NumberLiteral.Box(Converter.ExpectNumber(arg, position: 0) * Converter.ExpectNumber(value, position: 1));
                        break;

                    case AssignmentOperator.RemainderAssignment:
                        frame[Index] = NumberLiteral.Box(Converter.ExpectNumber(arg, position: 0) % Converter.ExpectNumber(value, position: 1));
                        break;

                    case AssignmentOperator.ExponentiationAssignment:
                        frame[Index] = NumberOperations.Power(
                            context,
                            Converter.ExpectNumber(arg, position: 0),
                            Converter.ExpectNumber(value, position: 1), LocationForLogging(context, env));
                        break;

                    case AssignmentOperator.LeftShiftAssignment:
                        frame[Index] = NumberLiteral.Box(Converter.ExpectNumber(frame[Index], position: 0) << Converter.ExpectNumber(value, position: 1));
                        break;

                    case AssignmentOperator.RightShiftAssignment:
                        frame[Index] = NumberLiteral.Box(NumberOperations.SignPropagatingRightShift(
                                                             Converter.ExpectNumber(arg, position: 0),
                                                             Converter.ExpectNumber(value, position: 1)).Value);
                        break;

                    case AssignmentOperator.UnsignedRightShiftAssignment:
                        frame[Index] = NumberLiteral.Box(NumberOperations.ZeroFillingRightShift(
                                                             Converter.ExpectNumber(arg, position: 0),
                                                             Converter.ExpectNumber(value, position: 1)).Value);
                        break;

                    case AssignmentOperator.BitwiseAndAssignment:
                        frame[Index] =
                            Converter.ToEnumValueIfNeeded(
                                arg.GetType(),
                                Converter.ExpectNumberOrEnum(arg, position: 0) & Converter.ExpectNumberOrEnum(value, position: 1));
                        break;

                    case AssignmentOperator.BitwiseXorAssignment:
                        frame[Index] =
                            Converter.ToEnumValueIfNeeded(
                                arg.GetType(),
                                Converter.ExpectNumberOrEnum(arg, position: 0) ^ Converter.ExpectNumberOrEnum(value, position: 1));
                        break;

                    case AssignmentOperator.BitwiseOrAssignment:
                        frame[Index] =
                            Converter.ToEnumValueIfNeeded(
                                arg.GetType(),
                                Converter.ExpectNumberOrEnum(arg, position: 0) | Converter.ExpectNumberOrEnum(value, position: 1));
                        break;

                    default:
                        var message = I($"Unknown operator kind '{OperatorKind}'");
                        Contract.Assert(false, message);
                        throw new InvalidOperationException(message);
                    }
                }

                return(frame[Index]);
            }
            catch (OverflowException)
            {
                context.Logger.ReportArithmeticOverflow(context.LoggingContext, LocationForLogging(context, env), this.ToDisplayString(context));
            }
            catch (ConvertException exception)
            {
                if (exception.ErrorContext.Pos == 0)
                {
                    context.Errors.ReportUnexpectedValueTypeForName(env, LeftExpression, exception.ExpectedTypesToString(context), exception.Value, Location);
                }
                else
                {
                    context.Errors.ReportUnexpectedValueType(env, RightExpression, exception.Value, exception.ExpectedTypesToString(context));
                }
            }

            return(EvaluationResult.Error);
        }