예제 #1
0
        private Type binary_optional_left_expr(ParserRuleContext context, ParserRuleContext left, IToken op, ParserRuleContext right)
        {
            if (left == null)
            {
                Type t = right.Accept(this);
                type_dict[context] = t;
                return(t);
            }

            Type left_type      = left.Accept(this);
            Type right_type     = right.Accept(this);
            Type resulting_type = get_binary_operator_result(left_type, right_type, op);

            type_dict[context] = resulting_type;
            Debug.Assert(resulting_type != null && resulting_type != typeof(void));
            return(resulting_type);
        }
예제 #2
0
        private ObjectType VisitLogicalExpression(ParserRuleContext context, string op, ParserRuleContext left,
                                                  ParserRuleContext right)
        {
            var leftType  = left.Accept(this);
            var rightType = right.Accept(this);

            if (leftType == ObjectType.Boolean &&
                rightType == ObjectType.Boolean)
            {
                return(ObjectType.Boolean);
            }

            _scriptEnvironmentBuilder.Errors.Add(new InvalidOperandsException(context, op, leftType, rightType));
            return(ObjectType.Unknown);
        }
예제 #3
0
        //public override ObjectType VisitArithmeticExpression(QuestScriptParser.ArithmeticExpressionContext context)
        private ObjectType VisitArithmeticExpression(ParserRuleContext context, ParserRuleContext op,
                                                     ParserRuleContext left, ParserRuleContext right)
        {
            var leftType  = left.Accept(this);
            var rightType = right.Accept(this);

            //if at least one is unknown, then we already have an error and can stop evaluating types
            if (leftType == ObjectType.Unknown || rightType == ObjectType.Unknown)
            {
                return(ObjectType.Unknown);
            }

            if (leftType == rightType)
            {
                return(leftType);
            }

            //we don't want to lose precision, thus any arithmetic expression with double operand becomes double too
            if (TypeUtil.IsNumeric(rightType) &&
                TypeUtil.IsNumeric(leftType) &&
                (leftType == ObjectType.Double || rightType == ObjectType.Double))
            {
                return(ObjectType.Double);
            }

            if (TypeUtil.CanConvert(rightType, leftType))
            {
                return(leftType);
            }

            if (TypeUtil.CanConvert(leftType, rightType))
            {
                return(rightType);
            }

            _scriptEnvironmentBuilder.Errors.Add(new InvalidOperandsException(context, op.GetText(), leftType,
                                                                              rightType));

            return(ObjectType.Unknown);
        }
        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;
            }));
        }