///// <summary> ///// Returns methodName from Args ///// </summary> ///// <param name="args"></param> ///// <returns></returns> //protected DynamicMetaObject GetRuntimeMethodName(DynamicMetaObject[] args) //{ // //if (args.Length == this.genericParamsCount + this.paramsCount + 3) // args contains ClassContext // // return args[this.genericParamsCount + this.paramsCount + 2]; // //else if (args.Length == this.genericParamsCount + this.paramsCount + 2) // // return args[this.genericParamsCount + this.paramsCount + 1]; // //throw new InvalidOperationException(); // return args[args.Length - 1]; //} protected override DynamicMetaObject /*!*/ FallbackInvokeMember( DynamicMetaObject target, DynamicMetaObject[] args) { Debug.Assert(Types.String[0].IsAssignableFrom(args[args.Length - 1].LimitType), "Wrong field name type!"); DynamicMetaObject dmoMethodName = args[args.Length - 1]; string name = PhpVariable.AsString(dmoMethodName.Value); if (name == null) { //PhpException.Throw(PhpError.Error, CoreResources.GetString("invalid_method_name")); //return new PhpReference() | null; return(DoAndReturnDefault( BinderHelper.ThrowError("invalid_method_name"), target.Restrictions)); throw new NotImplementedException(); } else { // Restriction: PhpVariable.AsString(methodName) == |methodName| BindingRestrictions restrictions = BindingRestrictions.GetExpressionRestriction( Expression.Equal( Expression.Call(Methods.PhpVariable.AsString, dmoMethodName.Expression), Expression.Constant(dmoMethodName.Value, Types.String[0]))); actualMethodName = name; //transform arguments that it doesn't contains methodName Array.Resize <DynamicMetaObject>(ref args, args.Length - 1); DynamicMetaObject result = base.FallbackInvokeMember(target, args); return(new DynamicMetaObject( result.Expression, result.Restrictions.Merge(restrictions)));//TODO: Creation of this can be saved } }
protected override DynamicMetaObject /*!*/ FallbackInvokeMember(DynamicMetaObject target /*!*/, DynamicMetaObject /*!*/[] /*!*/ args) { Expression invokeMethodExpr; DObject obj = target.Value as DObject;// target.Value can be something else which isn't DObject ? WrappedClrDynamicMetaObject wrappedTarget = null; bool invokeCallMethod = false; // Restrictions BindingRestrictions restrictions; BindingRestrictions classContextRestrictions = BindingRestrictions.Empty; BindingRestrictions defaultRestrictions = BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType); DTypeDesc classContext = this._classContext; if (!ClassContextIsKnown)//ClassContext wasn't supplied during creation of binder => put it into restriction { Debug.Assert(args.Length > RealMethodArgumentCount, "Not enough arguments!"); DynamicMetaObject dmoRuntimeClassContext = GetRuntimeClassContext(args); Debug.Assert(dmoRuntimeClassContext.Value == null || Types.DTypeDesc[0].IsAssignableFrom(dmoRuntimeClassContext.LimitType), "Wrong class context type!"); classContext = (DTypeDesc)dmoRuntimeClassContext.Value; Debug.Assert(classContext == null || !classContext.IsUnknown, "Class context should be known at run time!"); classContextRestrictions = BindingRestrictions.GetInstanceRestriction(dmoRuntimeClassContext.Expression, classContext); defaultRestrictions = defaultRestrictions.Merge(classContextRestrictions); } if (obj == null) { if (target.Value != null && Configuration.Application.Compiler.ClrSemantics) { // TODO: some normalizing conversions (PhpString, PhpBytes -> string): target = new WrappedClrDynamicMetaObject(target); obj = target.Value as DObject; wrappedTarget = target as WrappedClrDynamicMetaObject; Debug.Assert(obj != null); } else { //defaultRestrictions = defaultRestrictions.Merge(BindingRestrictions.GetTypeRestriction if (target.Value == null) { defaultRestrictions = BindingRestrictions.GetInstanceRestriction(target.Expression, null); } return(DoAndReturnDefault( BinderHelper.ThrowError("method_called_on_non_object", ActualMethodName), defaultRestrictions)); } } // obtain the appropriate method table DTypeDesc type_desc = obj.TypeDesc; // perform method lookup DRoutineDesc method; GetMemberResult result = type_desc.GetMethod(new Name(ActualMethodName), classContext, out method); //PhpStack stack = context.Stack; if (result == GetMemberResult.NotFound) { if ((result = type_desc.GetMethod(DObject.SpecialMethodNames.Call, classContext, out method)) == GetMemberResult.NotFound) { return(DoAndReturnDefault( Expression.Call(Methods.PhpException.UndefinedMethodCalled, Expression.Constant(obj.TypeName), Expression.Constant(ActualMethodName)), defaultRestrictions )); // TODO: alter restrictions } else { invokeCallMethod = true; } } // throw an error if the method was found but the caller is not allowed to call it due to its visibility if (result == GetMemberResult.BadVisibility) { return(DoAndReturnDefault( BinderHelper.ThrowVisibilityError(method, classContext), defaultRestrictions)); } if (invokeCallMethod) { InvokeCallMethod(target, args, obj, method, out restrictions, out invokeMethodExpr); return(new DynamicMetaObject(invokeMethodExpr, restrictions.Merge(classContextRestrictions))); } else { // we are invoking the method // PhpRoutine (function or method) if (method.Member is PhpRoutine) { InvokePhpMethod(target, args, method.PhpRoutine, out restrictions, out invokeMethodExpr); return(new DynamicMetaObject(invokeMethodExpr, restrictions.Merge(classContextRestrictions))); } // ClrMethod else if (method.Member is ClrMethod) { var targetwrapper = (target.LimitType == typeof(ClrObject)) ? (DynamicMetaObject) new ClrDynamicMetaObject(target) : // ((ClrObject)target).RealType restriction (DynamicMetaObject) new ClrValueDynamicMetaObject(target); // simple type restriction, IClrValue<T> or any .NET class inheriting PhpObject InvokeClrMethod(targetwrapper, args, method, out restrictions, out invokeMethodExpr); if (wrappedTarget != null) { return(new DynamicMetaObject(Expression.Block(wrappedTarget.WrapIt(), invokeMethodExpr), wrappedTarget.Restrictions.Merge(classContextRestrictions))); } return(new DynamicMetaObject(invokeMethodExpr, restrictions.Merge(classContextRestrictions))); } } throw new NotImplementedException(); }