internal ITupleCSharpPattern(CSharpPatternInfo info, MethodInfo getLengthMethod, MethodInfo getItemMethod, ReadOnlyCollection <PositionalCSharpSubpattern> deconstruction)
     : base(info)
 {
     GetLengthMethod = getLengthMethod;
     GetItemMethod   = getItemMethod;
     Deconstruction  = deconstruction;
 }
 internal BinaryCSharpPattern(CSharpPatternInfo info, CSharpPatternType patternType, CSharpPattern left, CSharpPattern right)
     : base(info)
 {
     PatternType = patternType;
     Left        = left;
     Right       = right;
 }
        /// <summary>
        /// Creates a pattern that always matches and assigns the input to a variable.
        /// </summary>
        /// <param name="info">Type information about the pattern.</param>
        /// <param name="variable">The variable to assign to.</param>
        /// <returns>A <see cref="DiscardCSharpPattern" /> that represents a pattern that always matches.</returns>
        public static VarCSharpPattern Var(CSharpPatternInfo info, ParameterExpression variable)
        {
            RequiresNotNull(variable, nameof(variable));

            info ??= PatternInfo(variable.Type, variable.Type);

            return(Var(ObjectPatternInfo(info, variable)));
        }
        /// <summary>
        /// Creates a pattern that checks convertibility to a type and assigns to a variable.
        /// </summary>
        /// <param name="info">Type information about the pattern.</param>
        /// <param name="variable">The variable to assign to.</param>
        /// <returns>A <see cref="DeclarationCSharpPattern" /> that represents a pattern that checks convertibility to a type and assigns to a variable.</returns>
        public static DeclarationCSharpPattern Declaration(CSharpPatternInfo info, ParameterExpression variable)
        {
            RequiresNotNull(variable, nameof(variable));

            info ??= PatternInfo(variable.Type, variable.Type);

            return(Declaration(ObjectPatternInfo(info, variable), variable.Type));
        }
        /// <summary>
        /// Creates an and pattern with the specified left and right patterns.
        /// </summary>
        /// <param name="info">Type information about the pattern.</param>
        /// <param name="left">The left pattern.</param>
        /// <param name="right">The right pattern.</param>
        /// <returns>A <see cref="NotCSharpPattern" /> representing an and pattern.</returns>
        public static BinaryCSharpPattern And(CSharpPatternInfo info, CSharpPattern left, CSharpPattern right)
        {
            RequiresNotNull(left, nameof(left));
            RequiresNotNull(right, nameof(right));

            info ??= PatternInfo(left.InputType, right.NarrowedType);

            RequiresCompatiblePatternTypes(info.InputType, ref left);
            RequiresCompatiblePatternTypes(left.NarrowedType, ref right);
            RequiresCompatiblePatternTypes(right.NarrowedType, info.NarrowedType);

            return(new BinaryCSharpPattern(info, CSharpPatternType.And, left, right));
        }
Beispiel #6
0
        /// <summary>
        /// Creates a relational pattern that compares against a constant value.
        /// </summary>
        /// <param name="info">Type information about the pattern.</param>
        /// <param name="type">The type of the pattern.</param>
        /// <param name="value">The value to compare with.</param>
        /// <returns>A <see cref="RelationalCSharpPattern" /> representing a relational pattern.</returns>
        public static RelationalCSharpPattern Relational(CSharpPatternInfo info, CSharpPatternType type, ConstantExpression value)
        {
            switch (type)
            {
            case CSharpPatternType.LessThan:
            case CSharpPatternType.LessThanOrEqual:
            case CSharpPatternType.GreaterThan:
            case CSharpPatternType.GreaterThanOrEqual:
                return(RelationalCSharpPattern.Make(info, type, value));

            default:
                throw Error.InvalidRelationalPatternType(type);
            }
        }
Beispiel #7
0
        /// <summary>
        /// Creates a pattern that always matches.
        /// </summary>
        /// <param name="info">Type information about the pattern.</param>
        /// <returns>A <see cref="DiscardCSharpPattern" /> that represents a pattern that always matches.</returns>
        public static DiscardCSharpPattern Discard(CSharpPatternInfo info)
        {
            if (info != null)
            {
                if (info.InputType != info.NarrowedType)
                {
                    throw Error.PatternInputAndNarrowedTypeShouldMatch(nameof(CSharpPatternType.Discard));
                }
            }
            else
            {
                info = PatternInfo(typeof(object), typeof(object));
            }

            return(new DiscardCSharpPattern(info));
        }
