コード例 #1
0
ファイル: CallBinder.cs プロジェクト: hungud/peachpie
        protected virtual Expression BindMissingMethod(DynamicMetaObject ctx, PhpTypeInfo tinfo, DynamicMetaObject nameExpr, DynamicMetaObject target, /*in, out*/ IList <DynamicMetaObject> args, ref BindingRestrictions restrictions)
        {
            string nameText = NameValue;

            if (nameText == null)
            {
                if (nameExpr != null)
                {
                    nameText = nameExpr.Value.ToString();
                }
                else
                {
                    nameText = "<unknown>";
                }
            }

            // TODO: ErrCode method not found
            throw new ArgumentException(string.Format("Function '{0}' not found!", nameText));
        }
        /// <summary>
        /// Selects only candidates of given name.
        /// </summary>
        public static MethodInfo[] SelectRuntimeMethods(this PhpTypeInfo tinfo, string name, Type classCtx)
        {
            var routine = (PhpMethodInfo)tinfo?.RuntimeMethods[name];

            if (routine != null)
            {
                return(routine.Methods);
            }
            else
            {
                if (classCtx != null && tinfo.Type.IsSubclassOf(classCtx))
                {
                    // {tinfo} extends {classCtx} // we might have to look for private methods on {classCtx}
                    return(SelectRuntimeMethods(classCtx.GetPhpTypeInfo(), name, null));
                }

                return(Array.Empty <MethodInfo>());
            }
        }
コード例 #3
0
        public static PhpInvokable BindToPhpInvokable(MethodInfo[] methods, PhpTypeInfo lateStaticType = null)
        {
            // (Context ctx, object target, PhpValue[] arguments)
            var ps = new ParameterExpression[] {
                Expression.Parameter(typeof(Context), "ctx"),
                Expression.Parameter(typeof(object), "target"),
                Expression.Parameter(typeof(PhpValue[]), "argv")
            };

            // invoke targets
            var invocation = OverloadBinder.BindOverloadCall(typeof(PhpValue), ps[1], methods, ps[0], ps[2], lateStaticType);

            Debug.Assert(invocation.Type == typeof(PhpValue));

            // compile & create delegate
            var lambda = Expression.Lambda <PhpInvokable>(invocation, methods[0].Name + "#" + methods.Length, true, ps);

            return(lambda.Compile());
        }
コード例 #4
0
ファイル: PhpCallback.cs プロジェクト: vickydeJager/peachpie
            PhpCallable BindCore(PhpTypeInfo tinfo)
            {
                var routine = (PhpMethodInfo)tinfo?.RuntimeMethods[_method];

                if (routine != null)
                {
                    return(routine.PhpInvokable.Bind(null));
                }
                else if (tinfo != null)
                {
                    routine = (PhpMethodInfo)tinfo.RuntimeMethods[TypeMethods.MagicMethods.__callstatic];
                    if (routine != null)
                    {
                        return(routine.PhpInvokable.BindMagicCall(null, _method));
                    }
                }

                return(null);
            }
コード例 #5
0
        public void __construct(Context ctx, PhpValue @class, string name)
        {
            if (name != null)
            {
                _tinfo   = ReflectionUtils.ResolvePhpTypeInfo(ctx, @class);
                _routine = _tinfo.RuntimeMethods[name] ?? throw new ReflectionException(string.Format(Resources.Resources.method_does_not_exist, _tinfo.Name, name));
            }
            else if (@class.IsString(out var class_method))
            {
                __construct(ctx, class_method);
            }
            else
            {
                throw new ReflectionException(string.Format("Invalid method name '{0}'", @class.ToString(ctx)));
            }

            // get the real declaring type from routine:
            _tinfo = _routine.DeclaringType ?? _tinfo;
        }
        public void __construct(Context ctx, string class_method)
        {
            if (class_method != null)
            {
                var col = class_method.IndexOf("::", StringComparison.Ordinal);
                if (col > 0)
                {
                    var @class = class_method.Remove(col);        // class name
                    var name   = class_method.Substring(col + 2); // method namne

                    _tinfo   = ctx.GetDeclaredTypeOrThrow(@class, true);
                    _routine = _tinfo.RuntimeMethods[name] ?? throw new ReflectionException(string.Format(Resources.Resources.method_does_not_exist, _tinfo.Name, name));

                    // ok
                    return;
                }
            }

            throw new ReflectionException();
        }
