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; }
/// <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); }
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)); }