示例#1
0
        private static Expression /*!*/ PeekReferenceUnchecked(PhpRoutine routine, DynamicMetaObject scriptContext, DynamicMetaObject arg, int argIndex)
        {
            // the caller may not pushed a reference although the formal argument is a reference:
            // it doesn't matter if called by callback:
            if (!Types.PhpReference[0].IsAssignableFrom(arg.LimitType))
            {
                // caller may have pushed a runtime chain => evaluate it:
                if (arg.LimitType == Types.PhpRuntimeChain[0])
                {
                    //result = php_chain.GetReference(Context);
                    return(Expression.Call(
                               Expression.Convert(arg.Expression, Types.PhpRuntimeChain[0]),
                               Methods.PhpRuntimeChain.GetReference,
                               scriptContext.Expression));
                }
                else
                {
                    // the reason of copy is not exactly known (it may be returning by copy as well as passing by copy):
                    // result = new PhpReference(PhpVariable.Copy(arg_i, CopyReason.Unknown));

                    ParameterExpression   resultVariable = Expression.Parameter(Types.PhpReference[0], "result");
                    ParameterExpression[] vars           = new ParameterExpression[] { resultVariable };

                    return(Expression.Block(vars,
                                            Expression.Assign(
                                                resultVariable,
                                                Expression.New(Constructors.PhpReference_Object, Expression.Call(Methods.PhpVariable.Copy, arg.Expression, Expression.Constant(CopyReason.Unknown)))),
                                            BinderHelper.ThrowArgumentNotPassedByRef(argIndex, routine.FullName),
                                            resultVariable));

                    //(MB) I'm not sure if it's necessary to execute these two in this order


                    //Original code
                    //
                    //(MB) I don't have to solve this now, PhpCallback is called in a old manner. So I can just throw exception always now.
                    //
                    // Reports an error in the case that we are not called by callback.
                    // Although, this error is fatal one can switch throwing exceptions off.
                    // If this is the case the afterwards behavior will be the same as if callback was called.
                    //if (!Callback)
                    //{
                    //    // warning (can invoke user code => we have to save and restore callstate):
                    //    CallState call_state = SaveCallState();

                    //    PhpException.ArgumentNotPassedByRef(i, CalleeName);
                    //    RestoreCallState(call_state);
                    //}
                }
            }
            else
            {
                return(Expression.Convert(arg.Expression, arg.LimitType));
            }
        }
示例#2
0
 private static Expression /*!*/ PeekType(PhpRoutine routine, DynamicMetaObject scriptContext, DynamicMetaObject arg, int argIndex)
 {
     if (arg != null)
     {
         // peeks the value:
         return(Expression.Convert(arg.Expression, arg.LimitType));
     }
     else
     {
         return(Expression.Block(
                    BinderHelper.ThrowMissingTypeArgument(argIndex, routine.FullName),
                    Expression.Constant(DTypeDesc.ObjectTypeDesc, Types.DTypeDesc[0])));
     }
 }
示例#3
0
 private static Expression /*!*/ PeekReference(PhpRoutine routine, DynamicMetaObject scriptContext, DynamicMetaObject arg, int argIndex)
 {
     if (arg != null)
     {
         // peeks the reference:
         return(PeekReferenceUnchecked(routine, scriptContext, arg, argIndex));
     }
     else
     {
         return(Expression.Block(
                    BinderHelper.ThrowMissingArgument(argIndex, routine.FullName),
                    Expression.New(Constructors.PhpReference_Void)));
     }
 }
示例#4
0
 private static Expression /*!*/ PeekValue(PhpRoutine routine, DynamicMetaObject scriptContext, DynamicMetaObject arg, int argIndex)
 {
     if (arg != null)
     {
         // peeks the value:
         return(PeekValueUnchecked(routine, scriptContext, arg, argIndex));
     }
     else
     {
         return(Expression.Block(
                    BinderHelper.ThrowMissingArgument(argIndex, routine.FullName),
                    Expression.Constant(null)));
     }
 }
示例#5
0
        ///// <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
            }
        }
示例#6
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;
        }