Beispiel #8
0
        /// <summary>
        /// Creates an object holding type information about a pattern.
        /// </summary>
        /// <param name="info">The underlying type information.</param>
        /// <param name="variable">The CSharpObjectPatternInfo to assign to upon successfully matching the associated pattern.</param>
        /// <returns>A <see cref="CSharpPatternInfo" /> object holding type information about a pattern.</returns>
        public static CSharpObjectPatternInfo ObjectPatternInfo(CSharpPatternInfo info, ParameterExpression variable)
        {
            info ??= PatternInfo(typeof(object), variable?.Type ?? typeof(object));

            if (variable != null)
            {
                if (variable.Type.IsByRef)
                {
                    throw LinqError.VariableMustNotBeByRef(variable, variable.Type);
                }

                RequiresCompatiblePatternTypes(info.NarrowedType, variable.Type);
            }

            return(new CSharpObjectPatternInfo(info, variable));
        }
Beispiel #9
0
        internal static RelationalCSharpPattern Make(CSharpPatternInfo info, CSharpPatternType type, ConstantExpression value)
        {
            RequiresNotNull(value, nameof(value));

            CheckConstant(value, isRelational: true);

            if (info != null)
            {
                RequiresCompatiblePatternTypes(value.Type, info.NarrowedType);
            }
            else
            {
                info = PatternInfo(typeof(object), value.Type);
            }

            return(new RelationalCSharpPattern(info, type, value));
        }
Beispiel #10
0
        /// <summary>
        /// Creates a pattern that checks convertibility to a type.
        /// </summary>
        /// <param name="info">Type information about the pattern.</param>
        /// <param name="type">The type to check for.</param>
        /// <returns>A <see cref="TypeCSharpPattern" /> that represents a pattern that checks for a type.</returns>
        public static TypeCSharpPattern Type(CSharpPatternInfo info, Type type)
        {
            RequiresNotNull(type, nameof(type));

            ValidatePatternType(type);

            if (info != null)
            {
                RequiresCompatiblePatternTypes(type, info.NarrowedType);
            }
            else
            {
                info = PatternInfo(typeof(object), type);
            }

            return(new TypeCSharpPattern(info, type));
        }
        /// <summary>
        /// Creates a constant pattern that checks for equality with the given constant value.
        /// </summary>
        /// <param name="info">Type information about the pattern.</param>
        /// <param name="value">The value used for the constant check.</param>
        /// <returns>A <see cref="ConstantCSharpPattern" /> representing a constant pattern.</returns>
        public static ConstantCSharpPattern Constant(CSharpPatternInfo info, ConstantExpression value)
        {
            RequiresNotNull(value, nameof(value));

            CheckConstant(value, isRelational: false);

            if (info != null)
            {
                var inputType = value.Value == null ? info.InputType : value.Type;
                RequiresCompatiblePatternTypes(inputType, info.NarrowedType);
            }
            else
            {
                info = PatternInfo(typeof(object), value.Type);
            }

            return(new ConstantCSharpPattern(info, value));
        }
