예제 #1
0
        public override DynamicMetaObject FallbackInvokeMember(
            DynamicMetaObject target, DynamicMetaObject[] args,
            DynamicMetaObject errorSuggestion)
        {
            var deferArgs = Runtime.CheckDeferArgs(target, args);

            if (deferArgs != null)
            {
                return(Defer(deferArgs));
            }

            var limitType = target.LimitType;
            var name      = Name.LispToPascalCaseName();

            if (target.Value == null)
            {
                return(Runtime.CheckTargetNullReference(target,
                                                        "Cannot invoke a method on a null reference:"
                                                        + limitType.FullName + "." + name + Runtime.CollectParameterInfo(target, args)));
            }

            var builtin = Runtime.FindImportedFunction(limitType, Name);

            if (builtin != null)
            {
                DynamicMetaObject result;
                if (builtin.TryBindInvokeBestInstanceMethod(false, target, target, args, out result))
                {
                    return(result);
                }
            }

            var  flags   = BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy;
            var  methods = new List <CandidateMethod <MethodInfo> >();
            bool createdParamArray;

            foreach (var m in limitType.GetMember(name, flags))
            {
                MethodInfo mi;

                if (m is PropertyInfo)
                {
                    mi = ((PropertyInfo)m).GetGetMethod();
                }
                else
                {
                    mi = m as MethodInfo;
                }

                if (mi != null && Runtime.ParametersMatchArguments(mi.GetParameters(), args, out createdParamArray))
                {
                    Runtime.InsertInMostSpecificOrder(methods, mi, createdParamArray);
                }
            }

            if (methods.Count == 0 && (Name.StartsWith("set-") || Name.StartsWith("get-")))
            {
                // Fallback to special handling to change .set-bla to .set_bla if the former has failed.
                name = Name.Left(3) + "_" + Name.Substring(4).LispToPascalCaseName();

                foreach (var m in limitType.GetMember(name, flags))
                {
                    MethodInfo mi;

                    if (m is PropertyInfo)
                    {
                        mi = ((PropertyInfo)m).GetGetMethod();
                    }
                    else
                    {
                        mi = m as MethodInfo;
                    }

                    if (mi != null && Runtime.ParametersMatchArguments(mi.GetParameters(), args, out createdParamArray))
                    {
                        Runtime.InsertInMostSpecificOrder(methods, mi, createdParamArray);
                    }
                }
            }

            var restrictions = Runtime.GetTargetArgsRestrictions(target, args, false);

            if (methods.Count == 0)
            {
                return(errorSuggestion ?? Runtime.CreateThrow(target, args, restrictions, typeof(MissingMemberException),
                                                              "No (suitable) method found: " + limitType.FullName + "." + name + Runtime.CollectParameterInfo(target, args)));
            }
            else
            {
                var        method    = methods[0].Method;
                var        callArgs2 = Runtime.ConvertArguments(args, method.GetParameters());
                Expression expr;

                if (method.IsStatic)
                {
                    // NOT REACHED
                    // static
                    // extension with target as extra parameter
                    expr = Expression.Call(method, callArgs2);
                }
                else
                {
                    expr = Expression.Call(Expression.Convert(target.Expression, limitType), method, callArgs2);
                }

                return(new DynamicMetaObject(Runtime.EnsureObjectResult(expr), restrictions));
            }
        }