コード例 #7
0
ファイル: CallBinder.cs プロジェクト: hungud/peachpie
        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));
        }
コード例 #8
0
ファイル: CallBinder.cs プロジェクト: hungud/peachpie
        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());
        }
コード例 #9
0
        /// <summary>
        /// Default SPL autoload that tries to load scripts with name of class name concatenated with autoload extensions.
        /// </summary>
        public static void spl_autoload(Context ctx, string className)
        {
            var         extensions = ctx.GetSplAutoload()?.AutoloadExtensions ?? SplAutoloadService.DefaultAutoloadExtensions;
            PhpTypeInfo resolved   = null;

            for (int i = 0; (resolved = ctx.GetDeclaredType(className)) == null && i < extensions.Length; i++)
            {
                var ext = extensions[i];

                // try to dynamically include the file specified by the class name, if it exists
                string fileName = className + ext;
                ctx.Include(null, fileName, true, false);
            }

            if (resolved == null)
            {
                //PhpException.Throw(PhpError.Error, string.Format(CoreResources.class_could_not_be_loaded, className));
                throw new InvalidOperationException("class_could_not_be_loaded");
            }
        }
コード例 #10
0
            /// <summary>
            /// Performs autoload.
            /// </summary>
            public PhpTypeInfo AutoloadTypeByName(string fullName)
            {
                PhpTypeInfo resolved = null;

                using (var token = new Context.RecursionCheckToken(_ctx, fullName))
                {
                    if (!token.IsInRecursion)
                    {
                        var args = new[] { (PhpValue)fullName };

                        for (var node = _autoloaders.First; node != null && resolved == null; node = node.Next)
                        {
                            node.Value.Invoke(_ctx, args);
                            resolved = _ctx.GetDeclaredType(fullName);
                        }
                    }
                }

                //
                return(resolved);
            }
コード例 #11
0
ファイル: CallBinder.cs プロジェクト: hungud/peachpie
        protected override MethodBase[] ResolveMethods(DynamicMetaObject ctx, PhpTypeInfo tinfo, DynamicMetaObject nameExpr, ref DynamicMetaObject target, IList <DynamicMetaObject> args, ref BindingRestrictions restrictions)
        {
            // check tinfo is assignable from target
            if (target?.Value == null || !tinfo.Type.IsAssignableFrom(target.LimitType))
            {
                target = null;
            }

            //
            var nameStr = _name ?? (string)nameExpr.Value;

            if (nameStr != null)
            {
                // candidates:
                var candidates = tinfo.SelectRuntimeMethods(nameStr).SelectVisible(_classCtx).SelectStatic().ToList();
                return(candidates.ToArray());
            }
            else
            {
                throw new NotImplementedException();
            }
        }
コード例 #12
0
ファイル: CallBinder.cs プロジェクト: yh200212121212/peachpie
        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));
        }
コード例 #13
0
            PhpCallable BindCore(PhpTypeInfo tinfo)
            {
                var routine = (PhpMethodInfo)tinfo?.RuntimeMethods[_method];

                if (routine != null)
                {
                    return(routine.PhpInvokable.Bind(null));
                }
                else if (tinfo != null)
                {
                    routine = (PhpMethodInfo)tinfo.RuntimeMethods[TypeMethods.MagicMethods.__callstatic];
                    if (routine != null)
                    {
                        return(routine.PhpInvokable.BindMagicCall(null, _method));
                    }
                }

                Debug.WriteLine($"Method '{_class}::{_method}' is not defined!");
                // TODO: ctx.Error.CallToUndefinedMethod(_function)

                return(null);
            }
コード例 #14
0
        /// <summary>
        /// Gets <see cref="PhpTypeInfo"/> of parent.
        /// Throws in case of parent being used out of class context or within a parentless class.
        /// </summary>
        public static PhpTypeInfo GetParent(PhpTypeInfo self)
        {
            if (self == null)
            {
                PhpException.Throw(PhpError.Error, Resources.ErrResources.parent_used_out_of_class);
            }
            else
            {
                var t = self.BaseType;
                if (t != null)
                {
                    return(t);
                }
                else
                {
                    PhpException.Throw(PhpError.Error, Resources.ErrResources.parent_accessed_in_parentless_class);
                }
            }

            //
            throw new ArgumentException(nameof(self));
        }
