예제 #1
0
        internal static Expression MakeTest(CSharpPattern pattern, Expression @object, ExpressionType op, ConstantExpression value)
        {
            if (pattern.InputType == pattern.NarrowedType)
            {
                var obj = @object;

                if (obj.Type != pattern.InputType)
                {
                    obj = Expression.Convert(obj, pattern.InputType);
                }

                return
                    (Expression.MakeBinary(
                         op,
                         obj,
                         value
                         ));
            }
            else
            {
                return(PatternHelpers.Reduce(@object, obj =>
                {
                    return
                    Expression.AndAlso(
                        Expression.TypeIs(obj, pattern.NarrowedType),
                        Expression.MakeBinary(
                            op,
                            Expression.Convert(obj, pattern.NarrowedType),
                            value
                            )
                        );
                }));
            }
        }
        internal override Expression Reduce(Expression @object)
        {
            Expression createTest(Expression obj)
            {
                if (Variable != null)
                {
                    var test = Expression.Parameter(typeof(bool), "__test");

                    return
                        (Expression.Block(
                             new[] { test },
                             Expression.Assign(test, Expression.TypeIs(obj, Type)),
                             Expression.IfThen(
                                 test,
                                 Expression.Assign(Variable, Expression.Convert(obj, Type))
                                 ),
                             test
                             ));
                }
                else
                {
                    return(Expression.TypeIs(obj, Type));
                }
            }

            return(PatternHelpers.Reduce(@object, createTest));
        }
        /// <summary>
        /// Reduces the pattern by applying it the specified object.
        /// </summary>
        /// <param name="object">The object to match the pattern against.</param>
        /// <returns>The expression representing the pattern applied to the specified object.</returns>
        internal override Expression Reduce(Expression @object)
        {
            Expression createTest(Expression obj)
            {
                return(Expression.MakeBinary(PatternType == CSharpPatternType.And ? ExpressionType.AndAlso : ExpressionType.OrElse, Left.Reduce(obj), Right.Reduce(obj)));
            }

            return(PatternHelpers.Reduce(@object, createTest));
        }
예제 #4
0
        internal Expression Reduce(Expression @object, List <ParameterExpression> vars, List <Expression> stmts, LabelTarget exit)
        {
            // NB: LengthOrCount is only used to refine the range of Int32 to >= 0. We don't yet use it for reduction.

            Expression createTest(Expression obj)
            {
                return(Pattern.Reduce(Member.Reduce(obj, vars, stmts, exit)));
            }

            return(PatternHelpers.Reduce(@object, createTest, vars, stmts));
        }
예제 #5
0
        /// <summary>
        /// Reduces the pattern by applying it the specified object.
        /// </summary>
        /// <param name="object">The object to match the pattern against.</param>
        /// <returns>The expression representing the pattern applied to the specified object.</returns>
        internal override Expression Reduce(Expression @object)
        {
            if (!AreReferenceAssignable(InputType, @object.Type))
            {
                throw LinqError.ExpressionTypeDoesNotMatchAssignment(@object.Type, InputType);
            }

            // NB: RecursiveCSharpPattern has a peephole optimization for the pattern below.

            // NB: Ensure any side-effects in evaluating @object are retained.
            return(PatternHelpers.Reduce(@object, _ => ConstantTrue));
        }
        /// <summary>
        /// Reduces the pattern by applying it the specified object.
        /// </summary>
        /// <param name="object">The object to match the pattern against.</param>
        /// <returns>The expression representing the pattern applied to the specified object.</returns>
        internal override Expression Reduce(Expression @object)
        {
            // NB: RecursiveCSharpPattern has a peephole optimization for the pattern below.

            if (Variable != null)
            {
                return
                    (Expression.Block(
                         Expression.Assign(Variable, @object),
                         ConstantTrue
                         ));
            }
            else
            {
                // NB: Ensure any side-effects in evaluating @object are retained.
                return(PatternHelpers.Reduce(@object, _ => ConstantTrue));
            }
        }
        /// <summary>
        /// Reduces the slice pattern by applying it the specified range in the specified object.
        /// </summary>
        /// <param name="object">The object to match the pattern against.</param>
        /// <param name="length">The (optional) precomputed length of the object.</param>
        /// <param name="range">The range to extract from the object.</param>
        /// <returns>The expression representing the pattern applied to the specified object and range.</returns>
        internal Expression Reduce(Expression @object, Expression length, Range range)
        {
            Expression GetSlice(Expression obj)
            {
                var rangeExpr = Expression.Constant(range);

                if (IndexerAccess.Body is ArrayAccessCSharpExpression a &&
                    a.Array == IndexerAccess.Parameters[0] &&
                    a.Indexes.Count == 1 &&
                    a.Indexes[0] == IndexerAccess.Parameters[1])
                {
                    var arrayAccess = a.Update(obj, new[] { rangeExpr });
                    return(arrayAccess.Reduce(length));
                }

                if (IndexerAccess.Body is IndexerAccessCSharpExpression i &&
                    i.Object == IndexerAccess.Parameters[0] &&
                    i.Argument == IndexerAccess.Parameters[1])
                {
                    var indexerAccess = i.Update(obj, rangeExpr);
                    return(indexerAccess.Reduce(length));
                }

                return(Expression.Invoke(IndexerAccess, obj, rangeExpr));
            }

            return(PatternHelpers.Reduce(@object, obj =>
            {
                if (IndexerAccess != null && Pattern != null && Pattern.PatternType != CSharpPatternType.Discard)
                {
                    var slice = GetSlice(obj);

                    return Pattern.Reduce(slice);
                }

                return ConstantTrue;
            }));
        }
        internal override Expression Reduce(Expression @object)
        {
            Expression createTest(Expression obj)
            {
                var exit = Expression.Label(typeof(bool), "__return");

                var stmts = new List <Expression>();

                AddFailIfNot(Expression.TypeIs(obj, typeof(ITuple)), exit, stmts);

                var temp = Expression.Parameter(typeof(ITuple), "__objT");

                stmts.Add(Expression.Assign(temp, Expression.Convert(obj, typeof(ITuple))));
                obj = temp;

                var deconstructionCount = Deconstruction.Count;

                AddFailIfNot(Expression.Equal(Expression.Call(obj, GetLengthMethod), CreateConstantInt32(deconstructionCount)), exit, stmts);

                for (var i = 0; i < deconstructionCount; i++)
                {
                    var deconstruction = Deconstruction[i];

                    var item = Expression.Call(obj, GetItemMethod, CreateConstantInt32(i));
                    var test = deconstruction.Pattern.Reduce(item);

                    AddFailIfNot(test, exit, stmts);
                }

                stmts.Add(Expression.Label(exit, ConstantTrue));

                return(Expression.Block(new[] { temp }, stmts));
            }

            return(PatternHelpers.Reduce(@object, createTest));
        }
