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)); }
/// <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); } }
/// <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)); }
/// <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)); }
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)); }
/// <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)); }
/// <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; }
internal CSharpObjectPatternInfo(CSharpPatternInfo info, ParameterExpression variable) { Info = info; Variable = variable; }
/// <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);
internal NotCSharpPattern(CSharpPatternInfo info, CSharpPattern negated) : base(info) { Negated = negated; }
internal ConstantCSharpPattern(CSharpPatternInfo info, ConstantExpression value) : base(info) { Value = value; }
/// <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);
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)); }
internal CSharpPattern(CSharpPatternInfo info) => _info = info;
internal DiscardCSharpPattern(CSharpPatternInfo info) : base(info) { }
/// <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);
/// <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);
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 {