コード例 #15
0
                IEnumerable <KeyValuePair <string, PhpValue> > EnumerateSerializableProperties(object obj, PhpTypeInfo tinfo, PhpArray properties)
                {
                    Debug.Assert(obj != null);
                    Debug.Assert(tinfo != null);
                    Debug.Assert(properties != null);

                    PhpArray runtime_fields = null;

                    var enumerator = properties.GetFastEnumerator();

                    while (enumerator.MoveNext())
                    {
                        FieldAttributes visibility;
                        string          name = enumerator.CurrentValue.ToStringOrThrow(_ctx);
                        string          declaring_type_name;
                        string          property_name = Serialization.ParseSerializedPropertyName(name, out declaring_type_name, out visibility);

                        PhpTypeInfo declarer;   // for visibility check
                        if (declaring_type_name == null)
                        {
                            declarer = tinfo;
                        }
                        else
                        {
                            declarer = _ctx.GetDeclaredType(declaring_type_name);
                            if (declarer == null)
                            {
                                // property name refers to an unknown class -> value will be null
                                yield return(new KeyValuePair <string, PhpValue>(name, PhpValue.Null));

                                continue;
                            }
                        }

                        // obtain the property desc and decorate the prop name according to its visibility and declaring class
                        var property = tinfo.GetDeclaredProperty(property_name);
                        if (property != null && !property.IsStatic && property.IsVisible(declarer.Type))
                        {
                            // if certain conditions are met, serialize the property as null
                            // (this is to precisely mimic the PHP behavior)
                            if ((visibility == (property.Attributes & FieldAttributes.FieldAccessMask) && visibility != FieldAttributes.Public) ||
                                (visibility == FieldAttributes.Private && declarer != property.ContainingType))
                            {
                                yield return(new KeyValuePair <string, PhpValue>(name, PhpValue.Null));

                                continue;
                            }

                            name = Serialization.FormatSerializedPropertyName(property);
                        }
                        else
                        {
                            property = null; // field is not visible, try runtime fields
                        }

                        // obtain the property value
                        PhpValue val;

                        if (property != null)
                        {
                            val = property.GetValue(_ctx, obj);
                        }
                        else
                        {
                            if (runtime_fields == null)
                            {
                                runtime_fields = tinfo.GetRuntimeFields(obj) ?? PhpArray.Empty;
                            }

                            if (!runtime_fields.TryGetValue(name, out val))
                            {
                                // PHP 5.1+
                                PhpException.Throw(PhpError.Notice, string.Format(Core.Resources.ErrResources.sleep_returned_bad_field, name));
                            }
                        }

                        yield return(new KeyValuePair <string, PhpValue>(name, val));
                    }
                }
コード例 #16
0
ファイル: Context.cs プロジェクト: SanduRajapakse/peachpie
 /// <summary>
 /// Declare a runtime user type unser an aliased name.
 /// </summary>
 /// <param name="tinfo">Original type descriptor.</param>
 /// <param name="typename">Type name alias, can differ from <see cref="PhpTypeInfo.Name"/>.</param>
 public void DeclareType(PhpTypeInfo tinfo, string typename) => _types.DeclareTypeAlias(tinfo, typename);
コード例 #17
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));
        }
コード例 #18
0
ファイル: Objects.cs プロジェクト: vickydeJager/peachpie
 public static string get_called_class([ImportCallerStaticClass] PhpTypeInfo @static) => @static?.Name;
コード例 #19
0
        public static Expression BindOverloadCall(Type treturn, Expression target, MethodBase[] methods, Expression ctx, Expression argsarray, bool isStaticCallSyntax, PhpTypeInfo lateStaticType = null)
        {
            Expression result = null;

            while (result == null)
            {
                result = BindOverloadCall(treturn, target, ref methods, ctx, new ArgumentsBinder.ArgsArrayBinder(ctx, argsarray), isStaticCallSyntax, lateStaticType);
            }

            return(result);
        }