예제 #9
0
 /// <summary>
 /// Reduces the pattern by applying it the specified object.
 /// </summary>
 /// <param name="object">The object to match the pattern against.</param>
 /// <returns>The expression representing the pattern applied to the specified object.</returns>
 internal override Expression Reduce(Expression @object)
 {
     return(PatternHelpers.Reduce(@object, obj => Expression.Not(Negated.Reduce(obj))));
 }
        /// <summary>
        /// Reduces the pattern by applying it the specified object.
        /// </summary>
        /// <param name="object">The object to match the pattern against.</param>
        /// <returns>The expression representing the pattern applied to the specified object.</returns>
        internal override Expression Reduce(Expression @object)
        {
            Expression GetLength(Expression obj)
            {
                if (LengthAccess.Body is MemberExpression m &&
                    m.Expression == LengthAccess.Parameters[0])
                {
                    return(m.Update(obj));
                }

                return(Expression.Invoke(LengthAccess, obj));
            }

            Expression GetElement(Expression obj, Expression length, Index index)
            {
                var indexExpr = Expression.Constant(index);

                if (IndexerAccess.Body is ArrayAccessCSharpExpression a &&
                    a.Array == IndexerAccess.Parameters[0] &&
                    a.Indexes.Count == 1 &&
                    a.Indexes[0] == IndexerAccess.Parameters[1])
                {
                    var arrayAccess = a.Update(obj, new[] { indexExpr });
                    return(arrayAccess.Reduce(length));
                }

                if (IndexerAccess.Body is IndexerAccessCSharpExpression i &&
                    i.Object == IndexerAccess.Parameters[0] &&
                    i.Argument == IndexerAccess.Parameters[1])
                {
                    var indexerAccess = i.Update(obj, indexExpr);
                    return(indexerAccess.Reduce(length));
                }

                return(Expression.Invoke(IndexerAccess, obj, indexExpr));
            }

            bool HasSlice()
            {
                foreach (var p in Patterns)
                {
                    if (p.PatternType == CSharpPatternType.Slice)
                    {
                        return(true);
                    }
                }

                return(false);
            }

            return(PatternHelpers.Reduce(@object, obj =>
            {
                var exit = Expression.Label(typeof(bool), "__return");

                var vars = new List <ParameterExpression>();
                var stmts = new List <Expression>();

                obj = AddNullCheck(obj, typeCheck: null, exit, vars, stmts);

                var n = Patterns.Count;

                var length = GetLength(obj);

                var hasSlice = HasSlice();

                if (hasSlice)
                {
                    var lengthTemp = Expression.Parameter(length.Type, "__len");
                    vars.Add(lengthTemp);
                    stmts.Add(Expression.Assign(lengthTemp, length));
                    length = new ReadOnlyTemporaryVariableExpression(lengthTemp);
                }

                var negatedLengthCheck = hasSlice
                    ? Expression.LessThan(length, CreateConstantInt32(n - 1))
                    : Expression.NotEqual(length, CreateConstantInt32(n));

                AddFailIf(negatedLengthCheck, exit, stmts);

                var hasSeenSlice = false;

                for (int i = 0; i < n; i++)
                {
                    var p = Patterns[i];

                    if (p is SliceCSharpPattern slice)
                    {
                        hasSeenSlice = true;

                        var rangeStart = new Index(i);
                        var rangeEnd = new Index(n - i - 1, fromEnd: true);
                        var range = new Range(rangeStart, rangeEnd);

                        var sliceCheck = slice.Reduce(obj, length, range);

                        AddFailIfNot(sliceCheck, exit, stmts);
                    }
                    else if (p.PatternType != CSharpPatternType.Discard)
                    {
                        var index = hasSeenSlice
                            ? new Index(n - i, fromEnd: true)
                            : new Index(i);

                        var element = GetElement(obj, length, index);
                        var elementCheck = p.Reduce(element);

                        AddFailIfNot(elementCheck, exit, stmts);
                    }
                }

                if (Variable != null)
                {
                    stmts.Add(Expression.Assign(Variable, obj));
                }

                stmts.Add(Expression.Label(exit, ConstantTrue));

                return Expression.Block(vars, stmts);
            }));
        }
