Esempio n. 1
0
        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);
        }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
        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);
        }
Esempio n. 4
0
        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);
        }