示例#1
0
        /// <summary>
        /// Validates expression. Trys to align types.
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public ArrayExpression Validate(IValidationScope context)
        {
            var elements = Elements.Select(e => e.Validate(context)).ToArray();
            //Attention! The array has at least one element.
            var elementType = Elements.First().SemanticType;

            for (var index = 1; index < elements.Length; index++)
            {
                if (elements[index].SemanticType != elementType)
                {
                    elementType = context.AlignTypes(ref elements[index - 1], ref elements[index], () => new LocateableException(Location, "Could not unify type of this array!"));
                }
            }
            Elements     = elements;
            elementType  = Elements.Select(e => e.SemanticType).GetCommonBaseClass();
            SemanticType = elementType.MakeArrayType();
            return(this);
        }
示例#2
0
 /// <summary>
 /// Validation.
 /// </summary>
 /// <param name="context"></param>
 /// <returns></returns>
 public ConditionalExpression Validate(IValidationScope context)
 {
     Condition = Condition.Validate(context);
     then      = then.Validate(context);
     @else     = @else.Validate(context);
     if (Condition.SemanticType != typeof(bool))
     {
         throw new LocateableException(Condition.Location, "Condition must be a boolean!");
     }
     if (Then.SemanticType != Else.SemanticType)
     {
         SemanticType = context.AlignTypes(ref then, ref @else,
                                           () => new LocateableException(Location, "In the end the Then and the Else part must have the same type (also using implicit type conversion)!"));
     }
     else
     {
         SemanticType = Then.SemanticType;
     }
     return(this);
 }
示例#3
0
        /// <summary>
        /// Validation: determines the actual operation and its return type.
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public BinaryOperationExpression Validate(IValidationScope context)
        {
            this.leftExpression  = this.leftExpression.Validate(context);
            this.rightExpression = this.rightExpression.Validate(context);
            switch (this.Operator)
            {
            case BinaryOperator.In:
            case BinaryOperator.NotIn:
            {
                Type needleType = leftExpression.SemanticType;
                if (!rightExpression.IfArrayTryGetElementType(out Type elementType))
                {
                    throw new LocateableException(Location, "The 'in' operator requires an array expression for the right operand.");
                }
                if (needleType != elementType)
                {
                    var chain   = context.TypeSystem.GetImplicitlyCastChain(needleType, elementType);
                    var newLeft = chain.ApplyCast(leftExpression, context);
                    if (newLeft != null)
                    {
                        leftExpression = newLeft;
                        needleType     = elementType;
                    }
                    else
                    {
                        chain = context.TypeSystem.GetImplicitlyCastChain(elementType, needleType);
                        var array = rightExpression as ArrayExpression;
                        if (array == null)
                        {
                            throw new LocateableException(Location, "The 'in' operator requires that the right operand to be a list of the left operand's type.");
                        }
                        else
                        {
                            var newArray = new ArrayExpression(rightExpression.Location, array.Elements.Select(exp => chain.ApplyCast(exp, context)));
                            if (newArray.Elements.All(e => e != null))
                            {
                                rightExpression = newArray;
                                elementType     = needleType;
                            }
                            else
                            {
                                throw new LocateableException(Location, "The 'in' operator requires that the left operand has the same type like the elements of the right operand. At least these types must be convertible in each other.");
                            }
                        }
                    }
                }
                Type haystackType   = typeof(IEnumerable <>).MakeGenericType(elementType);
                var  equalsOperator = Operator == BinaryOperator.In ? BinaryOperator.Equals : BinaryOperator.NotEquals;
                var  equals         = context.TypeSystem.GetBinaryOperation(equalsOperator, needleType, elementType);
                if (equals == null)
                {
                    throw new LocateableException(Location, "The elements of the array are not comparable with the left operand.");
                }
                operation = new BinaryOperation(needleType, haystackType, typeof(bool), Operator, (needle, haystack) =>
                    {
                        foreach (object element in ((IEnumerable)haystack))
                        {
                            if ((bool)equals.Operation(needle, element) == true)
                            {
                                return(true);
                            }
                        }
                        return(false);
                    });
                SemanticType = typeof(bool);
            }
            break;

            case BinaryOperator.Is:
            {
                var negate = false;
                if (rightExpression is NullExpression)
                {
                    //almost everything could be null
                    SemanticType = typeof(bool);
                    operation    = new BinaryOperation(leftExpression.SemanticType, rightExpression.SemanticType, typeof(bool), Operator,
                                                       (lhs, _) => { return(negate ^ object.Equals(lhs, null)); });
                }
                else if (rightExpression is EmptyExpression)
                {
                    if (!leftExpression.IfArrayTryGetElementType(out Type elementType))
                    {
                        throw new LocateableException(leftExpression.Location, "Left operand must be of an array type.");
                    }
                    SemanticType = typeof(bool);
                    operation    = new BinaryOperation(leftExpression.SemanticType, rightExpression.SemanticType, typeof(bool), Operator,
                                                       (lhs, _) =>
                        {
                            foreach (object element in ((IEnumerable)lhs))
                            {
                                return(negate);
                            }
                            return(!negate);
                        });
                }
                else
                {
                    throw new LocateableException(rightExpression.Location, "Right operand must be NULL or EMPTY.");
                }
            }
            break;

            default:
                operation = context.TypeSystem.GetBinaryOperation(Operator, LeftExpression.SemanticType, RightExpression.SemanticType);
                if (operation == null)
                {
                    context.AlignTypes(ref leftExpression, ref rightExpression,
                                       () => new LocateableException(Location, "Binary operation not supported!"));
                }
                operation = context.TypeSystem.GetBinaryOperation(Operator, LeftExpression.SemanticType, RightExpression.SemanticType);
                if (operation == null)
                {
                    throw new LocateableException(Location, "Binary operation not supported!");
                }
                SemanticType = operation.ResultType;
                break;
            }
            return(this);
        }