예제 #11
0
        internal override Expression Reduce(Expression @object)
        {
            Expression createTest(Expression obj)
            {
                var exit = Expression.Label(typeof(bool), "__return");

                var vars  = new List <ParameterExpression>();
                var stmts = new List <Expression>();

                obj = AddNullCheck(obj, Type, exit, vars, stmts);

                if (Deconstruction.Count > 0)
                {
                    if (DeconstructMethod != null)
                    {
                        var isExtensionMethod = DeconstructMethod.IsStatic;

                        var parameters     = DeconstructMethod.GetParametersCached();
                        var parameterCount = parameters.Length;

                        if (isExtensionMethod)
                        {
                            parameterCount--;
                        }

                        var parameterToVariable      = new Dictionary <ParameterInfo, ParameterExpression>(parameterCount);
                        var parameterIndexToVariable = new ParameterExpression[parameterCount];
                        var deconstructArgs          = new Expression[parameterCount];

                        for (var i = 0; i < parameterCount; i++)
                        {
                            var parameter = parameters[isExtensionMethod ? i + 1 : i];

                            Debug.Assert(parameter.IsOut && parameter.IsByRefParameter());

                            var type = parameter.ParameterType.GetElementType();
                            var temp = Expression.Parameter(type, "__obj_d" + i);

                            vars.Add(temp);

                            parameterToVariable.Add(parameter, temp);
                            parameterIndexToVariable[i] = temp;
                            deconstructArgs[i]          = temp;
                        }

                        var deconstruct = isExtensionMethod
                            ? Expression.Call(DeconstructMethod, deconstructArgs.AddFirst(obj))
                            : Expression.Call(obj, DeconstructMethod, deconstructArgs);

                        stmts.Add(deconstruct);

                        var deconstructionCount = Deconstruction.Count;

                        for (var i = 0; i < deconstructionCount; i++)
                        {
                            var deconstruction = Deconstruction[i];

                            var var  = deconstruction.Parameter != null ? parameterToVariable[deconstruction.Parameter] : parameterIndexToVariable[i];
                            var test = deconstruction.Pattern.Reduce(var);

                            AddFailIfNot(test, exit, stmts);
                        }
                    }
                    else
                    {
                        var deconstructionCount = Deconstruction.Count;

                        for (var i = 0; i < deconstructionCount; i++)
                        {
                            var deconstruction = Deconstruction[i];

                            var index = deconstruction.Field?.Index ?? i;
                            var item  = GetTupleItemAccess(obj, index);
                            var test  = deconstruction.Pattern.Reduce(item);

                            AddFailIfNot(test, exit, stmts);
                        }
                    }
                }

                if (Properties.Count > 0)
                {
                    foreach (var prop in Properties)
                    {
                        var test = prop.Reduce(obj, vars, stmts, exit);
                        AddFailIfNot(test, exit, stmts);
                    }
                }

                if (Variable != null)
                {
                    stmts.Add(Expression.Assign(Variable, obj));
                }

                stmts.Add(Expression.Label(exit, ConstantTrue));

                return(Expression.Block(vars, stmts));
            }

            return(PatternHelpers.Reduce(@object, createTest));
        }