示例#1
0
        private void InvokeArgLess(DynamicMetaObject target, DynamicMetaObject scriptContext, DRoutineDesc method, DynamicMetaObject[] args, out BindingRestrictions restrictions, out Expression invokeMethodExpr)
        {
            int argsWithoutScriptContext = RealMethodArgumentCount - 1;

            System.Reflection.MethodInfo miAddFrame = Methods.PhpStack.AddFrame.Overload(argsWithoutScriptContext);

            Expression[] argsExpr = null;
            if (miAddFrame == Methods.PhpStack.AddFrame.N)
            {
                //Create array of arguments
                argsExpr    = new Expression[1];
                argsExpr[0] = Expression.NewArrayInit(Types.Object[0], BinderHelper.PackToExpressions(args, 0, argsWithoutScriptContext));
            }
            else
            {
                //call overload with < N arguments
                //argsExpr = new Expression[argsWithoutScriptContext];
                argsExpr = BinderHelper.PackToExpressions(args, 0, argsWithoutScriptContext);
            }

            var stack = Expression.Field(scriptContext.Expression,
                                         Fields.ScriptContext_Stack);

            // scriptContext.PhpStack
            // PhpStack.Add( args )
            // call argless stub
            invokeMethodExpr = Expression.Block(_returnType,
                                                Expression.Call(
                                                    stack,
                                                    miAddFrame, argsExpr),
                                                Expression.Assign(
                                                    Expression.Field(stack, Fields.PhpStack_AllowProtectedCall),
                                                    Expression.Constant(true, Types.Bool[0])),
                                                HandleResult(
                                                    Expression.Call(method.ArglessStubMethod,
                                                                    target.Expression,
                                                                    stack),
                                                    method.ArglessStubMethod.ReturnType));

            restrictions = target.Restrictions;
        }
示例#2
0
        /// <summary>
        /// This method binds rules for PhpMethod
        /// </summary>
        private void InvokePhpMethod(DynamicMetaObject /*!*/ target, DynamicMetaObject[] /*!!*/ args, /*object targetObj,*/ PhpRoutine /*!*/ routine, out BindingRestrictions restrictions, out Expression invokeMethodExpr)
        {
            Debug.Assert(target != null && target.Value != null);
            Debug.Assert(!(target.Value is IClrValue), "PhpRoutine should not be declared on CLR value type!");

            /*if (target.Value is PhpObject)
             * {
             *  // Restriction: typeof(target) == |target.TypeDesc.RealType|
             *  var targetPhpObj = (PhpObject)target.Value;
             *  Debug.Assert(targetPhpObj.TypeDesc.RealType == target.LimitType);
             *  Debug.Assert(target.Value.GetType() == target.LimitType);
             *  restrictions = BindingRestrictions.GetTypeRestriction(target.Expression, targetPhpObj.TypeDesc.RealType);
             * }
             * else*/
            Debug.Assert(typeof(ClrObject).IsSealed);   // just to ensure following condition is correct
            if (target.Value.GetType() == typeof(ClrObject))
            {
                target       = new ClrDynamicMetaObject(target); // unwrap the real object, get restrictions
                restrictions = target.Restrictions;
            }
            else
            {
                Debug.Assert(target.Value.GetType() == target.LimitType);   // just for sure
                Debug.Assert(!(target.Value is PhpObject) || ((PhpObject)target.Value).TypeDesc.RealType == target.LimitType);

                restrictions = BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType);
            }

            BindingRestrictions argumentsRestrictions;

            Expression[] arguments;

            if (routine.Name != PHP.Core.Reflection.DObject.SpecialMethodNames.Call)
            {
                args = GetArgumentsRange(args, 0, RealMethodArgumentCount);// This can't be done when _call method is invoked

                //Check if method has ArgAware attribute
                if ((routine.Properties & RoutineProperties.IsArgsAware) != 0 ||
                    routine.IsStatic)// this is because of hack in PHP.Library.XML library static methods that can be also called like instance methods
                {
                    DynamicMetaObject scriptContext = args[0];

                    //Select arguments without scriptContext
                    DynamicMetaObject[] realArgs = GetArgumentsRange(args, 1, RealMethodArgumentCount - 1);

                    InvokeArgLess(target, scriptContext, routine.RoutineDesc, realArgs, out argumentsRestrictions, out invokeMethodExpr);
                    restrictions = restrictions.Merge(argumentsRestrictions);
                    return;
                }

                arguments    = routine.PrepareArguments(args, _genericParamsCount, _paramsCount, out argumentsRestrictions);
                restrictions = restrictions.Merge(argumentsRestrictions);
            }
            else
            {
                arguments = BinderHelper.PackToExpressions(args);
            }

            //((PhpObject)target))
            var realObjEx = Expression.Convert(target.Expression, routine.ArgFullInfo.DeclaringType);//targetObj.TypeDesc.RealType);

            //ArgFull( ((PhpObject)target), ScriptContext, args, ... )
            invokeMethodExpr = Expression.Call(BinderHelper.WrapInstanceMethodCall(routine.ArgFullInfo),
                                               BinderHelper.CombineArguments(realObjEx, arguments));

            invokeMethodExpr = ReturnArgumentHelpers.ReturnValueConversion(routine.ArgFullInfo, invokeMethodExpr);

            invokeMethodExpr = HandleResult(invokeMethodExpr, routine.ArgFullInfo.ReturnType, false);
        }