コード例 #20
0
        public static Expression BindOverloadCall(Type treturn, Expression target, MethodBase[] methods, Expression ctx, Expression[] args, PhpTypeInfo lateStaticType = null)
        {
            Expression result = null;

            while (result == null)
            {
                result = BindOverloadCall(treturn, target, ref methods, ctx, new ArgumentsBinder.ArgsBinder(ctx, args), lateStaticType);
            }

            return(result);
        }
コード例 #21
0
ファイル: BinderHelpers.cs プロジェクト: allisterb/peachpie
 public static PhpMethodInfo FindMagicMethod(PhpTypeInfo type, TypeMethods.MagicMethods magic)
 {
     return((PhpMethodInfo)type.RuntimeMethods[magic]);
 }
コード例 #22
0
ファイル: BinderHelpers.cs プロジェクト: allisterb/peachpie
        public static Expression BindField(PhpTypeInfo type, Type classCtx, Expression target, string field, Expression ctx, AccessMask access, Expression rvalue)
        {
            if (access.Write() != (rvalue != null))
            {
                throw new ArgumentException();
            }

            // lookup a declared field
            for (var t = type; t != null; t = t.BaseType)
            {
                foreach (var p in t.DeclaredFields.GetPhpProperties(field))
                {
                    if (p.IsStatic == (target == null) && p.IsVisible(classCtx))
                    {
                        return(BindAccess(p.Bind(ctx, target), ctx, access, rvalue));
                    }
                }
            }

            //
            // runtime fields
            //

            if (type.RuntimeFieldsHolder != null)                                         // we don't handle magic methods without the runtime fields
            {
                var runtimeflds = Expression.Field(target, type.RuntimeFieldsHolder);     // Template: target->__runtime_fields
                var fieldkey    = Expression.Constant(new IntStringKey(field));           // Template: IntStringKey(field)
                var resultvar   = Expression.Variable(Cache.Types.PhpValue[0], "result"); // Template: PhpValue result;

                // Template: runtimeflds != null && runtimeflds.TryGetValue(field, out result)
                var trygetfield   = Expression.AndAlso(Expression.ReferenceNotEqual(runtimeflds, Expression.Constant(null)), Expression.Call(runtimeflds, Cache.Operators.PhpArray_TryGetValue, fieldkey, resultvar));
                var containsfield = Expression.AndAlso(Expression.ReferenceNotEqual(runtimeflds, Expression.Constant(null)), Expression.Call(runtimeflds, Cache.Operators.PhpArray_ContainsKey, fieldkey));

                Expression result;

                //
                if (access.EnsureObject())
                {
                    // (object)target->field->

                    // Template: runtimeflds.EnsureObject(key)
                    result = Expression.Call(EnsureNotNullPhpArray(runtimeflds), Cache.Operators.PhpArray_EnsureItemObject, fieldkey);

                    var __get = BindMagicMethod(type, classCtx, target, ctx, TypeMethods.MagicMethods.__get, field, null);
                    if (__get != null)
                    {
                        // Template: runtimeflds.Contains(key) ? runtimeflds.EnsureObject(key) : ( __get(key) ?? runtimeflds.EnsureObject(key))
                        return(Expression.Condition(containsfield,
                                                    Expression.Call(runtimeflds, Cache.Operators.PhpArray_EnsureItemObject, fieldkey),
                                                    InvokeHandler(ctx, target, field, __get, access, result, typeof(object))));
                    }
                    else
                    {
                        return(result);
                    }
                }
                else if (access.EnsureArray())
                {
                    // (IPhpArray)target->field[] =
                    result = Expression.Call(EnsureNotNullPhpArray(runtimeflds), Cache.Operators.PhpArray_EnsureItemArray, fieldkey);

                    var __get = BindMagicMethod(type, classCtx, target, ctx, TypeMethods.MagicMethods.__get, field, null);
                    if (__get != null)
                    {
                        // Template: runtimeflds.Contains(key) ? runtimeflds.EnsureArray(key) : ( __get(key) ?? runtimeflds.EnsureArray(key))
                        return(Expression.Condition(containsfield,
                                                    Expression.Call(runtimeflds, Cache.Operators.PhpArray_EnsureItemArray, fieldkey),
                                                    InvokeHandler(ctx, target, field, __get, access, result, typeof(IPhpArray))));
                    }
                    else
                    {
                        // runtimeflds.EnsureItemArray(key)
                        return(result);
                    }
                }
                else if (access.EnsureAlias())
                {
                    // (PhpAlias)&target->field

                    result = Expression.Call(EnsureNotNullPhpArray(runtimeflds), Cache.Operators.PhpArray_EnsureItemAlias, fieldkey);

                    var __get = BindMagicMethod(type, classCtx, target, ctx, TypeMethods.MagicMethods.__get, field, null);
                    if (__get != null)
                    {
                        // Template: runtimeflds.Contains(key) ? runtimeflds.EnsureItemAlias(key) : ( __get(key) ?? runtimeflds.EnsureItemAlias(key))
                        return(Expression.Condition(containsfield,
                                                    Expression.Call(runtimeflds, Cache.Operators.PhpArray_EnsureItemAlias, fieldkey),
                                                    InvokeHandler(ctx, target, field, __get, access, result, typeof(PhpAlias))));
                    }
                    else
                    {
                        // runtimeflds.EnsureItemAlias(key)
                        return(result);
                    }
                }
                else if (access.Unset())
                {
                    // unset(target->field)
                    // Template: if (!runtimeflds.RemoveKey(key)) __unset(key)

                    var removekey = Expression.Call(runtimeflds, Cache.Operators.PhpArray_RemoveKey, fieldkey);
                    var __unset   = BindMagicMethod(type, classCtx, target, ctx, TypeMethods.MagicMethods.__unset, field, null);
                    if (__unset != null)
                    {
                        return(Expression.IfThen(
                                   Expression.OrElse(Expression.ReferenceEqual(runtimeflds, Expression.Constant(null)), Expression.IsFalse(removekey)),
                                   InvokeHandler(ctx, target, field, __unset, access, Expression.Block(), typeof(void))));
                    }
                    else
                    {
                        // if (runtimeflds != null) runtimeflds.RemoveKey(key)
                        return(Expression.IfThen(
                                   Expression.ReferenceNotEqual(runtimeflds, Expression.Constant(null)),
                                   removekey));
                    }
                }
                else if (access.Write())
                {
                    var __set = BindMagicMethod(type, classCtx, target, ctx, TypeMethods.MagicMethods.__set, field, rvalue);

                    if (access.WriteAlias())
                    {
                        // target->field = (PhpAlias)&rvalue
                        Debug.Assert(rvalue.Type == typeof(PhpAlias));
                        rvalue = ConvertExpression.Bind(rvalue, typeof(PhpAlias), ctx);

                        // EnsureNotNull(runtimeflds).SetItemAlias(key, rvalue)
                        result = Expression.Call(EnsureNotNullPhpArray(runtimeflds), Cache.Operators.PhpArray_SetItemAlias, fieldkey, rvalue);

                        if (__set != null)
                        {
                            // if (ContainsKey(key)) ? runtimeflds.SetItemAlias(rvalue) : (__set(key, rvalue) ?? runtimeflds.SetItemAlias(key, rvalue)
                            return(Expression.Condition(containsfield,
                                                        Expression.Call(runtimeflds, Cache.Operators.PhpArray_SetItemAlias, fieldkey, rvalue),
                                                        InvokeHandler(ctx, target, field, __set, access, result, typeof(void))));
                        }
                        else
                        {
                            return(result);
                        }
                    }
                    else
                    {
                        // target->field = rvalue
                        rvalue = ConvertExpression.Bind(rvalue, typeof(PhpValue), ctx);

                        /* Template:
                         * return runtimeflds != null && runtimeflds.ContainsKey(field)
                         *   ? runtimeflds.SetItemValue(key, rvalue)
                         *   : (__set(field, value) ?? runtimeflds.SetItemValue(key, value))
                         */

                        result = Expression.Call(EnsureNotNullPhpArray(runtimeflds), Cache.Operators.PhpArray_SetItemValue, fieldkey, rvalue);

                        if (__set != null)
                        {
                            return(Expression.Condition(containsfield,
                                                        Expression.Call(runtimeflds, Cache.Operators.PhpArray_SetItemValue, fieldkey, rvalue),
                                                        InvokeHandler(ctx, target, field, __set, access, result, typeof(void))));
                        }
                        else
                        {
                            return(result);
                        }
                    }
                }
                else if (access.Isset())
                {
                    // isset(target->field)

                    var __isset = BindMagicMethod(type, classCtx, target, ctx, TypeMethods.MagicMethods.__isset, field, null);

                    // Template: (TryGetField(result) || (bool)__isset(key)) ? true : void
                    result = Expression.Condition(Expression.OrElse(
                                                      trygetfield,
                                                      ConvertExpression.BindToBool(InvokeHandler(ctx, target, field, __isset, access))),
                                                  Expression.Property(null, Cache.Properties.PhpValue_True),
                                                  Expression.Field(null, Cache.Properties.PhpValue_Void));
                }
                else
                {
                    // = target->field

                    /* Template:
                     * return runtimeflds.TryGetValue(field, out result) ? result : (__get(field) ?? ERR);
                     */
                    var __get = BindMagicMethod(type, classCtx, target, ctx, TypeMethods.MagicMethods.__get, field, null);
                    result = Expression.Condition(trygetfield,
                                                  resultvar,
                                                  InvokeHandler(ctx, target, field, __get, access)); // TODO: @default = { ThrowError; return null; }
                }

                //
                return(Expression.Block(result.Type, new[] { resultvar }, result));
            }

            // TODO: IDynamicMetaObject

            //
            return(null);
        }