示例#7
0
        /// <summary>
        /// Handles the return argument of the method
        /// </summary>
        /// <remarks>
        /// Caller needs as returned type
        /// 1.) void
        ///    => result
        /// 2.) PhpReference
        ///    a.) if method returns PhpReference => result
        ///    b.) otherwise => PhpVariable.MakeReference(PhpVariable.Copy(result, CopyReason.ReturnedByCopy));
        /// 3.) otherwise
        ///    a.) if method returns PhpReference = > result.Value
        ///    b.) otherwise => PhpVariable.Dereference(PhpVariable.Copy(result, CopyReason.ReturnedByCopy));
        /// </remarks>
        /// <param name="result">Result to be handled</param>
        /// <param name="methodReturnType">Type of the return argument the method</param>
        /// <param name="dereference">Dereference will be generated.</param>
        protected Expression /*!*/ HandleResult(Expression /*!*/ result, Type /*!*/ methodReturnType, bool dereference = true)
        {
            if (_returnType == Types.Void)
            {
                // do nothing
                return(result);
            }
            else if (_returnType == Types.PhpReference[0])
            {
                if (methodReturnType == Types.PhpReference[0])
                {
                    return(result);
                }
                else
                {
                    result = CopyByReturn(result);

                    return(Expression.Call(Methods.PhpVariable.MakeReference, result));
                }
            }
            else /*if (_returnType != Types.PhpReference[0])*/
            {
                result = CopyByReturn(result);

                if (methodReturnType == Types.PhpReference[0])
                {
                    return(Expression.Field(Expression.Convert(result, Types.PhpReference[0]), Fields.PhpReference_Value));
                }
                else if (dereference)
                {
                    return(Expression.Call(Methods.PhpVariable.Dereference, result));
                }
                else
                {
                    // We don't need to dereference at all in this point(for argfull overload only!)
                    // To make sure
                    result = BinderHelper.AssertNotPhpReference(result);
                    return(result);
                }
            }
        }
示例#8
0
            public static DynamicMetaObject /*!*/ Bind(string /*!*/ methodName, CallInfo /*!*/ callInfo,
                                                       DynamicMetaObjectBinder /*!*/ binder, DynamicMetaObject /*!*/ target, DynamicMetaObject /*!*/[] /*!*/ args,
                                                       Func <DynamicMetaObject, DynamicMetaObject[], DynamicMetaObject> /*!*/ fallback)
            {
                Debug.Assert(fallback != null);

                //create DMO
                var phpInvokeBinder = Binder.MethodCall(methodName, 0, callInfo.ArgumentCount, null, Types.Object[0]) as PhpBaseInvokeMemberBinder;

                if (phpInvokeBinder != null)
                {
                    //Add ScriptContext.CurrentContext
                    var context = new DynamicMetaObject(Expression.Call(Methods.ScriptContext.GetCurrentContext), BindingRestrictions.Empty);

                    var restrictions = BinderHelper.GetSimpleInvokeRestrictions(target, args);

                    //Value type arguments have to be boxed
                    DynamicMetaObject[] arguments = new DynamicMetaObject[1 + args.Length];
                    arguments[0] = context;
                    for (int i = 0; i < args.Length; ++i)
                    {
                        arguments[1 + i] = new DynamicMetaObject(WrapDynamic(args[i].Expression),
                                                                 args[i].Restrictions);
                    }
                    var result = phpInvokeBinder.Bind(target, arguments);

                    //Unwrap result
                    var res = new DynamicMetaObject(Unwrap(result.Expression), restrictions);

                    return(res);
                }
                else
                {
                    return(fallback(target, args));//this will never happen
                }
            }
