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); }
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); }
private static void RenderArguments(ArgumentsTree arguments, StringBuilder builder, bool checkedScope) { if (arguments == null) { throw new ArgumentNullException("arguments"); } if (builder == null) { throw new ArgumentNullException("builder"); } var firstArgument = true; foreach (var argumentName in arguments.Keys) { var positionalArguments = new SortedDictionary <int, SyntaxTreeNode>(); var namedArguments = new SortedDictionary <string, SyntaxTreeNode>(); var position = default(int); if (int.TryParse(argumentName, out position)) { positionalArguments[position] = arguments[argumentName]; } else { namedArguments[argumentName] = arguments[argumentName]; } foreach (var argument in positionalArguments.Values) { if (!firstArgument) { builder.Append(", "); } Render(argument, builder, true, checkedScope); firstArgument = false; } foreach (var argumentKv in namedArguments) { if (!firstArgument) { builder.Append(", "); } builder.Append(argumentKv.Key).Append(": "); Render(argumentKv.Value, builder, true, checkedScope); firstArgument = false; } } }
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.parameters == null) // not a method, constructor, indexer { 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(this, arguments); } else if (this.Name == Constants.DELEGATE_INVOKE_NAME && this.DeclaringType.IsDelegate) { expression = Expression.Invoke(target, arguments); } else { expression = Expression.Call(target, this, arguments); } return(true); } else if (this.member is ConstructorInfo) { expression = Expression.New((ConstructorInfo)this.member, arguments); return(true); } else if (this.member is PropertyInfo) { if (this.IsStatic) { expression = Expression.Call(this, arguments); } else { expression = Expression.Call(target, this, arguments); } return(true); } expressionQuality = QUALITY_INCOMPATIBLE; return(false); }