public static bool TryPromoteUnaryOperation(ref Expression operand, ExpressionType type, out Expression operation) { if (operand == null) { throw new ArgumentNullException("operand"); } operation = null; var operandType = TypeDescription.GetTypeDescription(operand.Type); var operandTypeUnwrap = operandType.IsNullable ? operandType.UnderlyingType : operandType; var promoteToNullable = operandType.IsNullable; if (operandTypeUnwrap.IsEnum) { MorphType(ref operand, promoteToNullable ? operandTypeUnwrap.UnderlyingType.GetNullableType() : operandTypeUnwrap.UnderlyingType); } else if (operandTypeUnwrap.TypeCode >= TypeCode.SByte && operandTypeUnwrap.TypeCode <= TypeCode.UInt16) { MorphType(ref operand, promoteToNullable ? typeof(int?) : typeof(int)); } else if (operandTypeUnwrap.TypeCode == TypeCode.UInt32 && type == ExpressionType.Not) { MorphType(ref operand, promoteToNullable ? typeof(long?) : typeof(long)); } return(false); }
public static bool TryMorphType(ref Expression expression, Type toType, out float quality) { if (expression == null) { throw new ArgumentNullException("expression"); } if (toType == null) { throw new ArgumentNullException("toType"); } if (expression.Type == toType) { quality = TypeConversion.QUALITY_SAME_TYPE; return(true); } var actualType = TypeDescription.GetTypeDescription(expression.Type); var targetType = TypeDescription.GetTypeDescription(toType); if (TryConvertInPlace(ref expression, targetType, out quality) || TryFindConversion(ref expression, actualType, targetType, out quality)) { return(true); } quality = TypeConversion.QUALITY_NO_CONVERSION; return(false); }
/// <summary> /// Creates new binder for expressions with <paramref name="lambdaType"/> signature. Optionally specifying <paramref name="typeResolver"/> to reference additional types during binding. /// </summary> /// <param name="lambdaType">Signature of bound expression.</param> /// <param name="typeResolver">Type resolver used for type resolution during binding process. /// When not specified then new instance of <see cref="KnownTypeResolver"/> is created using <paramref name="lambdaType"/> parameter types and result type.</param> public Binder(Type lambdaType, ITypeResolver typeResolver = null) { if (lambdaType == null) { throw new ArgumentNullException("lambdaType"); } var lambdaTypeDescription = TypeDescription.GetTypeDescription(lambdaType); if (lambdaTypeDescription.IsDelegate == false || lambdaTypeDescription.HasGenericParameters) { throw new ArgumentException(string.Format(Resources.EXCEPTION_BIND_VALIDDELEGATETYPEISEXPECTED, lambdaType), "lambdaType"); } var invokeMethod = lambdaTypeDescription.GetMembers(Constants.DELEGATE_INVOKE_NAME).FirstOrDefault(m => !m.IsStatic && m.IsMethod); if (invokeMethod == null) { throw new MissingMethodException(string.Format(Resources.EXCEPTION_BIND_MISSINGMETHOD, lambdaType.ToString(), Constants.DELEGATE_INVOKE_NAME)); } var parametersArray = new ParameterExpression[invokeMethod.GetParametersCount()]; for (var i = 0; i < invokeMethod.GetParametersCount(); i++) { parametersArray[i] = Expression.Parameter(invokeMethod.GetParameterType(i), invokeMethod.GetParameterName(i)); } this.lambdaType = lambdaType; this.parameters = new ReadOnlyCollection <ParameterExpression>(parametersArray); this.resultType = TypeDescription.GetTypeDescription(invokeMethod.ResultType); this.typeResolver = typeResolver ?? new KnownTypeResolver(GetTypes(this.resultType, this.parameters), DefaultTypeResolver); }
public TypeAsNode(UnaryExpression typeAsExpression, ConstantExpression[] constExpressions, ParameterExpression[] parameterExpressions) { if (typeAsExpression == null) { throw new ArgumentNullException("typeAsExpression"); } if (constExpressions == null) { throw new ArgumentNullException("constExpressions"); } if (parameterExpressions == null) { throw new ArgumentNullException("parameterExpressions"); } this.typeAsExpression = typeAsExpression; this.targetType = TypeDescription.GetTypeDescription(typeAsExpression.Type); if (this.targetType.IsValueType) { this.convertNode = new ConvertNode(typeAsExpression, constExpressions, parameterExpressions); } else { this.targetNode = AotCompiler.Compile(typeAsExpression.Operand, constExpressions, parameterExpressions); } }
public static Expression Unpack(IDictionary <string, object> packedExpression, ITypeResolver typeResolver = null, Expression global = null, Type expectedType = null) { if (packedExpression == null) { throw new ArgumentNullException("packedExpression"); } if (typeResolver == null) { typeResolver = KnownTypeResolver.Default; } if (expectedType == null) { expectedType = typeof(object); } var syntaxTree = new SyntaxTreeNode(packedExpression); var bindingContext = new BindingContext(typeResolver, Constants.EmptyReadonlyParameters, expectedType, global); var boundExpression = default(Expression); var bindingError = default(Exception); if (AnyBinder.TryBindInNewScope(syntaxTree, bindingContext, TypeDescription.GetTypeDescription(expectedType), out boundExpression, out bindingError) == false) { throw bindingError; } return(boundExpression); }
public ConvertNode(UnaryExpression convertExpression, ConstantExpression[] constExpressions, ParameterExpression[] parameterExpressions) { this.convertExpression = convertExpression; this.operandNode = AotCompiler.Compile(convertExpression.Operand, constExpressions, parameterExpressions); this.sourceType = TypeDescription.GetTypeDescription(convertExpression.Operand.Type); this.targetType = TypeDescription.GetTypeDescription(convertExpression.Type); if (this.sourceType.IsNullable) { this.sourceType = this.sourceType.UnderlyingType; this.isSourceTypeNullable = true; } if (this.targetType.IsNullable) { this.targetType = this.targetType.UnderlyingType; this.isTargetTypeNullable = true; } this.operation = Intrinsic.WrapUnaryOperation(convertExpression.Method) ?? Intrinsic.WrapUnaryOperation ( this.targetType.ExplicitConvertFrom.FindConversion(this.sourceType, this.targetType) ?? this.targetType.ImplicitConvertFrom.FindConversion(this.sourceType, this.targetType) ?? this.sourceType.ExplicitConvertTo.FindConversion(this.sourceType, this.targetType) ?? this.sourceType.ImplicitConvertTo.FindConversion(this.sourceType, this.targetType) ); }
public static bool TryPromoteBinaryOperation(ref Expression leftOperand, ref Expression rightOperand, ExpressionType type, out Expression operation) { if (leftOperand == null) { throw new ArgumentNullException("leftOperand"); } if (rightOperand == null) { throw new ArgumentNullException("rightOperand"); } operation = null; var leftType = TypeDescription.GetTypeDescription(leftOperand.Type); var rightType = TypeDescription.GetTypeDescription(rightOperand.Type); var leftTypeUnwrap = leftType.IsNullable ? leftType.UnderlyingType : leftType; var rightTypeUnwrap = rightType.IsNullable ? rightType.UnderlyingType : rightType; // enum + enum if (leftTypeUnwrap.IsEnum || rightTypeUnwrap.IsEnum) { return(TryPromoteEnumBinaryOperation(ref leftOperand, leftType, ref rightOperand, rightType, type, out operation)); } // number + number else if (leftTypeUnwrap.IsNumber && rightTypeUnwrap.IsNumber) { return(TryPromoteNumberBinaryOperation(ref leftOperand, leftType, ref rightOperand, rightType, type, out operation)); } // null + nullable else if (IsNull(leftOperand) && rightType.CanBeNull) { leftType = rightType; leftOperand = rightType.DefaultExpression; } // nullable + null else if (IsNull(rightOperand) && leftType.CanBeNull) { rightType = leftType; rightOperand = leftType.DefaultExpression; } // [not]nullable + [not]nullable else if (leftType.IsNullable != rightType.IsNullable) { leftOperand = ConvertToNullable(leftOperand, leftType); if (type != ExpressionType.Coalesce) { rightOperand = ConvertToNullable(rightOperand, rightType); } } return(false); }
/// <summary> /// Creates new binder for expressions with signature contains <paramref name="parameters"/>(up to 4) and <paramref name="resultType"/>. Optionally specifying <paramref name="typeResolver"/> to reference additional types during binding. /// </summary> /// <param name="parameters">List of parameter for bound expression. Maximum number of parameters is 4.</param> /// <param name="resultType">Result type of bound expression.</param> /// <param name="typeResolver">Type resolver used for type resolution during binding process. /// When not specified then new instance of <see cref="KnownTypeResolver"/> is created using <paramref name="parameters"/> parameter types and result type.</param> public Binder(IList <ParameterExpression> parameters, Type resultType, ITypeResolver typeResolver = null) { if (parameters == null) { throw new ArgumentNullException("parameters"); } if (resultType == null) { throw new ArgumentNullException("resultType"); } if (resultType.IsGenericParameter) { throw new ArgumentException("A value can't be generic parameter type.", "resultType"); } if (parameters.Count > 4) { throw new ArgumentOutOfRangeException("parameters"); } if (parameters.Any(p => p == null || p.Type.IsGenericParameter)) { throw new ArgumentException("Collection can't contain nulls or generic parameter types.", "parameters"); } if (parameters is ReadOnlyCollection <ParameterExpression> == false) { parameters = new ReadOnlyCollection <ParameterExpression>(parameters); } if (resultType == typeof(void)) { var funcParams = new Type[parameters.Count]; for (var i = 0; i < parameters.Count; i++) { funcParams[i] = parameters[i].Type; } this.lambdaType = Expression.GetActionType(funcParams); } else { var funcParams = new Type[parameters.Count + 1]; for (var i = 0; i < parameters.Count; i++) { funcParams[i] = parameters[i].Type; } funcParams[funcParams.Length - 1] = resultType; this.lambdaType = Expression.GetFuncType(funcParams); } this.parameters = (ReadOnlyCollection <ParameterExpression>)parameters; this.resultType = TypeDescription.GetTypeDescription(resultType); this.typeResolver = typeResolver ?? new KnownTypeResolver(GetTypes(resultType, parameters), DefaultTypeResolver); }
public static Expression MakeNullPropagationExpression(List <Expression> nullTestExpressions, Expression ifNotNullExpression) { if (nullTestExpressions == null) { throw new ArgumentNullException("nullTestExpressions"); } if (ifNotNullExpression == null) { throw new ArgumentNullException("ifNotNullExpression"); } var notNullTestTreeExpression = default(Expression); foreach (var nullTestExpression in nullTestExpressions) { var testTypeDescription = TypeDescription.GetTypeDescription(nullTestExpression.Type); var notEqualDefault = Expression.NotEqual(nullTestExpression, testTypeDescription.DefaultExpression); if (notNullTestTreeExpression == null) { notNullTestTreeExpression = notEqualDefault; } else { notNullTestTreeExpression = Expression.AndAlso(notNullTestTreeExpression, notEqualDefault); } } if (notNullTestTreeExpression == null) { notNullTestTreeExpression = TrueConstant; } var ifNotNullTypeDescription = TypeDescription.GetTypeDescription(ifNotNullExpression.Type); var resultType = ifNotNullTypeDescription.CanBeNull == false?TypeDescription.GetTypeDescription(typeof(Nullable <>).MakeGenericType(ifNotNullExpression.Type)) : ifNotNullTypeDescription; if (resultType != ifNotNullExpression.Type) { ifNotNullExpression = Expression.Convert(ifNotNullExpression, resultType); } return(Expression.Condition ( test: notNullTestTreeExpression, ifTrue: ifNotNullExpression, ifFalse: resultType.DefaultExpression )); }
public TypeIsNode(TypeBinaryExpression typeBinaryExpression, ConstantExpression[] constExpressions, ParameterExpression[] parameterExpressions) { if (typeBinaryExpression == null) { throw new ArgumentNullException("typeBinaryExpression"); } if (constExpressions == null) { throw new ArgumentNullException("constExpressions"); } if (parameterExpressions == null) { throw new ArgumentNullException("parameterExpressions"); } this.typeBinaryExpression = typeBinaryExpression; this.targetType = TypeDescription.GetTypeDescription(this.typeBinaryExpression.TypeOperand); this.targetNode = AotCompiler.Compile(typeBinaryExpression.Expression, constExpressions, parameterExpressions); }
private static Expression ConvertToNullable(Expression notNullableExpression, TypeDescription typeDescription) { if (notNullableExpression == null) { throw new ArgumentNullException("notNullableExpression"); } if (typeDescription != null && notNullableExpression.Type != typeDescription) { throw new ArgumentException("Wrong type description.", "typeDescription"); } if (typeDescription == null) { typeDescription = TypeDescription.GetTypeDescription(notNullableExpression.Type); } if (typeDescription.CanBeNull == false) { return(Expression.Convert(notNullableExpression, typeDescription.GetNullableType())); } else { return(notNullableExpression); } }
private static bool TryConvertInPlace(ref Expression expression, TypeDescription targetType, out float quality) { if (expression == null) { throw new ArgumentNullException("expression"); } if (targetType == null) { throw new ArgumentNullException("targetType"); } quality = TypeConversion.QUALITY_NO_CONVERSION; var targetTypeUnwrap = targetType.IsNullable ? targetType.UnderlyingType : targetType; // try to convert value of constant var constantExpression = default(ConstantExpression); if (TryExposeConstant(expression, out constantExpression) == false) { return(false); } var constantValue = constantExpression.Value; var constantType = TypeDescription.GetTypeDescription(constantExpression.Type); var constantTypeUnwrap = constantType.IsNullable ? constantType.UnderlyingType : constantType; if (constantValue == null && constantType.DefaultExpression != constantExpression && targetType.CanBeNull) { quality = TypeConversion.QUALITY_SAME_TYPE; expression = Expression.Constant(null, targetType); return(true); } else if (constantValue == null) { return(false); } var constantTypeCode = constantTypeUnwrap.TypeCode; var convertibleToExpectedType = default(bool); // ReSharper disable RedundantCast // ReSharper disable once SwitchStatementMissingSomeCases switch (targetTypeUnwrap.TypeCode) { case TypeCode.Byte: convertibleToExpectedType = IsInRange(constantValue, constantTypeCode, byte.MinValue, byte.MaxValue); break; case TypeCode.SByte: convertibleToExpectedType = IsInRange(constantValue, constantTypeCode, sbyte.MinValue, (ulong)sbyte.MaxValue); break; case TypeCode.Char: case TypeCode.UInt16: convertibleToExpectedType = IsInRange(constantValue, constantTypeCode, ushort.MinValue, ushort.MaxValue); break; case TypeCode.Int16: convertibleToExpectedType = IsInRange(constantValue, constantTypeCode, short.MinValue, (ulong)short.MaxValue); break; case TypeCode.UInt32: convertibleToExpectedType = IsInRange(constantValue, constantTypeCode, uint.MinValue, uint.MaxValue); break; case TypeCode.Int32: convertibleToExpectedType = IsInRange(constantValue, constantTypeCode, int.MinValue, int.MaxValue); break; case TypeCode.UInt64: convertibleToExpectedType = IsInRange(constantValue, constantTypeCode, (long)ulong.MinValue, ulong.MaxValue); break; case TypeCode.Int64: convertibleToExpectedType = IsInRange(constantValue, constantTypeCode, long.MinValue, long.MaxValue); break; case TypeCode.Double: case TypeCode.Decimal: case TypeCode.Single: convertibleToExpectedType = NumberUtils.IsSignedInteger(constantTypeCode) || NumberUtils.IsUnsignedInteger(constantTypeCode); break; default: convertibleToExpectedType = false; break; } // ReSharper restore RedundantCast if (!convertibleToExpectedType) { return(false); } var newValue = Convert.ChangeType(constantValue, targetTypeUnwrap.TypeCode, Constants.DefaultFormatProvider); expression = Expression.Constant(newValue, targetType); quality = TypeConversion.QUALITY_IN_PLACE_CONVERSION; // converted in-place return(true); }