예제 #1
0
        public override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args)
        {
            var restrictions = BindingRestrictions.Empty;

            Expression target_expr;
            object     target_value;

            BinderHelpers.TargetAsObject(target, out target_expr, out target_value, ref restrictions);

            string     fldName;
            Expression value;

            ResolveArgs(args, ref restrictions, out fldName, out value);

            var runtime_type = target_value.GetType();

            //
            if (target_expr.Type != runtime_type)
            {
                restrictions = restrictions.Merge(BindingRestrictions.GetTypeRestriction(target_expr, runtime_type));
                target_expr  = Expression.Convert(target_expr, runtime_type);
            }

            //
            var setter = BinderHelpers.BindField(runtime_type.GetPhpTypeInfo(), _classContext, target_expr, fldName, null, _access, value);

            if (setter != null)
            {
                //
                return(new DynamicMetaObject(setter, restrictions));
            }

            // field not found
            throw new NotImplementedException();
        }
예제 #2
0
                bool TryBindArgument(int srcarg, Type targetType, out Expression expr)
                {
                    var args = _args;

                    if (srcarg >= 0 && srcarg < args.Length)
                    {
                        // skip RuntimeChain's
                        srcarg = MapToArgsIndex(srcarg);

                        //
                        if (srcarg < args.Length)
                        {
                            expr = args[srcarg];

                            // apply the runtime chain:
                            if (srcarg + 1 < args.Length)
                            {
                                BinderHelpers.TryAppendRuntimeChain(ref expr, args[srcarg + 1], _ctx, _classContext, targetType == typeof(PhpAlias));
                            }

                            //
                            if (targetType != null)
                            {
                                expr = ConvertExpression.Bind(expr, targetType, _ctx);
                            }

                            //
                            return(true);
                        }
                    }

                    // not provided
                    expr = null;
                    return(false);
                }
예제 #3
0
        public override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args)
        {
            var restrictions = BindingRestrictions.Empty;

            PhpTypeInfo phptype;
            Expression  target_expr;

            //
            var ctx     = args[0];
            var fldName = ResolveName(args, ref restrictions);

            //
            if (target.LimitType == typeof(PhpTypeInfo))    // static field
            {
                target_expr = null;
                phptype     = (PhpTypeInfo)target.Value;

                //
                restrictions = restrictions.Merge(BindingRestrictions.GetInstanceRestriction(target.Expression, phptype));
            }
            else
            {
                var isobject = BinderHelpers.TryTargetAsObject(target, out DynamicMetaObject instance);
                restrictions = restrictions.Merge(instance.Restrictions);

                if (isobject == false)
                {
                    var defaultexpr = ConvertExpression.BindDefault(_returnType);

                    if (!_access.Quiet())
                    {
                        // PhpException.VariableMisusedAsObject(target, _access.ReadRef)
                        var throwcall = Expression.Call(typeof(PhpException), "VariableMisusedAsObject", Array.Empty <Type>(),
                                                        ConvertExpression.BindToValue(target.Expression), Expression.Constant(_access.EnsureAlias()));
                        defaultexpr = Expression.Block(throwcall, defaultexpr);
                    }

                    return(new DynamicMetaObject(defaultexpr, restrictions));
                }

                phptype     = instance.RuntimeType.GetPhpTypeInfo();
                target_expr = target_expr = Expression.Convert(instance.Expression, instance.RuntimeType);
            }

            Debug.Assert(IsClassConst == (target_expr == null));

            //
            var getter = IsClassConst
                ? BinderHelpers.BindClassConstant(phptype, _classContext, fldName, ctx.Expression)
                : BinderHelpers.BindField(phptype, _classContext, target_expr, fldName, ctx.Expression, _access, null);

            if (getter != null)
            {
                //
                return(new DynamicMetaObject(ConvertExpression.Bind(getter, _returnType, ctx.Expression), restrictions));
            }

            // field not found
            throw new NotImplementedException();
        }