示例#3
0
        private void InvokeCallMethod(DynamicMetaObject target,
                                      DynamicMetaObject /*!*/[] args,
                                      DObject /*!*/ obj,
                                      DRoutineDesc /*!*/ method,
                                      out BindingRestrictions restrictions,
                                      out Expression invokeMethodExpr)
        {
            var insideCaller = Expression.Property(
                Expression.Convert(target.Expression, Types.DObject[0]),
                Properties.DObject_InsideCaller);

            if (argsArrayVariable == null)
            {
                argsArrayVariable = Expression.Parameter(Types.PhpArray[0], "args");
            }

            if (retValVariable == null)
            {
                retValVariable = Expression.Parameter(Types.Object[0], "retVal");
            }

            ParameterExpression[] vars = new ParameterExpression[] { argsArrayVariable, retValVariable };

            // Just select real method arguments without ScriptContext and generic type arguments
            var justParams = BinderHelper.PackToExpressions(args, 1 + _genericParamsCount, _paramsCount);

            // Expression which calls ((PhpArray)argArray).add method on each real method argument.
            var initArgsArray = Array.ConvertAll <Expression, Expression>(justParams, (x) => Expression.Call(argsArrayVariable, Methods.PhpHashtable_Add, x));

            // Argfull __call signature: (ScriptContext, object, object)->object
            var callerMethodArgs = new DynamicMetaObject[3] {
                args[0],
                new DynamicMetaObject(Expression.Constant(ActualMethodName), BindingRestrictions.Empty),
                new DynamicMetaObject(argsArrayVariable, BindingRestrictions.Empty)
            };

            // what if method.PhpRoutine is null
            InvokePhpMethod(target, callerMethodArgs, /*(PhpObject)target.Value, */ method.PhpRoutine, out restrictions, out invokeMethodExpr);


            //Expression:
            // if (target.insideCaller)
            //      throw new UndefinedMethodException();
            //
            // args = new PhpArray(paramsCount, 0);
            //
            // args.Add(arg0);
            // .
            // .
            // args.Add(paramsCount);
            //
            // target.insideCaller = true;
            // try
            // {
            //     ret_val = target.__call( scriptContext, methodName, args);
            // }
            // finally
            // {
            //     target.insideCaller = false;
            // }
            // return ret_val;
            //
            invokeMethodExpr = Expression.Block(
                vars,//local variables
                Expression.IfThen(Expression.Property(
                                      Expression.Convert(target.Expression, Types.DObject[0]),
                                      Properties.DObject_InsideCaller),
                                  Expression.Call(Methods.PhpException.UndefinedMethodCalled, Expression.Constant(obj.TypeName), Expression.Constant(ActualMethodName))),

                Expression.Assign(
                    argsArrayVariable,
                    Expression.New(Constructors.PhpArray.Int32_Int32,
                                   Expression.Constant(_paramsCount),
                                   Expression.Constant(0))),

                ((initArgsArray.Length == 0) ? (Expression)Expression.Empty() : Expression.Block(initArgsArray)),

                Expression.Assign(insideCaller,
                                  Expression.Constant(true)),
                Expression.TryFinally(
                    //__call(caller,args)
                    Expression.Assign(retValVariable, invokeMethodExpr),
                    //Finally part:
                    Expression.Assign(insideCaller,
                                      Expression.Constant(false))
                    ),
                HandleResult(retValVariable, method.PhpRoutine.ArgFullInfo.ReturnType, false));
        }