public override void Function()
        {
            switch (Operation)
            {
            case ArithmeticOperation.SUM:
                Value = Val1 + Val2;
                break;

            case ArithmeticOperation.SUBTRACT:
                Value = Val1 - Val2;
                break;

            case ArithmeticOperation.MULTIPLY:
                Value = Val1 * Val2;
                break;

            case ArithmeticOperation.DIVIDE:
                try
                {
                    Value = Val1 / Val2;
                }catch (DivideByZeroException ex)
                {
                    DivisionByZeroException exx = new DivisionByZeroException();
                    exx.blox = this.NodeBlox;
                    throw exx;
                }
                break;
            }
        }
        private Lazy <object> VisitArithmeticExpression(ParserRuleContext context, ParserRuleContext op,
                                                        ParserRuleContext left, ParserRuleContext right)
        {
            var expressionType = _scriptEnvironmentBuilder.TypeInferenceVisitor.Visit(context);

            if (!TypeUtil.IsNumeric(expressionType) && expressionType != ObjectType.String)
            {
                _scriptEnvironmentBuilder.Errors.Add(
                    new InvalidOperandsException(
                        context,
                        op.GetText(),
                        _scriptEnvironmentBuilder.TypeInferenceVisitor.Visit(left),
                        _scriptEnvironmentBuilder.TypeInferenceVisitor.Visit(right)));

                return(new Lazy <object>(() => null));
            }

            return(new Lazy <object>(() =>
            {
                var leftValue = left.Accept(this).GetValueOrLazyValue();
                var rightValue = right.Accept(this).GetValueOrLazyValue();

                if (op.GetText() == "+")
                {
                    //maybe we have string concatenation?
                    if (leftValue is string leftStr)
                    {
                        return leftStr + rightValue;
                    }
                    if (rightValue is string rightStr)
                    {
                        return leftValue + rightStr;
                    }
                }

                if (!(leftValue is int) && !(leftValue is double) ||
                    !(rightValue is int) && !(rightValue is double))
                {
                    return null;
                }

                bool TryConvertToNumber(object value, out double result)
                {
                    result = 0;
                    try
                    {
                        result = Convert.ToDouble(value);
                    }
                    catch (InvalidCastException e)
                    {
                        Errors.Add(new FailedToInferTypeException(context, left, e));
                        return false;
                    }

                    return true;
                }

                if (!TryConvertToNumber(leftValue, out var leftValueAsNumber))
                {
                    return null;
                }

                if (!TryConvertToNumber(rightValue, out var rightValueAsNumber))
                {
                    return null;
                }

                switch (op.GetText())
                {
                case "+":
                    return Cast(leftValueAsNumber + rightValueAsNumber, expressionType);

                case "-":
                    return Cast(leftValueAsNumber - rightValueAsNumber, expressionType);

                case "/":
                    if (Math.Abs(rightValueAsNumber) < 0.00000000001)     //epsilon :)
                    {
                        var error = new DivisionByZeroException(context);
                        Errors.Add(error);
                    }

                    var val = leftValueAsNumber / rightValueAsNumber;

                    return Cast(val, expressionType);

                case "%":
                    return Cast(leftValueAsNumber % rightValueAsNumber, expressionType);

                case "*":
                    return Cast(leftValueAsNumber * rightValueAsNumber, expressionType);
                }

                //if not numeric and not string concatenation, nothing to do...
                return null;
            }));
        }