コード例 #23
0
ファイル: PDOStatement.cs プロジェクト: Unknown6656/peachpie
        internal bool setFetchMode(PDO_FETCH mode, ReadOnlySpan <PhpValue> args)
        {
            switch (mode & ~PDO_FETCH.Flags)
            {
            case PDO_FETCH.Default:
            case PDO_FETCH.FETCH_LAZY:
            case PDO_FETCH.FETCH_ASSOC:
            case PDO_FETCH.FETCH_NUM:
            case PDO_FETCH.FETCH_BOTH:
            case PDO_FETCH.FETCH_OBJ:
            case PDO_FETCH.FETCH_BOUND:
            case PDO_FETCH.FETCH_NAMED:
            case PDO_FETCH.FETCH_KEY_PAIR:
                if (args.Length != 0)
                {
                    HandleError("fetch mode doesn't allow any extra arguments");
                    return(false);
                }

                // ok
                break;

            case PDO_FETCH.FETCH_COLUMN:
                if (args.Length != 1)
                {
                    HandleError("fetch mode requires the colno argument");
                    return(false);
                }
                else if (args[0].IsLong(out var l))
                {
                    _fetch_column = (int)l;
                    break;
                }
                else
                {
                    HandleError("colno must be an integer");
                    return(false);
                }

            case PDO_FETCH.FETCH_CLASS:

                _default_fetch_class_args = default;
                _default_fetch_class      = null;

                if ((mode & PDO_FETCH.FETCH_CLASSTYPE) != 0)
                {
                    // will be getting its class name from 1st column
                    if (args.Length != 0)
                    {
                        HandleError("fetch mode doesn't allow any extra arguments");
                        return(false);
                    }
                    else
                    {
                        break;
                    }
                }
                else
                {
                    if (args.Length == 0)
                    {
                        HandleError("fetch mode requires the classname argument");
                        return(false);
                    }
                    else if (args.Length > 2)
                    {
                        HandleError("too many arguments");
                        return(false);
                    }
                    else if (args[0].IsString(out var name))
                    {
                        _default_fetch_class = Context.GetDeclaredTypeOrThrow(name, autoload: true);
                        if (_default_fetch_class != null)
                        {
                            if (args.Length > 1)
                            {
                                var ctorargs = args[1].AsArray();
                                if (ctorargs == null && !args[1].IsNull)
                                {
                                    HandleError("ctor_args must be either NULL or an array");
                                    return(false);
                                }
                                else if (ctorargs != null && ctorargs.Count != 0)
                                {
                                    _default_fetch_class_args = ctorargs.GetValues();     // TODO: deep copy
                                }
                            }

                            break;
                        }
                        else
                        {
                            return(false);
                        }
                    }
                    else
                    {
                        HandleError("classname must be a string");
                        return(false);
                    }
                }

            //case PDO_FETCH.FETCH_INTO:
            //    if (args.Length != 1)
            //    {
            //        RaiseError("fetch mode requires the object parameter");
            //        return false;
            //    }
            //    else
            //    {
            //        FetchClassInto = args[0].AsObject();
            //        if (FetchClassInto == null)
            //        {
            //            RaiseError("object must be an object");
            //            return false;
            //        }

            //        m_fetchStyle = mode;
            //        return true;
            //    }

            //default:
            //    RaiseError("Invalid fetch mode specified");
            //    return false;

            default:
                throw new NotImplementedException(mode.ToString());
            }

            //
            _default_fetch_type = mode;

            return(true);
        }