예제 #4
0
        protected override MethodBase[] ResolveMethods(DynamicMetaObject ctx, PhpTypeInfo tinfo, DynamicMetaObject nameExpr, ref DynamicMetaObject target, IList <DynamicMetaObject> args, ref BindingRestrictions restrictions)
        {
            // resolve target expression:
            Expression target_expr;
            object     target_value;

            BinderHelpers.TargetAsObject(target, out target_expr, out target_value, ref restrictions);

            // (NULL)->
            if (target_value == null)
            {
                return(null);    // no methods
            }

            // target restrictions
            if (target_value != null && !target_expr.Type.GetTypeInfo().IsSealed)
            {
                restrictions = restrictions.Merge(BindingRestrictions.GetTypeRestriction(target_expr, target_value.GetType()));
                target_expr  = Expression.Convert(target_expr, target_value.GetType());
            }

            target = new DynamicMetaObject(target_expr, target.Restrictions, target_value);

            string name = _name ?? (string)nameExpr.Value;

            // candidates:
            var candidates = target.RuntimeType.GetPhpTypeInfo().SelectRuntimeMethods(name).SelectVisible(_classCtx).ToList();

            return(candidates.ToArray());
        }
예제 #5
0
        protected override Expression BindMissingMethod(CallSiteContext bound)
        {
            if (bound.TargetType == null)   // already reported - class cannot be found
            {
                return(ConvertExpression.BindDefault(this.ReturnType));
            }

            var call = BinderHelpers.FindMagicMethod(bound.TargetType, (bound.TargetInstance == null) ? TypeMethods.MagicMethods.__callstatic : TypeMethods.MagicMethods.__call);

            if (call != null)
            {
                var name_expr = (_name != null) ? Expression.Constant(_name) : bound.IndirectName;

                // T.__callStatic(name, array)
                var call_args = new Expression[]
                {
                    name_expr,
                    BinderHelpers.NewPhpArray(bound.Arguments),
                };
                return(OverloadBinder.BindOverloadCall(_returnType, bound.TargetInstance, call.Methods, bound.Context, call_args, true, lateStaticType: bound.TargetType));
            }

            //
            return(base.BindMissingMethod(bound));
        }
예제 #6
0
        protected override Expression BindMissingMethod(CallSiteContext bound)
        {
            var name_expr = (_name != null) ? Expression.Constant(_name) : bound.IndirectName;

            // resolve target expression:
            var isobject = bound.TargetType != null;

            if (isobject == false)
            {
                /* Template:
                 * PhpException.MethodOnNonObject(name_expr); // aka PhpException.Throw(Error, method_called_on_non_object, name_expr)
                 * return NULL;
                 */
                var throwcall = Expression.Call(typeof(PhpException), "MethodOnNonObject", Array.Empty <Type>(), ConvertExpression.Bind(name_expr, typeof(string), bound.Context));
                return(Expression.Block(throwcall, ConvertExpression.BindDefault(this.ReturnType)));
            }

            var call = BinderHelpers.FindMagicMethod(bound.TargetType, TypeMethods.MagicMethods.__call);

            if (call != null)
            {
                // target.__call(name, array)
                var call_args = new Expression[]
                {
                    name_expr,
                    BinderHelpers.NewPhpArray(bound.Arguments),
                };
                return(OverloadBinder.BindOverloadCall(_returnType, bound.TargetInstance, call.Methods, bound.Context, call_args, false));
            }

            return(base.BindMissingMethod(bound));
        }
예제 #7
0
        public override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args)
        {
            bool hasTargetInstance = (target.LimitType != typeof(TargetTypeParam));

            var bound = new CallSiteContext(!hasTargetInstance)
            {
                ClassContext = _classContext,
                Name         = _name
            }
            .ProcessArgs(target, args, hasTargetInstance);

            if (hasTargetInstance)
            {
                var isobject = bound.TargetType != null;
                if (isobject == false)
                {
                    var defaultexpr = ConvertExpression.BindDefault(_returnType);

                    if (!_access.Quiet())
                    {
                        // PhpException.VariableMisusedAsObject(target, _access.ReadRef)
                        var throwcall = BinderHelpers.VariableMisusedAsObject(target.Expression, _access.EnsureAlias());
                        defaultexpr = Expression.Block(throwcall, defaultexpr);
                    }

                    return(new DynamicMetaObject(defaultexpr, bound.Restrictions));
                }

                // instance := (T)instance
                bound.TargetInstance = Expression.Convert(bound.TargetInstance, bound.TargetType.Type);
            }

            Debug.Assert(IsClassConst ? (bound.TargetInstance == null) : true);

            //
            var getter = IsClassConst
                ? BinderHelpers.BindClassConstant(bound.TargetType, bound.ClassContext, bound.Name, bound.Context)
                : BinderHelpers.BindField(bound.TargetType, bound.ClassContext, bound.TargetInstance, bound.Name, bound.Context, _access, null);

            if (getter != null)
            {
                //
                return(new DynamicMetaObject(ConvertExpression.Bind(getter, _returnType, bound.Context), bound.Restrictions));
            }

            if (IsClassConst)
            {
                // error: constant not defined
                // ...
            }

            // unreachable: property not found
            throw new InvalidOperationException($"{bound.TargetType.Name}::{bound.Name} could not be resolved.");
        }
