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)); }
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)); }
/// <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)); }
/// <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); })); }
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)); }