Пример #1
0
        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(Name.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();

        }
Пример #2
0
        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();
        }