예제 #8
0
        public override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args)
        {
            var restrictions = BindingRestrictions.Empty;

            Expression  target_expr;
            PhpTypeInfo phptype;

            //
            string     fldName;
            Expression value;

            ResolveArgs(args, ref restrictions, out fldName, out value);
            var ctx = args[args.Length - 1];

            //
            if (target.LimitType == typeof(PhpTypeInfo))    // static field
            {
                target_expr = null;
                phptype     = (PhpTypeInfo)target.Value;
            }
            else
            {
                object target_value;
                BinderHelpers.TargetAsObject(target, out target_expr, out target_value, ref restrictions);

                var runtime_type = target_value.GetType();

                //
                if (target_expr.Type != runtime_type)
                {
                    restrictions = restrictions.Merge(BindingRestrictions.GetTypeRestriction(target_expr, runtime_type));
                    target_expr  = Expression.Convert(target_expr, runtime_type);
                }

                phptype = runtime_type.GetPhpTypeInfo();
            }

            //
            var setter = BinderHelpers.BindField(phptype, _classContext, target_expr, fldName, ctx.Expression, _access, value);

            if (setter != null)
            {
                //
                return(new DynamicMetaObject(setter, restrictions));
            }

            // field not found
            throw new NotImplementedException();
        }
예제 #9
0
        protected override Expression BindMissingMethod(CallSiteContext bound)
        {
            var type = bound.TargetType;

            if (type == null)   // already reported - class cannot be found
            {
                return(ConvertExpression.BindDefault(this.ReturnType));
            }

            if (bound.TargetInstance != null && bound.CurrentTargetInstance != null) // it has been checked it is a subclass of TargetType
            {
                // ensure current scope's __call() is favoured over the specified class
                type = bound.CurrentTargetInstance.GetPhpTypeInfo();
            }

            var call = BinderHelpers.FindMagicMethod(type, (bound.TargetInstance == null) ? TypeMethods.MagicMethods.__callstatic : TypeMethods.MagicMethods.__call);

            if (call != null)
            {
                Expression[] call_args;

                var name_expr = (_name != null) ? Expression.Constant(_name) : bound.IndirectName;

                if (call.Methods.All(IsClrMagicCallWithParams))
                {
                    // Template: target.__call(name, arg1, arg2, ...)
                    // flatterns the arguments:
                    call_args = ArrayUtils.AppendRange(name_expr, bound.Arguments);
                }
                else
                {
                    // Template: target.__call(name, array)
                    // regular PHP behavior:
                    call_args = new Expression[]
                    {
                        name_expr,
                        BinderHelpers.NewPhpArray(bound.Arguments, bound.Context, bound.ClassContext),
                    };
                }

                return(OverloadBinder.BindOverloadCall(_returnType, bound.TargetInstance, call.Methods, bound.Context, call_args,
                                                       isStaticCallSyntax: true,
                                                       lateStaticType: bound.TargetType,
                                                       classContext: bound.ClassContext));
            }

            //
            return(base.BindMissingMethod(bound));
        }