コード例 #24
0
 /// <summary>
 /// Checks the user type is declared in the current state of <see cref="Context"/>.
 /// </summary>
 /// <param name="phptype">PHP type runtime information. Must not be <c>null</c>.</param>
 /// <returns>True if the type has been declared on the current <see cref="Context"/>.</returns>
 internal bool IsUserTypeDeclared(PhpTypeInfo phptype) => _types.IsDeclared(phptype);
コード例 #25
0
ファイル: BinderHelpers.cs プロジェクト: iolevel/peachpie
        public static Expression BindField(PhpTypeInfo type, Type classCtx, Expression target, string field, Expression ctx, AccessFlags access, Expression rvalue)
        {
            if (access.Write() != (rvalue != null))
            {
                throw new ArgumentException();
            }

            // lookup a declared field
            for (var t = type; t != null; t = t.BaseType)
            {
                var expr = t.DeclaredFields.Bind(field, classCtx, target, ctx, (target != null) ? TypeFields.FieldKind.InstanceField : TypeFields.FieldKind.StaticField);
                if (expr != null)
                {
                    return BindAccess(expr, ctx, access, rvalue);
                }
            }

            // lookup __get, __set, ...
            TypeMethods.MagicMethods magic;
            if (access.Write())
                magic = TypeMethods.MagicMethods.__set;
            else if (access.Unset())
                magic = TypeMethods.MagicMethods.__unset;
            else if (access.Isset())
                magic = TypeMethods.MagicMethods.__isset;
            else
                magic = TypeMethods.MagicMethods.__get;

            for (var t = type; t != null; t = t.BaseType)
            {
                var m = (PhpMethodInfo)t.DeclaredMethods[magic];
                if (m != null)
                {
                    if (m.Methods.Length == 1 && m.Methods[0].IsVisible(classCtx))
                    {
                        switch (magic)
                        {
                            case TypeMethods.MagicMethods.__set:
                                // __set(name, value)
                                return OverloadBinder.BindOverloadCall(rvalue.Type, target, m.Methods, ctx, new Expression[] { Expression.Constant(field), rvalue });
                            default:
                                // __get(name), __unset(name), __isset(name)
                                return OverloadBinder.BindOverloadCall(m.Methods[0].ReturnType, target, m.Methods, ctx, new Expression[] { Expression.Constant(field) });
                        }
                    }

                    break;
                }
            }

            // runtime fields
            var __runtimeflds = type.RuntimeFieldsHolder;
            if (__runtimeflds != null)
            {
                var __runtimeflds_field = Expression.Field(target, __runtimeflds);
                var key = Expression.Constant(new IntStringKey(field));

                return BindArrayAccess(__runtimeflds_field, key, ctx, access, rvalue);
            }

            // TODO: dynamic

            //
            return null;
        }