示例#9
0
        private DynamicMetaObject /*!*/ FallbackInvokeMember(DynamicMetaObject target /*!*/, DynamicMetaObject /*!*/[] /*!*/ args)
        {
            // determine run time values and additional restrictions:
            DTypeDesc           classContext = this._classContext;
            string              fieldName    = this._fieldName;
            BindingRestrictions restrictions = BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType); //target.Restrictions;

            int currentArg = 0;

            if (!ClassContextIsKnown)
            {
                Debug.Assert(args.Length > currentArg, "Not enough arguments!");
                Debug.Assert(args[currentArg].Value == null || Types.DTypeDesc[0].IsAssignableFrom(args[currentArg].LimitType), "Wrong class context type!");
                classContext = (DTypeDesc)args[currentArg].Value;
                Debug.Assert(classContext == null || !classContext.IsUnknown, "Class context should be known at run time!");

                restrictions = restrictions.Merge(BindingRestrictions.GetInstanceRestriction(args[currentArg].Expression, classContext));

                currentArg++;
            }
            if (IsIndirect)
            {
                Debug.Assert(args.Length > currentArg, "Not enough arguments!");
                Debug.Assert(Types.String[0].IsAssignableFrom(args[currentArg].LimitType), "Wrong field name type!");
                fieldName = (string)args[currentArg].Value;

                restrictions = restrictions.Merge(
                    BindingRestrictions.GetExpressionRestriction(
                        Expression.Equal(
                            args[currentArg].Expression,
                            Expression.Constant(fieldName, Types.String[0]))));

                currentArg++;
            }

            //
            ////Debug.Assert(!(var is PhpReference) && name != null);
            Debug.Assert(target.HasValue && target.LimitType != Types.PhpReference[0], "Target should not be PhpReference!");

            ////if (ReferenceEquals(obj, ScriptContext.SetterChainSingletonObject))
            ////{
            ////    ScriptContext.CurrentContext.AbortSetterChain(false);
            ////    return new PhpReference();
            ////}
            if (WantReference && ReferenceEquals(target.Value, ScriptContext.SetterChainSingletonObject))
            {
                // GetObjectPropertyRef:
                Func <PhpReference> abortSetterChain = () =>
                {
                    ScriptContext.CurrentContext.AbortSetterChain(false);
                    return(new PhpReference());
                };

                return(new DynamicMetaObject(
                           Expression.Call(abortSetterChain.Method),
                           BindingRestrictions.GetInstanceRestriction(target.Expression, ScriptContext.SetterChainSingletonObject)
                           ));
            }

            DObject obj;

            ////// a property of a DObject:
            if ((obj = target.Value as DObject) != null)
            {
                if (obj is ClrObject /*|| obj is IClrValue // IClrValue -> ClrValue<T> -> already in restriction */)
                {
                    // ((DObject)target).RealType == <obj>.RealType
                    restrictions = restrictions.Merge(
                        BindingRestrictions.GetInstanceRestriction(
                            Expression.Property(Expression.Convert(target.Expression, Types.DObject[0]), Properties.DObject_RealType),
                            obj.RealType));
                }

                ////    return GetObjectProperty(obj, name, caller, quiet);
                DPropertyDesc   property;
                GetMemberResult result = obj.TypeDesc.GetInstanceProperty(new VariableName(fieldName), classContext, out property);

                switch (result)
                {
                case GetMemberResult.OK:
                    ////object value = property.Get(this);
                    ////PhpReference reference = value as PhpReference;

                    if (property.Member is PhpField || property.Member is PhpVisibleProperty)
                    {
                        var          realType     = property.DeclaringType.RealType;
                        FieldInfo    realField    = (property.Member is PhpField) ? property.PhpField.RealField : null;
                        PropertyInfo realProperty = (property.Member is PhpVisibleProperty) ? ((PhpVisibleProperty)property.Member).RealProperty : null;

                        Debug.Assert(realField != null ^ realProperty != null);

                        MemberExpression getter = null;

                        if (realField != null)
                        {
                            getter = Expression.Field(Expression.Convert(target.Expression, realType), realField);
                        }
                        else if (realProperty != null)
                        {
                            getter = Expression.Property(Expression.Convert(target.Expression, realType), realProperty);
                        }


                        if (Types.PhpReference[0].IsAssignableFrom(getter.Type))
                        {
                            var reference  = Expression.Variable(Types.PhpReference[0]);
                            var assignment = Expression.Assign(reference, getter);

                            if (WantReference)
                            {
                                ////value = property.Get(this);
                                ////reference = value as PhpReference;

                                var returnLabel = Expression.Label(this._returnType);

                                ////if (reference != null && reference.IsSet)
                                ////{
                                ////    reference.IsAliased = true;
                                ////    return reference;
                                ////}

                                var isset = Expression.IfThen(
                                    Expression.Property(assignment, Properties.PhpReference_IsSet),
                                    Expression.Block(
                                        Expression.Assign(Expression.Property(reference, Properties.PhpReference_IsAliased), Expression.Constant(true)),
                                        Expression.Return(returnLabel, reference)));

                                ////// the CT property has been unset -> try to invoke __get
                                ////PhpReference get_ref = InvokeGetterRef(name, caller, out getter_exists);
                                ////if (getter_exists) return (get_ref == null ? new PhpReference() : get_ref);

                                ////if (reference == null)
                                ////{
                                ////    reference = new PhpReference(value);
                                ////    property.Set(this, reference);
                                ////}
                                ////else
                                ////{
                                ////    reference.IsAliased = true;
                                ////    reference.IsSet = true;
                                ////}
                                Func <DObject, string, DTypeDesc, PhpReference, PhpReference> notsetOperation = (self, name, caller, refrnc) =>
                                {
                                    bool getter_exists;
                                    // the CT property has been unset -> try to invoke __get
                                    PhpReference get_ref = self.InvokeGetterRef(name, caller, out getter_exists);
                                    if (getter_exists)
                                    {
                                        return(get_ref ?? new PhpReference());
                                    }

                                    Debug.Assert(refrnc != null);

                                    refrnc.IsAliased = true;
                                    refrnc.IsSet     = true;

                                    return(refrnc);
                                };

                                ////return reference;

                                return(new DynamicMetaObject(
                                           Expression.Block(this._returnType,
                                                            new[] { reference },
                                                            new Expression[] {
                                    isset,
                                    Expression.Label(returnLabel,
                                                     Expression.Call(null, notsetOperation.Method, Expression.Convert(target.Expression, Types.DObject[0]), Expression.Constant(fieldName), Expression.Constant(classContext, Types.DTypeDesc[0]), reference))
                                }),
                                           restrictions));
                            }
                            else
                            {
                                ////if (reference != null && !reference.IsSet)
                                ////{
                                ////    // the property is CT but has been unset
                                ////    if (issetSemantics)
                                ////    {
                                ////        bool handled;
                                ////        return PropertyIssetHandler(name, caller, out handled);
                                ////    }
                                ////    else return GetRuntimeField(name, caller);
                                ////}
                                ////else return value;


                                Func <DObject, string, DTypeDesc, object> notsetOperation;
                                if (_issetSemantics)
                                {
                                    notsetOperation = (self, name, caller) =>
                                    {
                                        return(PhpVariable.Dereference(self.GetRuntimeField(name, caller)));
                                    }
                                }
                                ;
                                else
                                {
                                    notsetOperation = (self, name, caller) =>
                                    {
                                        bool handled;
                                        return(PhpVariable.Dereference(self.PropertyIssetHandler(name, caller, out handled)));
                                    }
                                };
                                var value =
                                    Expression.Block(this._returnType,
                                                     new[] { reference },
                                                     Expression.Condition(
                                                         Expression.Property(assignment, Properties.PhpReference_IsSet),
                                                         Expression.Field(reference, Fields.PhpReference_Value),
                                                         Expression.Call(null, notsetOperation.Method, Expression.Convert(target.Expression, Types.DObject[0]), Expression.Constant(fieldName), Expression.Constant(classContext, Types.DTypeDesc[0]))
                                                         ));

                                return(new DynamicMetaObject(value, restrictions));
                            }
                        }
                        else
                        {
                            if (WantReference)
                            {
                                return(new DynamicMetaObject(
                                           Expression.New(Constructors.PhpReference_Object, Expression.Convert(getter, Types.Object[0])),
                                           restrictions));
                            }
                            else
                            {
                                return(new DynamicMetaObject(
                                           Expression.Call(Methods.PhpVariable.Dereference, Expression.Convert(getter, Types.Object[0])),
                                           restrictions));
                            }
                        }
                    }
                    else if (property.Member is ClrProperty)
                    {
                        var realType     = property.DeclaringType.RealType;
                        var realProperty = property.ClrProperty.RealProperty;

                        // (target.{RealObject|realValue}).<realProperty>
                        Expression value = Expression.Convert(
                            BinderHelper.ClrObjectWrapDynamic(
                                Expression.Property(
                                    BinderHelper.ClrRealObject(target, realType),
                                    realProperty)),
                            Types.Object[0]);

                        if (WantReference)
                        {
                            value = BinderHelper.MakePhpReference(value);
                        }

                        return(new DynamicMetaObject(value, restrictions));
                    }
                    else if (property.Member is ClrField)
                    {
                        var realType  = property.DeclaringType.RealType;
                        var realField = property.ClrField.FieldInfo;

                        // (target.{RealObject|realValue}).<realField>
                        Expression value = Expression.Convert(
                            BinderHelper.ClrObjectWrapDynamic(
                                Expression.Field(
                                    BinderHelper.ClrRealObject(target, realType),
                                    realField)),
                            Types.Object[0]);

                        if (WantReference)
                        {
                            value = BinderHelper.MakePhpReference(value);
                        }

                        return(new DynamicMetaObject(value, restrictions));
                    }
                    else if (property.Member is ClrEvent)
                    {
                        var clrEvent = (ClrEvent)property.Member;
                        var realType = property.DeclaringType.RealType;

                        // emit stub that Wraps event as [ ClrEventObject<handlerType>.Wrap(<SC>, <event name>, <addMethod>, <removeMethod>) ]
                        var stub = new System.Reflection.Emit.DynamicMethod(
                            string.Format("event<{0}>", fieldName),
                            Types.DObject[0], new[] { realType }, realType);
                        var il = new ILEmitter(stub);
                        clrEvent.EmitGetEventObject(
                            il,
                            new Place(null, Properties.ScriptContext_CurrentContext),
                            new IndexedPlace(PlaceHolder.Argument, 0),
                            false);
                        il.Emit(System.Reflection.Emit.OpCodes.Ret);

                        Expression value = Expression.Call(stub, BinderHelper.ClrRealObject(target, realType));
                        if (WantReference)
                        {
                            value = BinderHelper.MakePhpReference(value);
                        }
                        return(new DynamicMetaObject(value, restrictions));
                    }
                    else
                    {
                        throw new NotImplementedException();
                    }

                case GetMemberResult.NotFound:
                    if (WantReference)
                    {
                        Func <DObject, string, DTypeDesc, PhpReference> op = (self, name, caller) =>
                        {
                            PhpReference reference;
                            bool         getter_exists;

                            // search in RT fields
                            if (self.RuntimeFields != null && self.RuntimeFields.ContainsKey(name))
                            {
                                var namekey = new IntStringKey(name);
                                return(self.RuntimeFields.table._ensure_item_ref(ref namekey, self.RuntimeFields));
                            }

                            // property is not present -> try to invoke __get
                            reference = self.InvokeGetterRef(name, caller, out getter_exists);
                            if (getter_exists)
                            {
                                return((reference == null) ? new PhpReference() : reference);
                            }

                            // (no notice/warning/error thrown by PHP)

                            // add the field
                            reference = new PhpReference();
                            if (self.RuntimeFields == null)
                            {
                                self.RuntimeFields = new PhpArray();
                            }
                            self.RuntimeFields[name] = reference;

                            return(reference);
                        };

                        return(new DynamicMetaObject(
                                   Expression.Call(null, op.Method, Expression.Convert(target.Expression, Types.DObject[0]), Expression.Constant(fieldName), Expression.Constant(classContext, Types.DTypeDesc[0])),
                                   restrictions));
                    }
                    else
                    {
                        ////if (issetSemantics)
                        ////{
                        ////    OrderedHashtable<string>.Element element;
                        ////    if (RuntimeFields != null && (element = RuntimeFields.GetElement(name)) != null)
                        ////    {
                        ////        return element.Value;
                        ////    }
                        ////    else
                        ////    {
                        ////        bool handled;
                        ////        return PropertyIssetHandler(name, caller, out handled);
                        ////    }
                        ////}
                        ////else return GetRuntimeField(name, caller);

                        if (_issetSemantics)
                        {
                            Func <DObject, string, DTypeDesc, object> notsetOperation = (self, name, caller) =>
                            {
                                if (self.RuntimeFields != null)
                                {
                                    object value;
                                    if (self.RuntimeFields.TryGetValue(name, out value))
                                    {
                                        return(value);
                                    }
                                }

                                bool handled;
                                return(self.PropertyIssetHandler(name, caller, out handled));
                            };

                            return(new DynamicMetaObject(
                                       Expression.Call(Methods.PhpVariable.Dereference,
                                                       Expression.Call(null, notsetOperation.Method, Expression.Convert(target.Expression, Types.DObject[0]), Expression.Constant(fieldName), Expression.Constant(classContext, Types.DTypeDesc[0]))),
                                       restrictions));
                        }
                        else
                        {
                            return(new DynamicMetaObject(
                                       Expression.Call(
                                           Methods.PhpVariable.Dereference,
                                           Expression.Call(
                                               Expression.Convert(target.Expression, Types.DObject[0]),
                                               Methods.DObject_GetRuntimeField, Expression.Constant(fieldName), Expression.Constant(classContext, Types.DTypeDesc[0]))),
                                       restrictions));
                        };
                    }

                case GetMemberResult.BadVisibility:
                {
                    ////PhpException.PropertyNotAccessible(
                    ////    property.DeclaringType.MakeFullName(),
                    ////    name.ToString(),
                    ////    (caller == null ? String.Empty : caller.MakeFullName()),
                    ////    property.IsProtected);

                    string stringResourceKey = property.IsProtected ? "protected_property_accessed" : "private_property_accessed";

                    return(new DynamicMetaObject(
                               Expression.Block(this._returnType,
                                                Expression.Call(null, Methods.PhpException.Throw,
                                                                Expression.Constant(PhpError.Error, Types.PhpError_String[0]),
                                                                Expression.Constant(CoreResources.GetString(stringResourceKey, property.DeclaringType.MakeFullName(), fieldName, (classContext == null ? String.Empty : classContext.MakeFullName())))),
                                                WantReference ? (Expression)Expression.New(Constructors.PhpReference_Void) : Expression.Constant(null)
                                                ),
                               restrictions));
                }
                }
            }

            ////// warnings:
            ////if (!quiet) // not in isset() operator only
            ////{
            if (!_issetSemantics)
            {
                ////    if (PhpVariable.IsEmpty(var))
                ////        // empty:
                ////        PhpException.Throw(PhpError.Notice, CoreResources.GetString("empty_used_as_object"));
                ////    else
                ////        // PhpArray, string, scalar type:
                ////        PhpException.VariableMisusedAsObject(var, false);

                Action <object> error = (var) =>
                {
                    if (PhpVariable.IsEmpty(var))
                    {
                        // empty:
                        PhpException.Throw(PhpError.Notice, CoreResources.GetString("empty_used_as_object"));
                    }
                    else
                    {
                        // PhpArray, string, scalar type:
                        PhpException.VariableMisusedAsObject(var, false);
                    }
                };

                return(new DynamicMetaObject(
                           Expression.Block(this._returnType,
                                            Expression.Call(error.Method, target.Expression),
                                            WantReference ? (Expression)Expression.New(Constructors.PhpReference_Void) : Expression.Constant(null)),
                           (target.HasValue && target.Value == null) ?
                           BindingRestrictions.GetInstanceRestriction(target.Expression, null) :
                           BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType)));
            }
            ////}

            ////// property does not exist
            ////return null;
            return(new DynamicMetaObject(
                       Expression.Constant(null),
                       (target.HasValue && target.Value == null) ?
                       BindingRestrictions.GetInstanceRestriction(target.Expression, null) :
                       BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType)));
        }
示例#10
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);
        }
示例#11
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));
        }
示例#12
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();
        }