예제 #10
0
        public override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args)
        {
            var restrictions = BindingRestrictions.Empty;

            PhpTypeInfo phptype;
            Expression  target_expr;

            //
            var fldName = ResolveName(args, ref restrictions);

            //
            if (target.LimitType == typeof(PhpTypeInfo))    // static field
            {
                target_expr = null;
                phptype     = (PhpTypeInfo)target.Value;

                //
                restrictions = restrictions.Merge(BindingRestrictions.GetInstanceRestriction(target.Expression, target_expr));
            }
            else
            {
                // instance field
                object target_value;
                BinderHelpers.TargetAsObject(target, out target_expr, out target_value, ref restrictions);

                var runtime_type = target_value.GetType();

                //
                if (target_expr.Type != runtime_type)
                {
                    restrictions = restrictions.Merge(BindingRestrictions.GetTypeRestriction(target_expr, runtime_type));
                    target_expr  = Expression.Convert(target_expr, runtime_type);
                }

                phptype = runtime_type.GetPhpTypeInfo();
            }

            //
            var getter = BinderHelpers.BindField(phptype, _classContext, target_expr, fldName, null, _access, null);

            if (getter != null)
            {
                //
                return(new DynamicMetaObject(ConvertExpression.Bind(getter, _returnType), restrictions));
            }

            // field not found
            throw new NotImplementedException();
        }
예제 #11
0
        public override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args)
        {
            bool hasTargetInstance = (target.LimitType != typeof(TargetTypeParam));

            var bound = new CallSiteContext()
            {
                ClassContext = _classContext,
                Name         = _name
            }
            .ProcessArgs(target, args, hasTargetInstance);

            if (hasTargetInstance)
            {
                var isobject = bound.TargetType != null;
                if (isobject == false)
                {
                    var defaultexpr = ConvertExpression.BindDefault(_returnType);

                    if (!_access.Quiet())
                    {
                        // PhpException.VariableMisusedAsObject(target, _access.ReadRef)
                        var throwcall = Expression.Call(typeof(PhpException), "VariableMisusedAsObject", Array.Empty <Type>(),
                                                        ConvertExpression.BindToValue(target.Expression), Expression.Constant(_access.EnsureAlias()));
                        defaultexpr = Expression.Block(throwcall, defaultexpr);
                    }

                    return(new DynamicMetaObject(defaultexpr, bound.Restrictions));
                }

                // instance := (T)instance
                bound.TargetInstance = Expression.Convert(bound.TargetInstance, bound.TargetType.Type.AsType());
            }

            Debug.Assert(IsClassConst ? (bound.TargetInstance == null) : true);

            //
            var getter = IsClassConst
                ? BinderHelpers.BindClassConstant(bound.TargetType, bound.ClassContext, bound.Name, bound.Context)
                : BinderHelpers.BindField(bound.TargetType, bound.ClassContext, bound.TargetInstance, bound.Name, bound.Context, _access, null);

            if (getter != null)
            {
                //
                return(new DynamicMetaObject(ConvertExpression.Bind(getter, _returnType, bound.Context), bound.Restrictions));
            }

            // field not found
            throw new NotImplementedException();
        }
예제 #12
0
        void ProcessTarget(DynamicMetaObject target)
        {
            Debug.Assert(target != null);

            if (BinderHelpers.TryTargetAsObject(target, out target))
            {
                this.AddRestriction(target.Restrictions);
                this.TargetInstance        = target.Expression;
                this.CurrentTargetInstance = target.Value;
                if (this.TargetType == null && target.Value != null)
                {
                    this.TargetType = target.Value.GetPhpTypeInfo();
                }
            }
        }
예제 #13
0
                public override Expression BindArgsCount()
                {
                    int count = 0;

                    foreach (var x in _args)
                    {
                        if (!BinderHelpers.IsRuntimeChain(x.Type))
                        {
                            count++;
                        }
                    }

                    //
                    return(Expression.Constant(count, typeof(int)));
                }
예제 #14
0
        static int MandatoryParametersCount(ParameterInfo[] ps, int from)
        {
            // gets count of parameters that are mandatory (last parameter that does not have a default value(is not optional))

            int lastmandatory = -1;

            for (int i = from; i < ps.Length; i++)
            {
                if (BinderHelpers.IsMandatoryParameter(ps[i]))
                {
                    lastmandatory = i;
                }
            }

            return(lastmandatory - from + 1);
        }