コード例 #26
0
        public static Expression BindToCall(Expression instance, MethodBase method, Expression ctx, OverloadBinder.ArgumentsBinder args, PhpTypeInfo lateStaticType)
        {
            Debug.Assert(method is MethodInfo || method is ConstructorInfo);

            var ps        = method.GetParameters();
            var boundargs = new Expression[ps.Length];

            int argi = 0;

            for (int i = 0; i < ps.Length; i++)
            {
                var p = ps[i];
                if (argi == 0 && p.IsImplicitParameter())
                {
                    if (p.IsContextParameter())
                    {
                        boundargs[i] = ctx;
                    }
                    else if (p.IsLateStaticParameter())
                    {
                        if (lateStaticType != null)
                        {
                            // Template: PhpTypeInfoExtension.GetPhpTypeInfo<lateStaticType>()
                            boundargs[i] = Expression.Call(
                                null,
                                typeof(PhpTypeInfoExtension).GetMethod("GetPhpTypeInfo", Cache.Types.Empty).MakeGenericMethod(lateStaticType.Type.AsType()));
                        }
                        else
                        {
                            throw new InvalidOperationException("static context not available.");
                        }
                    }
                    else if (p.IsImportLocalsParameter())
                    {
                        // no way we can implement this
                        throw new NotImplementedException();    // TODO: empty array & report warning
                    }
                    else if (p.IsImportCallerArgsParameter())
                    {
                        // we don't have this info
                        throw new NotImplementedException();    // TODO: empty array & report warning
                    }
                    else if (p.IsImportCallerClassParameter())
                    {
                        // TODO: pass classctx from the callsite
                        throw new NotImplementedException();
                    }
                    else if (p.IsImportCallerStaticClassParameter())
                    {
                        throw new NotSupportedException(); // we don't know current late static bound type
                    }
                    else
                    {
                        throw new NotImplementedException();
                    }
                }
                else
                {
                    if (i == ps.Length - 1 && p.IsParamsParameter())
                    {
                        var element_type = p.ParameterType.GetElementType();
                        boundargs[i] = args.BindParams(argi, element_type);
                        break;
                    }
                    else
                    {
                        boundargs[i] = args.BindArgument(argi, p);
                    }

                    //
                    argi++;
                }
            }

            //
            Debug.Assert(boundargs.All(x => x != null));

            //
            if (method.IsStatic)
            {
                instance = null;
            }

            //
            if (method.IsConstructor)
            {
                return(Expression.New((ConstructorInfo)method, boundargs));
            }

            if (instance != null)
            {
                instance = Expression.Convert(instance, method.DeclaringType);
            }

            if (instance != null && method.IsVirtual)   // NOTE: only needed for parent::foo(), static::foo() and self::foo() ?
            {
                // Ugly hack here,
                // we NEED to call the method nonvirtually, but LambdaCompiler emits .callvirt always and there is no way how to change it (except we can emit all the stuff by ourselfs).
                // We use DynamicMethod to emit .call inside, and use its MethodInfo which is static.
                // LambdaCompiler generates .call to static DynamicMethod which calls our method via .call as well,
                // after all the inlining, there should be no overhead.

                method = WrapInstanceMethodToStatic((MethodInfo)method);

                //
                var newargs = new Expression[boundargs.Length + 1];
                newargs[0] = instance;
                Array.Copy(boundargs, 0, newargs, 1, boundargs.Length);
                boundargs = newargs;
                instance  = null;
            }

            //
            return(Expression.Call(instance, (MethodInfo)method, boundargs));
        }