Beispiel #12
0
        /// <summary>
        /// Creates a negated pattern.
        /// </summary>
        /// <param name="info">Type information about the pattern.</param>
        /// <param name="negated">The pattern to negate.</param>
        /// <returns>A <see cref="NotCSharpPattern" /> representing a negated pattern.</returns>
        public static NotCSharpPattern Not(CSharpPatternInfo info, CSharpPattern negated)
        {
            RequiresNotNull(negated, nameof(negated));

            if (info != null)
            {
                if (info.InputType != info.NarrowedType)
                {
                    throw Error.PatternInputAndNarrowedTypeShouldMatch(nameof(CSharpPatternType.Not));
                }

                RequiresCompatiblePatternTypes(info.InputType, ref negated);
            }
            else
            {
                info = PatternInfo(negated.InputType, negated.InputType);
            }

            return(new NotCSharpPattern(info, negated));
        }
        // TODO: Add convenience overloads.

        /// <summary>
        /// Creates a slice pattern.
        /// </summary>
        /// <param name="info">Type information about the pattern.</param>
        /// <param name="indexerAccess">The <see cref="LambdaExpression"/> representing the indexer access used to retrieve a slice from the collection.</param>
        /// <param name="pattern">The <see cref="CSharpPattern"/> representing the optional pattern to apply to the slice.</param>
        /// <returns>A <see cref="SliceCSharpPattern" /> representing a slice pattern.</returns>
        public static SliceCSharpPattern Slice(CSharpPatternInfo info, LambdaExpression indexerAccess, CSharpPattern pattern)
        {
            RequiresNotNull(info, nameof(info));

            var collectionType = info.InputType;

            if (indexerAccess != null)
            {
                RequiresCanRead(indexerAccess, nameof(indexerAccess));

                if (indexerAccess.Parameters.Count != 2)
                {
                    throw Error.IndexerAccessShouldHaveTwoParameters();
                }

                if (!AreEquivalent(indexerAccess.Parameters[0].Type, collectionType))
                {
                    throw Error.IndexerAccessFirstParameterShouldHaveCollectionType(collectionType);
                }

                if (indexerAccess.Parameters[1].Type != typeof(Range))
                {
                    throw Error.IndexerAccessSecondParameterInvalidType(typeof(Range));
                }

                if (indexerAccess.ReturnType == typeof(void))
                {
                    throw Error.ElementTypeCannotBeVoid();
                }
            }

            if (pattern != null)
            {
                RequiresNotNull(indexerAccess, nameof(indexerAccess));

                RequiresCompatiblePatternTypes(indexerAccess.ReturnType, ref pattern);
                RequiresCompatiblePatternTypes(pattern.NarrowedType, info.NarrowedType);
            }

            return(new SliceCSharpPattern(info, indexerAccess, pattern));
        }
        /// <summary>
        /// Creates an or pattern with the specified left and right patterns.
        /// </summary>
        /// <param name="info">Type information about the pattern.</param>
        /// <param name="left">The left pattern.</param>
        /// <param name="right">The right pattern.</param>
        /// <returns>A <see cref="NotCSharpPattern" /> representing an or pattern.</returns>
        public static BinaryCSharpPattern Or(CSharpPatternInfo info, CSharpPattern left, CSharpPattern right)
        {
            RequiresNotNull(left, nameof(left));
            RequiresNotNull(right, nameof(right));

            RequiresCompatiblePatternTypes(left.InputType, ref right);

            if (info == null)
            {
                var inputType    = left.InputType;
                var narrowedType = FindLeastSpecificType(inputType, left, right);
                info = PatternInfo(inputType, narrowedType);
            }
            else
            {
                var leastSpecificType = FindLeastSpecificType(info.InputType, left, right);
                RequiresCompatiblePatternTypes(leastSpecificType, info.NarrowedType);
            }

            RequiresCompatiblePatternTypes(info.InputType, ref left);
            RequiresCompatiblePatternTypes(info.InputType, ref right);

            return(new BinaryCSharpPattern(info, CSharpPatternType.Or, left, right));
        }
 internal SliceCSharpPattern(CSharpPatternInfo info, LambdaExpression indexerAccess, CSharpPattern pattern)
     : base(info)
 {
     IndexerAccess = indexerAccess;
     Pattern       = pattern;
 }
Beispiel #16
0
 internal CSharpObjectPatternInfo(CSharpPatternInfo info, ParameterExpression variable)
 {
     Info     = info;
     Variable = variable;
 }
Beispiel #17
0
 /// <summary>
 /// Creates a property pattern that matches on properties.
 /// </summary>
 /// <param name="info">Type information about the pattern.</param>
 /// <param name="type">The type to check for.</param>
 /// <param name="variable">The variable to assign to.</param>
 /// <param name="properties">The property subpatterns to apply.</param>
 /// <returns>A <see cref="RecursiveCSharpPattern" /> representing a property pattern.</returns>
 public static RecursiveCSharpPattern Property(CSharpPatternInfo info, Type type, ParameterExpression variable, params PropertyCSharpSubpattern[] properties) =>
 Property(info, type, variable, (IEnumerable <PropertyCSharpSubpattern>)properties);
Beispiel #18
0
 internal NotCSharpPattern(CSharpPatternInfo info, CSharpPattern negated)
     : base(info)
 {
     Negated = negated;
 }
 internal ConstantCSharpPattern(CSharpPatternInfo info, ConstantExpression value)
     : base(info)
 {
     Value = value;
 }
Beispiel #20
0
 /// <summary>
 /// Creates a property pattern that matches on properties.
 /// </summary>
 /// <param name="info">Type information about the pattern.</param>
 /// <param name="type">The type to check for.</param>
 /// <param name="variable">The variable to assign to.</param>
 /// <param name="properties">The property subpatterns to apply.</param>
 /// <returns>A <see cref="RecursiveCSharpPattern" /> representing a property pattern.</returns>
 public static RecursiveCSharpPattern Property(CSharpPatternInfo info, Type type, ParameterExpression variable, IEnumerable <PropertyCSharpSubpattern> properties) =>
 Recursive(ObjectPatternInfo(info, variable), type, deconstructMethod: null, deconstruction: null, properties);