예제 #15
0
        public sealed override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args)
        {
            var bound = CreateContext().ProcessArgs(target, args, HasTarget);

            Expression invocation;

            //
            var methods = ResolveMethods(bound);

            if (methods != null && methods.Length != 0)
            {
                // late static bound type, 'static' if available, otherwise the target type
                var lateStaticTypeArg = (object)bound.LateStaticType ?? bound.TargetType;

                if (bound.HasArgumentUnpacking)
                {
                    var args_var = Expression.Variable(typeof(PhpValue[]), "args_array");

                    /*
                     * args_var = ArgumentsToArray()
                     * call(...args_var...)
                     */

                    invocation = Expression.Block(new[] { args_var },
                                                  Expression.Assign(args_var, BinderHelpers.UnpackArgumentsToArray(methods, bound.Arguments, bound.Context, bound.ClassContext)),
                                                  OverloadBinder.BindOverloadCall(_returnType, bound.TargetInstance, methods, bound.Context, args_var,
                                                                                  isStaticCallSyntax: bound.IsStaticSyntax,
                                                                                  lateStaticType: lateStaticTypeArg)
                                                  );
                }
                else
                {
                    invocation = OverloadBinder.BindOverloadCall(_returnType, bound.TargetInstance, methods, bound.Context, bound.Arguments,
                                                                 isStaticCallSyntax: bound.IsStaticSyntax,
                                                                 lateStaticType: lateStaticTypeArg,
                                                                 classContext: bound.ClassContext);
                }
            }
            else
            {
                invocation = BindMissingMethod(bound);
            }

            // TODO: by alias or by value
            return(new DynamicMetaObject(invocation, bound.Restrictions));
        }
예제 #16
0
        protected override Expression BindMissingMethod(CallSiteContext bound)
        {
            var name_expr = (_name != null) ? Expression.Constant(_name) : bound.IndirectName;

            // resolve target expression:
            var isobject = bound.TargetType != null;

            if (isobject == false)
            {
                /* Template:
                 * PhpException.MethodOnNonObject(name_expr);
                 * return NULL;
                 */
                var throwcall = Expression.Call(typeof(PhpException), "MethodOnNonObject", Array.Empty <Type>(), ConvertExpression.Bind(name_expr, typeof(string), bound.Context));
                return(Expression.Block(throwcall, ConvertExpression.BindDefault(this.ReturnType)));
            }

            var call = BinderHelpers.FindMagicMethod(bound.TargetType, TypeMethods.MagicMethods.__call);

            if (call != null)
            {
                Expression[] call_args;

                if (call.Methods.All(IsClrMagicCallWithParams))
                {
                    // Template: target.__call(name, arg1, arg2, ...)
                    // flatterns the arguments:
                    call_args = ArrayUtils.AppendRange(name_expr, bound.Arguments);
                }
                else
                {
                    // Template: target.__call(name, array)
                    // regular PHP behavior:
                    call_args = new Expression[]
                    {
                        name_expr,
                        BinderHelpers.NewPhpArray(bound.Arguments, bound.Context, bound.ClassContext),
                    };
                }

                return(OverloadBinder.BindOverloadCall(_returnType, bound.TargetInstance, call.Methods, bound.Context, call_args, false));
            }

            return(base.BindMissingMethod(bound));
        }
예제 #17
0
                int MapToArgsIndex(int srcarg)
                {
                    var args = _args;

                    if (srcarg > 0 && srcarg < args.Length) // [0] is never IRuntimeChain
                    {
                        // skip RuntimeChain's
                        for (int i = 1; i <= srcarg && i < args.Length; i++)
                        {
                            if (BinderHelpers.IsRuntimeChain(args[i].Type))
                            {
                                ++srcarg;
                            }
                        }
                    }

                    return(srcarg);
                }