コード例 #27
0
 public static string get_called_class([ImportValue(ImportValueAttribute.ValueSpec.CallerStaticClass)] PhpTypeInfo @static) => @static?.Name;
コード例 #28
0
ファイル: Functions.cs プロジェクト: Seamless2014/peachpie
 /// <summary>
 /// Calls a user defined function or method given by the function parameter.
 /// This function must be called within a method context, it can't be used outside a class.
 /// It uses the late static binding.
 /// All arguments of the forwarded method are passed as values, and as an array, similarly to <see cref="call_user_func_array"/>.
 /// </summary>
 public static PhpValue forward_static_call_array(Context ctx, [ImportValue(ImportValueAttribute.ValueSpec.CallerStaticClass)] PhpTypeInfo @static, IPhpCallable function, PhpArray args)
 {
     return(forward_static_call(ctx, @static, function, args.GetValues()));
 }
コード例 #29
0
 internal ReflectionClass(PhpTypeInfo tinfo)
 {
     Debug.Assert(tinfo != null);
     _tinfo = tinfo;
 }
コード例 #30
0
        public virtual void __construct(Context ctx, PhpValue @class)
        {
            Debug.Assert(_tinfo == null, "Subsequent call not allowed.");

            _tinfo = ReflectionUtils.ResolvePhpTypeInfo(ctx, @class);
        }
コード例 #31
0
 /// <summary>
 /// Binds callback to given late static bound type.
 /// </summary>
 public virtual PhpCallable BindToStatic(Context ctx, PhpTypeInfo @static) => Bind(ctx);