예제 #1
0
        protected override Expression BindMissingMethod(CallSiteContext bound)
        {
            var type = bound.TargetType;

            if (type == null)   // already reported - class cannot be found
            {
                return(ConvertExpression.BindDefault(this.ReturnType));
            }

            if (bound.TargetInstance != null && bound.CurrentTargetInstance != null) // it has been checked it is a subclass of TargetType
            {
                // ensure current scope's __call() is favoured over the specified class
                type = bound.CurrentTargetInstance.GetPhpTypeInfo();
            }

            // try to find __call() first if we have $this
            var call = (bound.TargetInstance != null) ? BinderHelpers.FindMagicMethod(type, TypeMethods.MagicMethods.__call) : null;

            if (call == null)
            {
                // look for __callStatic()
                call = BinderHelpers.FindMagicMethod(type, TypeMethods.MagicMethods.__callstatic);
            }

            if (call != null)
            {
                Expression[] call_args;

                var name_expr = (_name != null) ? Expression.Constant(_name) : bound.IndirectName;

                if (call.Methods.All(IsClrMagicCallWithParams))
                {
                    // Template: target.__call(name, arg1, arg2, ...)
                    // flatterns the arguments:
                    call_args = ArrayUtils.AppendRange(name_expr, bound.Arguments);
                }
                else
                {
                    // Template: target.__call(name, array)
                    // regular PHP behavior:
                    call_args = new Expression[]
                    {
                        name_expr,
                        BinderHelpers.NewPhpArray(bound.Arguments, bound.Context, bound.ClassContext),
                    };
                }

                return(OverloadBinder.BindOverloadCall(_returnType, bound.TargetInstance, call.Methods, bound.Context, call_args,
                                                       isStaticCallSyntax: true,
                                                       lateStaticType: bound.TargetType,
                                                       classContext: bound.ClassContext));
            }

            //
            return(base.BindMissingMethod(bound));
        }
예제 #2
0
        public static Expression BindToCall(Expression instance, MethodBase method, Expression ctx, OverloadBinder.ArgumentsBinder args)
        {
            Debug.Assert(method is MethodInfo || method is ConstructorInfo);

            var ps = method.GetParameters();
            var boundargs = new Expression[ps.Length];

            int argi = 0;

            for (int i = 0; i < ps.Length; i++)
            {
                var p = ps[i];
                if (argi == 0 && p.IsImplicitParameter())
                {
                    if (p.IsContextParameter())
                        boundargs[i] = ctx;
                    else
                        throw new NotImplementedException();
                }
                else
                {
                    if (i == ps.Length - 1 && p.IsParamsParameter())
                    {
                        var element_type = p.ParameterType.GetElementType();
                        boundargs[i] = args.BindParams(argi, element_type);
                        break;
                    }
                    else
                    {
                        boundargs[i] = args.BindArgument(argi, p);
                    }

                    //
                    argi++;
                }
            }

            //
            Debug.Assert(boundargs.All(x => x != null));

            //
            if (method.IsStatic)
            {
                instance = null;
            }

            //
            if (method.IsConstructor)
            {
                return Expression.New((ConstructorInfo)method, boundargs);
            }

            if (instance != null && method.IsVirtual)
            {
                // Ugly hack here,
                // we NEED to call the method nonvirtually, but LambdaCompiler emits .callvirt always and there is no way how to change it (except we can emit all the stuff by ourselfs).
                // We use DynamicMethod to emit .call inside, and use its MethodInfo which is static.
                // LambdaCompiler generates .call to static DynamicMethod which calls our method via .call as well,
                // after all the inlining, there should be no overhead.

                method = WrapInstanceMethodToStatic((MethodInfo)method);

                //
                var newargs = new Expression[boundargs.Length + 1];
                newargs[0] = instance;
                Array.Copy(boundargs, 0, newargs, 1, boundargs.Length);
                boundargs = newargs;
                instance = null;
            }

            //
            return Expression.Call(instance, (MethodInfo)method, boundargs);
        }