예제 #18
0
        protected override MethodBase[] ResolveMethods(DynamicMetaObject ctx, ref DynamicMetaObject target, IList <DynamicMetaObject> args, ref BindingRestrictions restrictions)
        {
            if (target.Value == null)
            {
                Combine(ref restrictions, BindingRestrictions.GetInstanceRestriction(target.Expression, Expression.Constant(null)));
                // TODO: Err instance is null
                return(null);
            }

            // resolve target expression:
            Expression target_expr;
            object     target_value;

            BinderHelpers.TargetAsObject(target, out target_expr, out target_value, ref restrictions);

            // target restrictions
            if (!target_expr.Type.GetTypeInfo().IsSealed)
            {
                restrictions = restrictions.Merge(BindingRestrictions.GetTypeRestriction(target_expr, target_value.GetType()));
                target_expr  = Expression.Convert(target_expr, target_value.GetType());
            }

            target = new DynamicMetaObject(target_expr, target.Restrictions, target_value);

            string name = _name;

            if (_name == null)
            {
                // indirect function name

                Debug.Assert(args.Count >= 1 && args[0].LimitType == typeof(string));
                Debug.Assert(args[0].Value is string);

                restrictions = restrictions.Merge(BindingRestrictions.GetExpressionRestriction(Expression.Equal(args[0].Expression, Expression.Constant(args[0].Value)))); // args[0] == "VALUE"

                name = (string)args[0].Value;
                args.RemoveAt(0);
            }

            // candidates:
            var candidates = target.RuntimeType.SelectCandidates().SelectByName(name).SelectVisible(_classCtx).ToList();

            return(candidates.ToArray());
        }
예제 #19
0
        protected override Expression BindMissingMethod(DynamicMetaObject ctx, PhpTypeInfo tinfo, DynamicMetaObject nameMeta, DynamicMetaObject target, IList <DynamicMetaObject> args, ref BindingRestrictions restrictions)
        {
            var call = BinderHelpers.FindMagicMethod(tinfo, target == null ? TypeMethods.MagicMethods.__callstatic : TypeMethods.MagicMethods.__call);

            if (call != null)
            {
                var name_expr = (_name != null) ? Expression.Constant(_name) : nameMeta?.Expression;

                // T.__callStatic(name, array)
                var call_args = new Expression[]
                {
                    name_expr,
                    BinderHelpers.NewPhpArray(ctx.Expression, args.Select(a => a.Expression)),
                };
                return(OverloadBinder.BindOverloadCall(_returnType, target?.Expression, call.Methods, ctx.Expression, call_args));
            }

            //
            return(base.BindMissingMethod(ctx, tinfo, nameMeta, target, args, ref restrictions));
        }
예제 #20
0
        protected override MethodBase[] ResolveMethods(DynamicMetaObject ctx, PhpTypeInfo tinfo, DynamicMetaObject nameExpr, ref DynamicMetaObject target, IList <DynamicMetaObject> args, ref BindingRestrictions restrictions)
        {
            // resolve target expression:
            var isobject = BinderHelpers.TryTargetAsObject(target, out DynamicMetaObject instance);

            restrictions = restrictions.Merge(instance.Restrictions);
            target       = new DynamicMetaObject(Expression.Convert(instance.Expression, instance.RuntimeType), target.Restrictions, instance.Value);

            if (isobject == false)
            {
                return(null);    // no methods
            }

            string name = _name ?? (string)nameExpr.Value;

            // candidates:
            var candidates = target.RuntimeType.GetPhpTypeInfo().SelectRuntimeMethods(name).SelectVisible(_classCtx).ToList();

            return(candidates.ToArray());
        }
예제 #21
0
        protected override Expression BindMissingMethod(DynamicMetaObject ctx, PhpTypeInfo tinfo, DynamicMetaObject nameMeta, DynamicMetaObject target, IList <DynamicMetaObject> args, ref BindingRestrictions restrictions)
        {
            var name_expr = (_name != null) ? Expression.Constant(_name) : nameMeta?.Expression;

            // resolve target expression:
            Expression target_expr;
            object     target_value;

            BinderHelpers.TargetAsObject(target, out target_expr, out target_value, ref restrictions);

            if (target_value == null)
            {
                /* Template:
                 * PhpException.MethodOnNonObject(name_expr); // aka PhpException.Throw(Error, method_called_on_non_object, name_expr)
                 * return NULL;
                 */
                var throwcall = Expression.Call(typeof(PhpException), "MethodOnNonObject", Array.Empty <Type>(), ConvertExpression.Bind(name_expr, typeof(string), ctx.Expression));
                return(Expression.Block(throwcall, ConvertExpression.BindDefault(this.ReturnType)));
            }

            Debug.Assert(ReflectionUtils.IsClassType(target_value.GetType().GetTypeInfo()));

            tinfo = target_value.GetPhpTypeInfo();

            var call = BinderHelpers.FindMagicMethod(tinfo, TypeMethods.MagicMethods.__call);

            if (call != null)
            {
                // target.__call(name, array)
                var call_args = new Expression[]
                {
                    name_expr,
                    BinderHelpers.NewPhpArray(ctx.Expression, args.Select(a => a.Expression)),
                };
                return(OverloadBinder.BindOverloadCall(_returnType, target.Expression, call.Methods, ctx.Expression, call_args));
            }

            return(base.BindMissingMethod(ctx, tinfo, nameMeta, target, args, ref restrictions));
        }
