public static bool TryBind(SyntaxTreeNode node, BindingContext bindingContext, TypeDescription expectedType, out Expression boundExpression, out Exception bindingError) { if (node == null) { throw new ArgumentNullException("node"); } if (bindingContext == null) { throw new ArgumentNullException("bindingContext"); } if (expectedType == null) { throw new ArgumentNullException("expectedType"); } if (node == null) { throw new ArgumentNullException("node"); } var arguments = node.GetArguments(throwOnError: false); var methodName = node.GetMethodName(throwOnError: false); if (methodName != null) { return(TryBindToMethod(node, methodName, arguments, bindingContext, expectedType, out boundExpression, out bindingError)); } else { var typeName = node.GetTypeName(throwOnError: true); return(TryBindToType(node, typeName, arguments, bindingContext, expectedType, out boundExpression, out bindingError)); } }
private static bool TryBindTarget(SyntaxTreeNode node, BindingContext bindingContext, out Expression target, out Type type, out Exception bindingError) { type = null; target = null; bindingError = null; // target is passed as Expression from InvokeBinder var targetObj = default(object); if (node.TryGetValue(Constants.EXPRESSION_ATTRIBUTE, out targetObj)) { if (targetObj is Expression) { target = (Expression)targetObj; type = target.Type; return(true); } else if (targetObj is Type) { target = null; type = (Type)targetObj; return(true); } } var targetNode = node.GetExpression(throwOnError: false); if (targetNode == null) { if (bindingContext.Global == null) { var methodName = node.GetMethodName(throwOnError: false); bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_UNABLETORESOLVENAME, methodName ?? "<unknown>"), node); return(false); } target = bindingContext.Global; type = target.Type; } else if (bindingContext.TryResolveType(targetNode, out type)) { target = null; } else { if (TryBind(targetNode, bindingContext, TypeDescription.ObjectType, out target, out bindingError) == false) { return(false); } type = target.Type; } return(true); }
public static bool TryBind(SyntaxTreeNode node, BindingContext bindingContext, TypeDescription expectedType, out Expression boundExpression, out Exception bindingError) { if (node == null) { throw new ArgumentNullException("node"); } if (bindingContext == null) { throw new ArgumentNullException("bindingContext"); } if (expectedType == null) { throw new ArgumentNullException("expectedType"); } boundExpression = null; bindingError = null; var expressionType = node.GetExpressionType(throwOnError: true); var operandNode = node.GetExpression(throwOnError: true); var operand = default(Expression); var methodName = node.GetMethodName(throwOnError: false); var methodMember = default(MemberDescription); if (AnyBinder.TryBindInNewScope(operandNode, bindingContext, TypeDescription.ObjectType, out operand, out bindingError) == false) { return(false); } if (methodName != null) { bindingContext.TryResolveMember(methodName, out methodMember); } Debug.Assert(operand != null, "operand != null"); switch (expressionType) { case Constants.EXPRESSION_TYPE_NEGATE: if (ExpressionUtils.TryPromoteUnaryOperation(ref operand, ExpressionType.Negate, out boundExpression) == false) { // fixing b_u_g in mono expression compiler: Negate on float or double = exception if (operand.Type == typeof(double) || operand.Type == typeof(float)) { boundExpression = Expression.Multiply(operand, operand.Type == typeof(float) ? ExpressionUtils.NegativeSingle : ExpressionUtils.NegativeDouble); } else { boundExpression = Expression.Negate(operand, methodMember); } } break; case Constants.EXPRESSION_TYPE_NEGATE_CHECKED: if (ExpressionUtils.TryPromoteUnaryOperation(ref operand, ExpressionType.NegateChecked, out boundExpression) == false) { // fixing b_u_g in mono expression compiler: Negate on float or double = exception if (operand.Type == typeof(double) || operand.Type == typeof(float)) { boundExpression = Expression.Multiply(operand, operand.Type == typeof(float) ? ExpressionUtils.NegativeSingle : ExpressionUtils.NegativeDouble); } else { boundExpression = Expression.NegateChecked(operand, methodMember); } } break; case Constants.EXPRESSION_TYPE_COMPLEMENT: case Constants.EXPRESSION_TYPE_NOT: if (ExpressionUtils.TryPromoteUnaryOperation(ref operand, ExpressionType.Not, out boundExpression) == false) { boundExpression = Expression.Not(operand, methodMember); } break; case Constants.EXPRESSION_TYPE_UNARY_PLUS: if (ExpressionUtils.TryPromoteUnaryOperation(ref operand, ExpressionType.UnaryPlus, out boundExpression) == false) { boundExpression = Expression.UnaryPlus(operand, methodMember); } break; case Constants.EXPRESSION_TYPE_ARRAY_LENGTH: boundExpression = Expression.ArrayLength(operand); break; default: bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_UNKNOWNEXPRTYPE, expressionType), node); return(false); } return(true); }
public static bool TryBind(SyntaxTreeNode node, BindingContext bindingContext, TypeDescription expectedType, out Expression boundExpression, out Exception bindingError) { if (node == null) { throw new ArgumentNullException("node"); } if (bindingContext == null) { throw new ArgumentNullException("bindingContext"); } if (expectedType == null) { throw new ArgumentNullException("expectedType"); } boundExpression = null; bindingError = null; var target = default(Expression); var arguments = node.GetArguments(throwOnError: false); var methodName = node.GetMethodName(throwOnError: true); var useNullPropagation = node.GetUseNullPropagation(throwOnError: false); var methodMember = default(MemberDescription); if (bindingContext.TryResolveMember(methodName, out methodMember)) { if (methodMember.IsMethod == false) { bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_CALLMEMBERISNOTMETHOD, methodMember.Name, methodMember.DeclaringType), node); return(false); } var targetNode = node.GetExpression(throwOnError: true); if (AnyBinder.TryBind(targetNode, bindingContext, TypeDescription.ObjectType, out target, out bindingError) == false) { return(false); } float methodQuality; if (methodMember.TryMakeCall(target, arguments, bindingContext, out boundExpression, out methodQuality) == false) { bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_UNABLETOBINDMETHOD, methodMember.Name, target.Type, arguments.Count), node); return(false); } return(true); } var methodRef = default(TypeReference); if (BindingContext.TryGetMethodReference(methodName, out methodRef) == false) { bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_UNABLETORESOLVENAME, methodName), node); return(false); } var targetType = default(Type); if (TryBindTarget(node, bindingContext, out target, out targetType, out bindingError) == false) { return(false); } var isStatic = target == null; var selectedMethodQuality = MemberDescription.QUALITY_INCOMPATIBLE; var hasGenericParameters = methodRef.IsGenericType; var genericArguments = default(Type[]); if (hasGenericParameters) { genericArguments = new Type[methodRef.TypeArguments.Count]; for (var i = 0; i < genericArguments.Length; i++) { var typeArgument = methodRef.TypeArguments[i]; if (bindingContext.TryResolveType(typeArgument, out genericArguments[i]) == false) { bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_UNABLETORESOLVETYPE, typeArgument), node); return(false); } } } var targetTypeDescription = TypeDescription.GetTypeDescription(targetType); var foundMethod = default(MethodInfo); foreach (var memberDescription in targetTypeDescription.GetMembers(methodRef.Name)) { if (memberDescription.IsMethod == false) { continue; } var methodDescription = memberDescription; var method = (MethodInfo)memberDescription; foundMethod = foundMethod ?? method; if (method.IsStatic != isStatic || method.IsGenericMethod != hasGenericParameters) { continue; } if (hasGenericParameters && memberDescription.GenericArgumentsCount != methodRef.TypeArguments.Count) { continue; } if (hasGenericParameters) { try { methodDescription = methodDescription.MakeGenericMethod(genericArguments); method = methodDescription; } catch (ArgumentException exception) { bindingError = exception; continue; /* An element of typeArguments does not satisfy the constraints specified for the corresponding type parameter of the current generic method definition. */ } } var methodQuality = 0.0f; var methodCallExpression = default(Expression); if (methodDescription.TryMakeCall(target, arguments, bindingContext, out methodCallExpression, out methodQuality) == false) { continue; } if (float.IsNaN(methodQuality) || methodQuality <= selectedMethodQuality) { continue; } boundExpression = methodCallExpression; selectedMethodQuality = methodQuality; if (Math.Abs(methodQuality - MemberDescription.QUALITY_EXACT_MATCH) < float.Epsilon) { break; // best match } } if (bindingError != null) { return(false); } if (boundExpression == null) { if (foundMethod != null) { bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_UNABLETOBINDMETHOD, methodRef.Name, targetType, arguments.Count), node); } else { bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_UNABLETOBINDCALL, methodRef.Name, targetType, arguments.Count), node); } return(false); } if (useNullPropagation && target == null) { bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_UNABLETOAPPLYNULLCONDITIONALOPERATORONTYPEREF, targetType)); return(false); } if (useNullPropagation && targetTypeDescription.CanBeNull) { bindingContext.RegisterNullPropagationTarget(target); } if (targetTypeDescription.IsAssignableFrom(typeof(Type)) && bindingContext.IsKnownType(typeof(Type)) == false && (bindingContext.IsKnownType(targetType) == false || methodRef.Name.Equals("InvokeMember", StringComparison.Ordinal))) { bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_RESTRICTED_MEMBER_INVOCATION, methodName, targetType, typeof(ITypeResolver)), node); return(false); } return(true); }
public static bool TryBind(SyntaxTreeNode node, BindingContext bindingContext, TypeDescription expectedType, out Expression boundExpression, out Exception bindingError) { if (node == null) { throw new ArgumentNullException("node"); } if (bindingContext == null) { throw new ArgumentNullException("bindingContext"); } if (expectedType == null) { throw new ArgumentNullException("expectedType"); } boundExpression = null; bindingError = null; var expressionType = node.GetExpressionType(throwOnError: true); var left = node.GetLeftExpression(throwOnError: true); var right = node.GetRightExpression(throwOnError: true); var methodName = node.GetMethodName(throwOnError: false); var conversion = node.GetConversion(throwOnError: false); var leftOperand = default(Expression); var rightOperand = default(Expression); var conversionLambda = default(Expression); var methodMember = default(MemberDescription); if (AnyBinder.TryBindInNewScope(left, bindingContext, TypeDescription.ObjectType, out leftOperand, out bindingError) == false) { return(false); } if (AnyBinder.TryBindInNewScope(right, bindingContext, TypeDescription.ObjectType, out rightOperand, out bindingError) == false) { return(false); } if (methodName != null) { bindingContext.TryResolveMember(methodName, out methodMember); } if (conversion != null) { AnyBinder.TryBindInNewScope(conversion, bindingContext, TypeDescription.ObjectType, out conversionLambda, out bindingError); bindingError = null; } Debug.Assert(leftOperand != null, "leftOperand != null"); Debug.Assert(rightOperand != null, "rightOperand != null"); switch (expressionType) { case Constants.EXPRESSION_TYPE_ADD: if (leftOperand.Type == typeof(string) || rightOperand.Type == typeof(string)) { boundExpression = Expression.Call ( StringConcat.GetMethodInfo(), Expression.Convert(leftOperand, typeof(object)), Expression.Convert(rightOperand, typeof(object)) ); break; } else { if (ExpressionUtils.TryPromoteBinaryOperation(ref leftOperand, ref rightOperand, ExpressionType.Add, out boundExpression) == false) { boundExpression = Expression.Add(leftOperand, rightOperand); } break; } case Constants.EXPRESSION_TYPE_ADD_CHECKED: if (leftOperand.Type == typeof(string) || rightOperand.Type == typeof(string)) { boundExpression = Expression.Call ( StringConcat.GetMethodInfo(), Expression.Convert(leftOperand, typeof(object)), Expression.Convert(rightOperand, typeof(object)) ); break; } else { if (ExpressionUtils.TryPromoteBinaryOperation(ref leftOperand, ref rightOperand, ExpressionType.AddChecked, out boundExpression) == false) { boundExpression = Expression.AddChecked(leftOperand, rightOperand); } break; } case Constants.EXPRESSION_TYPE_SUBTRACT: if (ExpressionUtils.TryPromoteBinaryOperation(ref leftOperand, ref rightOperand, ExpressionType.Subtract, out boundExpression) == false) { boundExpression = Expression.Subtract(leftOperand, rightOperand, methodMember); } break; case Constants.EXPRESSION_TYPE_SUBTRACT_CHECKED: if (ExpressionUtils.TryPromoteBinaryOperation(ref leftOperand, ref rightOperand, ExpressionType.SubtractChecked, out boundExpression) == false) { boundExpression = Expression.SubtractChecked(leftOperand, rightOperand, methodMember); } break; case Constants.EXPRESSION_TYPE_LEFT_SHIFT: ExpressionUtils.TryPromoteUnaryOperation(ref leftOperand, ExpressionType.LeftShift, out boundExpression); ExpressionUtils.TryPromoteUnaryOperation(ref rightOperand, ExpressionType.LeftShift, out boundExpression); boundExpression = Expression.LeftShift(leftOperand, rightOperand, methodMember); break; case Constants.EXPRESSION_TYPE_RIGHT_SHIFT: ExpressionUtils.TryPromoteUnaryOperation(ref leftOperand, ExpressionType.RightShift, out boundExpression); ExpressionUtils.TryPromoteUnaryOperation(ref rightOperand, ExpressionType.RightShift, out boundExpression); boundExpression = Expression.RightShift(leftOperand, rightOperand, methodMember); break; case Constants.EXPRESSION_TYPE_GREATER_THAN: if (ExpressionUtils.TryPromoteBinaryOperation(ref leftOperand, ref rightOperand, ExpressionType.GreaterThan, out boundExpression) == false) { boundExpression = Expression.GreaterThan(leftOperand, rightOperand); } break; case Constants.EXPRESSION_TYPE_GREATER_THAN_OR_EQUAL: if (ExpressionUtils.TryPromoteBinaryOperation(ref leftOperand, ref rightOperand, ExpressionType.GreaterThanOrEqual, out boundExpression) == false) { boundExpression = Expression.GreaterThanOrEqual(leftOperand, rightOperand); } break; case Constants.EXPRESSION_TYPE_LESS_THAN: if (ExpressionUtils.TryPromoteBinaryOperation(ref leftOperand, ref rightOperand, ExpressionType.LessThan, out boundExpression) == false) { boundExpression = Expression.LessThan(leftOperand, rightOperand); } break; case Constants.EXPRESSION_TYPE_LESS_THAN_OR_EQUAL: if (ExpressionUtils.TryPromoteBinaryOperation(ref leftOperand, ref rightOperand, ExpressionType.LessThanOrEqual, out boundExpression) == false) { boundExpression = Expression.LessThanOrEqual(leftOperand, rightOperand); } break; case Constants.EXPRESSION_TYPE_POWER: var resultType = TypeDescription.GetTypeDescription(leftOperand.Type); var resultTypeUnwrap = resultType.IsNullable ? resultType.UnderlyingType : resultType; if (ExpressionUtils.TryPromoteBinaryOperation(ref leftOperand, ref rightOperand, ExpressionType.Power, out boundExpression) == false) { var operandsType = TypeDescription.GetTypeDescription(leftOperand.Type); var operandTypeUnwrap = operandsType.IsNullable ? operandsType.UnderlyingType : operandsType; var promoteToNullable = resultType.IsNullable || operandsType.IsNullable; if (operandTypeUnwrap != typeof(double) && leftOperand.Type == rightOperand.Type) { leftOperand = Expression.ConvertChecked(leftOperand, promoteToNullable ? typeof(double?) : typeof(double)); rightOperand = Expression.ConvertChecked(rightOperand, promoteToNullable ? typeof(double?) : typeof(double)); } boundExpression = Expression.Power(leftOperand, rightOperand, methodMember); if (resultType != typeof(double)) { boundExpression = Expression.ConvertChecked(boundExpression, promoteToNullable ? resultTypeUnwrap.GetNullableType() : resultTypeUnwrap); } } break; case Constants.EXPRESSION_TYPE_DIVIDE: if (ExpressionUtils.TryPromoteBinaryOperation(ref leftOperand, ref rightOperand, ExpressionType.Divide, out boundExpression) == false) { boundExpression = Expression.Divide(leftOperand, rightOperand, methodMember); } break; case Constants.EXPRESSION_TYPE_MULTIPLY: if (ExpressionUtils.TryPromoteBinaryOperation(ref leftOperand, ref rightOperand, ExpressionType.Multiply, out boundExpression) == false) { boundExpression = Expression.Multiply(leftOperand, rightOperand, methodMember); } break; case Constants.EXPRESSION_TYPE_MULTIPLY_CHECKED: if (ExpressionUtils.TryPromoteBinaryOperation(ref leftOperand, ref rightOperand, ExpressionType.MultiplyChecked, out boundExpression) == false) { boundExpression = Expression.MultiplyChecked(leftOperand, rightOperand, methodMember); } break; case Constants.EXPRESSION_TYPE_MODULO: if (ExpressionUtils.TryPromoteBinaryOperation(ref leftOperand, ref rightOperand, ExpressionType.Modulo, out boundExpression) == false) { boundExpression = Expression.Modulo(leftOperand, rightOperand, methodMember); } break; case Constants.EXPRESSION_TYPE_EQUAL: if (ExpressionUtils.TryPromoteBinaryOperation(ref leftOperand, ref rightOperand, ExpressionType.Equal, out boundExpression) == false) { boundExpression = Expression.Equal(leftOperand, rightOperand); } break; case Constants.EXPRESSION_TYPE_NOT_EQUAL: if (ExpressionUtils.TryPromoteBinaryOperation(ref leftOperand, ref rightOperand, ExpressionType.NotEqual, out boundExpression) == false) { boundExpression = Expression.NotEqual(leftOperand, rightOperand); } break; case Constants.EXPRESSION_TYPE_AND: if (ExpressionUtils.TryPromoteBinaryOperation(ref leftOperand, ref rightOperand, ExpressionType.And, out boundExpression) == false) { boundExpression = Expression.And(leftOperand, rightOperand, methodMember); } break; case Constants.EXPRESSION_TYPE_OR: if (ExpressionUtils.TryPromoteBinaryOperation(ref leftOperand, ref rightOperand, ExpressionType.Or, out boundExpression) == false) { boundExpression = Expression.Or(leftOperand, rightOperand, methodMember); } break; case Constants.EXPRESSION_TYPE_EXCLUSIVE_OR: if (ExpressionUtils.TryPromoteBinaryOperation(ref leftOperand, ref rightOperand, ExpressionType.ExclusiveOr, out boundExpression) == false) { boundExpression = Expression.ExclusiveOr(leftOperand, rightOperand, methodMember); } break; case Constants.EXPRESSION_TYPE_AND_ALSO: boundExpression = Expression.AndAlso(leftOperand, rightOperand, methodMember); break; case Constants.EXPRESSION_TYPE_OR_ELSE: boundExpression = Expression.OrElse(leftOperand, rightOperand, methodMember); break; case Constants.EXPRESSION_TYPE_COALESCE: if (ExpressionUtils.TryPromoteBinaryOperation(ref leftOperand, ref rightOperand, ExpressionType.Coalesce, out boundExpression) == false) { boundExpression = Expression.Coalesce(leftOperand, rightOperand, conversionLambda as LambdaExpression); } break; default: bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_UNKNOWNEXPRTYPE, expressionType), node); return(false); } return(true); }