コード例 #1
0
        public static Expression Reduce(Expression @object, Func <Expression, Expression> reduce, List <ParameterExpression> vars, List <Expression> stmts)
        {
            if (@object.IsPure(readOnly: true))
            {
                if (@object is ParameterExpression p)
                {
                    // NB: Trick some purity checks down the line to not introduce more temps. Patterns do not cause assignments
                    //     to variables, so a variable input can be considered to be pure.

                    @object = new ReadOnlyTemporaryVariableExpression(p);
                }

                return(reduce(@object));
            }
            else
            {
                var p = Expression.Parameter(@object.Type, "__obj");
                var r = new ReadOnlyTemporaryVariableExpression(p);

                if (vars != null)
                {
                    vars.Add(p);
                    stmts.Add(Expression.Assign(p, @object));
                    return(reduce(r));
                }
                else
                {
                    return
                        (Expression.Block(
                             new[] { p },
                             Expression.Assign(p, @object),
                             reduce(r)
                             ));
                }
            }
        }
コード例 #2
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)
        {
            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);
            }));
        }