예제 #22
0
        public override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args)
        {
            bool hasTargetInstance = (target.LimitType != typeof(TargetTypeParam));

            var bound = new CallSiteContext(!hasTargetInstance)
            {
                ClassContext = _classContext,
                Name         = _name,
            }
            .ProcessArgs(target, args, hasTargetInstance);

            //
            if (hasTargetInstance)
            {
                var isobject = bound.TargetType != null;
                if (isobject == false)
                {
                    // VariableMisusedAsObject
                    return(new DynamicMetaObject(
                               BinderHelpers.VariableMisusedAsObject(target.Expression, false),
                               bound.Restrictions));
                }

                // instance := (T)instance
                bound.TargetInstance = Expression.Convert(bound.TargetInstance, bound.TargetType.Type.AsType());
            }

            //
            var setter = BinderHelpers.BindField(bound.TargetType, bound.ClassContext, bound.TargetInstance, bound.Name, bound.Context, _access, bound.Arguments.FirstOrDefault());

            if (setter != null)
            {
                //
                return(new DynamicMetaObject(setter, bound.Restrictions));
            }

            // field not found
            throw new NotImplementedException();
        }
예제 #23
0
        protected override Expression BindMissingMethod(DynamicMetaObject ctx, DynamicMetaObject target, IList <DynamicMetaObject> args, ref BindingRestrictions restrictions)
        {
            var tinfo = target.RuntimeType.GetPhpTypeInfo();
            var call  = (PhpMethodInfo)tinfo.DeclaredMethods[TypeMethods.MagicMethods.__call];

            if (call != null)
            {
                if (_name == null)
                {
                    throw new NotImplementedException();
                }

                // target.__call(name, array)
                var call_args = new Expression[]
                {
                    Expression.Constant(_name),
                    BinderHelpers.NewPhpArray(ctx.Expression, args.Select(a => a.Expression)),
                };
                return(OverloadBinder.BindOverloadCall(_returnType, target.Expression, call.Methods, ctx.Expression, call_args));
            }

            return(base.BindMissingMethod(ctx, target, args, ref restrictions));
        }