Beispiel #21
0
 internal TypeCSharpPattern(CSharpPatternInfo info, Type type)
     : base(info)
 {
     Type = type;
 }
        /// <summary>
        /// Creates a pattern that matches a tuple using the <see cref="ITuple"/> interface.
        /// </summary>
        /// <param name="info">Type information about the pattern.</param>
        /// <param name="getLengthMethod">The method used to obtain the tuple element count.</param>
        /// <param name="getItemMethod">The method used to access a tuple element.</param>
        /// <param name="deconstruction">The subpatterns to apply to the tuple elements.</param>
        /// <returns>A <see cref="ITupleCSharpPattern" /> representing a tuple pattern.</returns>
        public static ITupleCSharpPattern ITuple(CSharpPatternInfo info, MethodInfo getLengthMethod, MethodInfo getItemMethod, IEnumerable <PositionalCSharpSubpattern> deconstruction)
        {
            if (info != null)
            {
                RequiresCompatiblePatternTypes(info.NarrowedType, typeof(ITuple));
            }
            else
            {
                info = PatternInfo(typeof(object), typeof(ITuple));
            }

            if (getLengthMethod != null)
            {
                ValidateMethodInfo(getLengthMethod);

                // NB: The check for an instance method with no args is part of the Call factory.
                var checkCallGetLength = Expression.Call(Expression.Default(info.NarrowedType), getLengthMethod);

                if (checkCallGetLength.Type != typeof(int))
                {
                    throw Error.ITupleGetLengthShouldReturnInt32();
                }
            }
            else
            {
                getLengthMethod = ITupleGetLength;
            }

            if (getItemMethod != null)
            {
                ValidateMethodInfo(getItemMethod);

                // NB: The check for an instance method with a single integer args is part of the Call factory.
                var checkCallGetItem = Expression.Call(Expression.Default(info.NarrowedType), getItemMethod, Expression.Default(typeof(int)));

                if (checkCallGetItem.Type != typeof(object))
                {
                    throw Error.ITupleGetItemShouldReturnObject();
                }
            }
            else
            {
                getItemMethod = ITupleGetItem;
            }

            var deconstructionCollection = deconstruction.ToReadOnly();

            for (int i = 0, n = deconstructionCollection.Count; i < n; i++)
            {
                var positionalPattern = deconstructionCollection[i];

                RequiresNotNull(positionalPattern, nameof(deconstruction));

                if (positionalPattern.Field != null)
                {
                    throw Error.ITuplePositionalPatternCannotHaveField(i);
                }
                if (positionalPattern.Parameter != null)
                {
                    throw Error.ITuplePositionalPatternCannotHaveParameter(i);
                }

                //
                // CONSIDER: If the input type does not match, we could trigger ChangeType (which would do the opposite of narrowing,
                //           i.e. generalize to 'object').
                //

                if (positionalPattern.Pattern.InputType != typeof(object))
                {
                    throw Error.ITuplePositionalPatternInvalidInputType(i, positionalPattern.Pattern.InputType);
                }
            }

            return(new ITupleCSharpPattern(info, getLengthMethod, getItemMethod, deconstructionCollection));
        }
Beispiel #23
0
 internal CSharpPattern(CSharpPatternInfo info) => _info = info;
Beispiel #24
0
 internal DiscardCSharpPattern(CSharpPatternInfo info)
     : base(info)
 {
 }
Beispiel #25
0
 /// <summary>
 /// Creates a relational less than pattern that compares against a constant value.
 /// </summary>
 /// <param name="info">Type information about the pattern.</param>
 /// <param name="value">The value to compare with.</param>
 /// <returns>A <see cref="RelationalCSharpPattern" /> representing a relational pattern.</returns>
 public static RelationalCSharpPattern LessThan(CSharpPatternInfo info, ConstantExpression value) => RelationalCSharpPattern.Make(info, CSharpPatternType.LessThan, value);
Beispiel #26
0
 /// <summary>
 /// Creates a relational greater than or equal pattern that compares against a constant value.
 /// </summary>
 /// <param name="info">Type information about the pattern.</param>
 /// <param name="value">The value to compare with.</param>
 /// <returns>A <see cref="RelationalCSharpPattern" /> representing a relational pattern.</returns>
 public static RelationalCSharpPattern GreaterThanOrEqual(CSharpPatternInfo info, ConstantExpression value) => RelationalCSharpPattern.Make(info, CSharpPatternType.GreaterThanOrEqual, value);
Beispiel #27
0
 internal RelationalCSharpPattern(CSharpPatternInfo info, CSharpPatternType patternType, ConstantExpression value)
     : base(info)
 {
     PatternType = patternType;
     Value       = value;
 }
 /// <summary>
 /// Creates a binary pattern with the specified left and right patterns.
 /// </summary>
 /// <param name="info">Type information about the pattern.</param>
 /// <param name="type">The type of the pattern.</param>
 /// <param name="left">The left pattern.</param>
 /// <param name="right">The right pattern.</param>
 /// <returns>A <see cref="NotCSharpPattern" /> representing a binary pattern.</returns>
 public static BinaryCSharpPattern MakeBinary(CSharpPatternInfo info, CSharpPatternType type, CSharpPattern left, CSharpPattern right) =>
 type switch
 {