private static bool TryBindToType(SyntaxTreeNode node, object typeName, ArgumentsTree arguments, BindingContext bindingContext, TypeDescription expectedType, out Expression boundExpression, out Exception bindingError) { boundExpression = null; bindingError = null; var type = default(Type); if (bindingContext.TryResolveType(typeName, out type) == false) { bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_UNABLETORESOLVETYPE, typeName), node); return(false); } var typeDescription = TypeDescription.GetTypeDescription(type); // feature: lambda building via new Func() var lambdaArgument = default(SyntaxTreeNode); if (typeDescription.IsDelegate && arguments.Count == 1 && (lambdaArgument = arguments.Values.Single()).GetExpressionType(throwOnError: true) == Constants.EXPRESSION_TYPE_LAMBDA) { return(LambdaBinder.TryBind(lambdaArgument, bindingContext, typeDescription, out boundExpression, out bindingError)); } var selectedConstructorQuality = MemberDescription.QUALITY_INCOMPATIBLE; foreach (var constructorDescription in typeDescription.Constructors) { var constructorQuality = MemberDescription.QUALITY_INCOMPATIBLE; var constructorCall = default(Expression); if (constructorDescription.TryMakeCall(null, arguments, bindingContext, out constructorCall, out constructorQuality) == false) { continue; } if (float.IsNaN(constructorQuality) || constructorQuality <= selectedConstructorQuality) { continue; } boundExpression = constructorCall; selectedConstructorQuality = constructorQuality; if (Math.Abs(constructorQuality - MemberDescription.QUALITY_EXACT_MATCH) < float.Epsilon) { break; // best match } } if (boundExpression == null) { bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_UNABLETOBINDCONSTRUCTOR, type), node); return(false); } return(true); }
public bool TryMakeCall(Expression target, ArgumentsTree argumentsTree, BindingContext bindingContext, out Expression expression, out float expressionQuality) { if (argumentsTree == null) { throw new ArgumentNullException("argumentsTree"); } if (bindingContext == null) { throw new ArgumentNullException("bindingContext"); } if (!this.IsStatic && !this.IsConstructor && target == null) { throw new ArgumentNullException("target"); } expression = null; expressionQuality = QUALITY_INCOMPATIBLE; if (this.member is MethodBase == false) { return(false); } // check argument count if (argumentsTree.Count > this.parameters.Length) { return(false); // not all arguments are bound to parameters } var requiredParametersCount = this.parameters.Length - this.parameters.Count(p => p.IsOptional); if (argumentsTree.Count < requiredParametersCount) { return(false); // not all required parameters has values } // bind arguments var parametersQuality = 0.0f; var arguments = default(Expression[]); foreach (var argumentName in argumentsTree.Keys) { var parameter = default(ParameterInfo); var parameterIndex = 0; if (HasDigitsOnly(argumentName)) { parameterIndex = int.Parse(argumentName, Constants.DefaultFormatProvider); if (parameterIndex >= this.parameters.Length) { return(false); // position out of range } parameter = this.parameters[parameterIndex]; if (argumentsTree.ContainsKey(parameter.Name)) { return(false); // positional intersects named } } else { if (this.parametersByName.TryGetValue(argumentName, out parameter) == false) { return(false); // parameter is not found } parameterIndex = parameter.Position; } var expectedType = TypeDescription.GetTypeDescription(parameter.ParameterType); var argValue = default(Expression); var bindingError = default(Exception); if (AnyBinder.TryBindInNewScope(argumentsTree[argumentName], bindingContext, expectedType, out argValue, out bindingError) == false) { return(false); } Debug.Assert(argValue != null, "argValue != null"); var quality = 0.0f; if (ExpressionUtils.TryMorphType(ref argValue, expectedType, out quality) == false || quality <= 0) { return(false); // failed to bind parameter } parametersQuality += quality; // casted if (arguments == null) { arguments = new Expression[this.parameters.Length]; } arguments[parameterIndex] = argValue; } if (this.parameters.Length > 0) { if (arguments == null) { arguments = new Expression[this.parameters.Length]; } for (var i = 0; i < arguments.Length; i++) { if (arguments[i] != null) { continue; } var parameter = this.parameters[i]; if (parameter.IsOptional == false) { return(false); // missing required parameter } var typeDescription = TypeDescription.GetTypeDescription(parameter.ParameterType); arguments[i] = typeDescription.DefaultExpression; parametersQuality += TypeConversion.QUALITY_SAME_TYPE; } expressionQuality = parametersQuality / this.parameters.Length; } else { expressionQuality = QUALITY_EXACT_MATCH; } if (this.member is MethodInfo) { if (this.IsStatic) { expression = Expression.Call((MethodInfo)this.member, arguments); } else { expression = Expression.Call(target, (MethodInfo)this.member, arguments); } return(true); } else if (this.member is ConstructorInfo) { expression = Expression.New((ConstructorInfo)this.member, arguments); return(true); } expressionQuality = QUALITY_INCOMPATIBLE; return(false); }
private static bool TryBindToMethod(SyntaxTreeNode node, object methodName, ArgumentsTree arguments, BindingContext bindingContext, TypeDescription expectedType, out Expression boundExpression, out Exception bindingError) { boundExpression = null; bindingError = null; var constructorDescription = default(MemberDescription); if (bindingContext.TryResolveMember(methodName, out constructorDescription) == false || constructorDescription.IsConstructor == false) { bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_UNABLETOBINDCONSTRUCTOR, methodName), node); return(false); } var typeDescription = TypeDescription.GetTypeDescription(constructorDescription.DeclaringType); // feature: lambda building via new Func() var lambdaArgument = default(SyntaxTreeNode); if (typeDescription.IsDelegate && arguments.Count == 1 && (lambdaArgument = arguments.Values.Single()).GetExpressionType(throwOnError: true) == Constants.EXPRESSION_TYPE_LAMBDA) { return(LambdaBinder.TryBind(lambdaArgument, bindingContext, typeDescription, out boundExpression, out bindingError)); } var constructorQuality = MemberDescription.QUALITY_INCOMPATIBLE; if (constructorDescription.TryMakeCall(null, arguments, bindingContext, out boundExpression, out constructorQuality)) { return(true); } bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_UNABLETOBINDCONSTRUCTOR, constructorDescription.DeclaringType), node); return(false); }
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 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.TypeArguments.Count > 0; 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); foreach (var memberDescription in targetTypeDescription.GetMembers(methodRef.Name)) { if (memberDescription.IsMethod == false) { continue; } var methodDescription = memberDescription; var method = (MethodInfo)memberDescription; if (method == null || 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 (method == Constants.GetTypeMethod && bindingContext.IsKnownType(typeof(Type)) == false) { bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_RESTRICTED_METHOD_INVOCATION, method.Name, typeof(Type), typeof(ITypeResolver)), node); return(false); } } if (bindingError != null) { return(false); } if (boundExpression == null) { 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); } 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 targetNode = node.GetExpression(throwOnError: true); var typeName = node.GetTypeName(throwOnError: true); var type = default(Type); if (bindingContext.TryResolveType(typeName, out type) == false) { bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_UNABLETORESOLVETYPE, typeName), node); return(false); } var target = default(Expression); if (AnyBinder.TryBindInNewScope(targetNode, bindingContext, TypeDescription.ObjectType, out target, out bindingError) == false) { return(false); } Debug.Assert(target != null, "target != null"); switch (expressionType) { case Constants.EXPRESSION_TYPE_TYPEIS: boundExpression = Expression.TypeIs(target, type); break; case Constants.EXPRESSION_TYPE_TYPEAS: boundExpression = Expression.TypeAs(target, type); break; case Constants.EXPRESSION_TYPE_CONVERT: boundExpression = Expression.Convert(target, type); break; case Constants.EXPRESSION_TYPE_CONVERTCHECKED: boundExpression = Expression.ConvertChecked(target, type); break; default: boundExpression = null; 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; if (expectedType.HasGenericParameters || !expectedType.IsDelegate) { bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_VALIDDELEGATETYPEISEXPECTED, expectedType != null ? expectedType.ToString() : "<null>")); return(false); } var expressionType = node.GetExpressionType(throwOnError: true); var bodyNode = node.GetExpression(throwOnError: true); var argumentsTree = node.GetArguments(throwOnError: false); var lambdaInvokeMethod = expectedType.GetMembers(Constants.DELEGATE_INVOKE_NAME).FirstOrDefault(m => m.IsMethod && !m.IsStatic); if (lambdaInvokeMethod == null) { bindingError = new MissingMethodException(expectedType.ToString(), Constants.DELEGATE_INVOKE_NAME); return(false); } if (lambdaInvokeMethod.GetParametersCount() != argumentsTree.Count) { bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_INVALIDLAMBDAARGUMENTS, expectedType)); return(false); } var argumentNames = new string[argumentsTree.Count]; for (var i = 0; i < argumentNames.Length; i++) { var argumentNameTree = default(SyntaxTreeNode); if (argumentsTree.TryGetValue(i, out argumentNameTree) == false || argumentNameTree == null || argumentNameTree.GetExpressionType(throwOnError: true) != Constants.EXPRESSION_TYPE_PROPERTY_OR_FIELD) { bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_MISSINGATTRONNODE, Constants.EXPRESSION_ATTRIBUTE, expressionType), node); return(false); } argumentNames[i] = argumentNameTree.GetPropertyOrFieldName(throwOnError: true); } var lambdaParameters = new ParameterExpression[argumentsTree.Count]; for (var i = 0; i < argumentsTree.Count; i++) { lambdaParameters[i] = Expression.Parameter(lambdaInvokeMethod.GetParameter(i).ParameterType, argumentNames[i]); } var currentParameters = bindingContext.Parameters; var newParameters = new List <ParameterExpression>(lambdaParameters.Length + currentParameters.Count); // add all lambda's parameters newParameters.AddRange(lambdaParameters); // add closure parameters foreach (var parameterExpr in currentParameters) { if (Array.IndexOf(argumentNames, parameterExpr.Name) < 0) { newParameters.Add(parameterExpr); } } var nestedBindingContext = bindingContext.CreateNestedContext(newParameters.AsReadOnly(), lambdaInvokeMethod.ResultType); var body = default(Expression); if (AnyBinder.TryBindInNewScope(bodyNode, nestedBindingContext, TypeDescription.GetTypeDescription(lambdaInvokeMethod.ResultType), out body, out bindingError) == false) { return(false); } Debug.Assert(body != null, "body != null"); boundExpression = Expression.Lambda(expectedType, body, lambdaParameters); return(true); }
public static bool TryBindMethodCall(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"); } // bindingError could return null from this method bindingError = null; boundExpression = null; var methodNameNode = node.GetExpression(throwOnError: true); var methodNameNodeType = methodNameNode.GetExpressionType(throwOnError: true); if (methodNameNodeType != Constants.EXPRESSION_TYPE_PROPERTY_OR_FIELD) { return(false); } var methodTargetNode = methodNameNode.GetExpression(throwOnError: false); var methodTarget = default(Expression); var type = default(Type); var typeReference = default(TypeReference); var isStatic = false; if (methodTargetNode == null && bindingContext.Global != null) { methodTarget = bindingContext.Global; type = methodTarget.Type; isStatic = false; } else if (methodTargetNode == null) { var methodName = methodNameNode.GetPropertyOrFieldName(throwOnError: false); bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_UNABLETORESOLVENAME, methodName ?? "<unknown>"), node); return(false); } else if (BindingContext.TryGetTypeReference(methodTargetNode, out typeReference) && bindingContext.TryResolveType(typeReference, out type)) { isStatic = true; } else if (AnyBinder.TryBind(methodTargetNode, bindingContext, TypeDescription.ObjectType, out methodTarget, out bindingError)) { Debug.Assert(methodTarget != null, "methodTarget != null"); isStatic = false; type = methodTarget.Type; } else { if (typeReference != null && bindingError == null) { bindingError = new ExpressionParserException(string.Format(Properties.Resources.EXCEPTION_BIND_UNABLETORESOLVETYPE, typeReference), node); } return(false); } var methodRef = default(TypeReference); if (type == null || BindingContext.TryGetMethodReference(methodNameNode, out methodRef) == false) { return(false); } var typeDescription = TypeDescription.GetTypeDescription(type); foreach (var member in typeDescription.GetMembers(methodRef.Name)) { if (member.IsMethod == false || member.IsStatic != isStatic) { continue; } var callNode = new SyntaxTreeNode(new Dictionary <string, object> { { Constants.EXPRESSION_ATTRIBUTE, methodTarget ?? (object)type }, { Constants.ARGUMENTS_ATTRIBUTE, node.GetValueOrDefault(Constants.ARGUMENTS_ATTRIBUTE, default(object)) }, { Constants.METHOD_ATTRIBUTE, methodRef }, { Constants.USE_NULL_PROPAGATION_ATTRIBUTE, methodNameNode.GetValueOrDefault(Constants.USE_NULL_PROPAGATION_ATTRIBUTE, default(object)) }, { Constants.EXPRESSION_POSITION, methodNameNode.GetPosition(throwOnError: false) } }); return(CallBinder.TryBind(callNode, bindingContext, expectedType, out boundExpression, out bindingError)); } return(false); }