예제 #24
0
        /// <summary>
        /// Creates expression with overload resolution.
        /// </summary>
        /// <param name="treturn">Expected return type.</param>
        /// <param name="target">Target instance in case of instance methods.</param>
        /// <param name="methods">List of methods to resolve overload.</param>
        /// <param name="ctx">Expression of current runtime context.</param>
        /// <param name="args">Provides arguments.</param>
        /// <param name="lateStaticType">Optional type used to statically invoke the method (late static type).</param>
        /// <returns>Expression representing overload call with resolution or <c>null</c> in case binding should be restarted with updated array of <paramref name="methods"/>.</returns>
        static Expression BindOverloadCall(Type treturn, Expression target, ref MethodBase[] methods, Expression ctx, ArgumentsBinder args, PhpTypeInfo lateStaticType = null)
        {
            if (methods == null || args == null)
            {
                throw new ArgumentNullException();
            }

            // overload resolution

            // order methods

            /*
             * cost1 = CostOf(m1)
             * cost2 = CostOf(m2)
             * ...
             * best = Min(cost1, .., costN)
             * if (cost1 == best) m1( ... )
             * ...
             * default(T) // unreachable
             */

            var locals = new List <ParameterExpression>();
            var body   = new List <Expression>();

            Expression invoke = Expression.Default(treturn);

            //
            if (methods.Length == 0)
            {
                throw new ArgumentException();    // no method to call
                // invoke = ERR
            }
            if (methods.Length == 1)
            {
                // just this piece of code is enough:
                invoke = ConvertExpression.Bind(BindCastToFalse(BinderHelpers.BindToCall(target, methods[0], ctx, args, lateStaticType), DoCastToFalse(methods[0], treturn)), treturn, ctx);
            }
            else
            {
                var list = new List <MethodCostInfo>();

                // collect arguments, that have same type across all provided methods => we don't have to check costof()
                var makeCostOf = DifferentArgumentTypeIndexes(methods); // parameters which costof() have to be calculated and compared to others

                // costX = CostOf(mX)
                foreach (var m in methods)
                {
                    ConversionCost mincost; // minimal cost resolved in compile time
                    var            expr_cost = BindCostOf(m, args, makeCostOf, out mincost);
                    if (mincost >= ConversionCost.NoConversion)
                    {
                        continue;   // we don't have to try this overload
                    }
                    var const_cost = expr_cost as ConstantExpression;
                    var cost_var   = Expression.Variable(typeof(ConversionCost), "cost" + list.Count);

                    if (const_cost == null)
                    {
                        body.Add(Expression.Assign(cost_var, expr_cost));   // costX = CostOf(m)
                    }

                    list.Add(new MethodCostInfo()
                    {
                        Method      = m,
                        CostExpr    = (Expression)const_cost ?? cost_var,
                        MinimalCost = mincost,
                    });
                }

                if (list.Count != 0)
                {
                    var minresolved = ConversionCost.Error;
                    foreach (var c in list.Where(c => c.ResolvedCost.HasValue))
                    {
                        minresolved = CostOf.Min(minresolved, c.ResolvedCost.Value);
                    }

                    if (list.All(c => c.ResolvedCost.HasValue))
                    {
                        for (int i = 0; i < list.Count; i++)
                        {
                            if (list[i].ResolvedCost.Value == minresolved)
                            {
                                list = new List <MethodCostInfo>()
                                {
                                    list[i]
                                };
                                break;
                            }
                        }
                    }
                    else
                    {
                        // if minimal cost is greater than some resolved cost, we can reduce it
                        if (minresolved < ConversionCost.Error)
                        {
                            for (int i = list.Count - 1; i >= 0; i--)
                            {
                                if (list[i].MinimalCost > minresolved)
                                {
                                    list.RemoveAt(i);
                                }
                            }
                        }
                    }
                }

                if (list.Count < methods.Length)
                {
                    // restart binding with reduced list
                    methods = list.Select(l => l.Method).ToArray();
                    return(null);
                }

                Debug.Assert(list.Count != 0);

                // declare costI local variables
                locals.AddRange(list.Select(l => l.CostExpr).OfType <ParameterExpression>());

                // best = Min( cost1, .., costN )
                var        expr_best     = Expression.Variable(typeof(ConversionCost), "best");
                var        min_cost_cost = typeof(CostOf).GetMethod("Min", typeof(ConversionCost), typeof(ConversionCost));
                Expression minexpr       = list[0].CostExpr;
                for (int i = 1; i < list.Count; i++)
                {
                    minexpr = Expression.Call(min_cost_cost, list[i].CostExpr, minexpr);
                }
                body.Add(Expression.Assign(expr_best, minexpr));
                locals.Add(expr_best);

                // switch over method costs
                for (int i = list.Count - 1; i >= 0; i--)
                {
                    // (best == costI) mI(...) : ...

                    var m     = list[i].Method;
                    var mcall = ConvertExpression.Bind(BindCastToFalse(BinderHelpers.BindToCall(target, m, ctx, args, lateStaticType), DoCastToFalse(m, treturn)), treturn, ctx);
                    invoke = Expression.Condition(Expression.Equal(expr_best, list[i].CostExpr), mcall, invoke);
                }
            }

            //
            body.Insert(0, args.CreatePreamble(locals));

            //
            body.Add(invoke);

            // return Block { ... ; invoke; }
            return(Expression.Block(treturn, locals, body));
        }