static Expression BindMagicMethod(PhpTypeInfo type, Type classCtx, Expression target, Expression ctx, TypeMethods.MagicMethods magic, string field, Expression rvalue = null) { var m = FindMagicMethod(type, magic); if (m != null) { var methods = m.Methods.Length == 1 ? (m.Methods[0].IsVisible(classCtx) ? m.Methods : Array.Empty <MethodInfo>()) // optimization for array[1] : m.Methods.Where(x => x.IsVisible(classCtx)).ToArray(); if (methods.Length != 0) { switch (magic) { case TypeMethods.MagicMethods.__set: // __set(name, value) return(OverloadBinder.BindOverloadCall(typeof(void), target, methods, ctx, new Expression[] { Expression.Constant(field), rvalue })); default: // __get(name), __unset(name), __isset(name) return(OverloadBinder.BindOverloadCall(methods[0].ReturnType, target, methods, ctx, new Expression[] { Expression.Constant(field) })); } } else { // TODO: ERR inaccessible } } return(null); }
public sealed override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args) { var restrictions = BindingRestrictions.Empty; var argsList = new List <DynamicMetaObject>(args); // ctx, [Target], [TypeName], [RoutineName], [args...] Debug.Assert(target?.Value is Context); var ctx = target; target = PopTargetOrNull(argsList); var tinfo = PopTypeInfoOrNull(argsList, ref restrictions); var nameExpr = PopNameExpression(argsList, ref restrictions); // Expression invocation; // var methods = ResolveMethods(ctx, tinfo, nameExpr, ref target, argsList, ref restrictions); if (methods != null && methods.Length != 0) { // TODO: visibility var expr_args = argsList.Select(x => x.Expression).ToArray(); invocation = OverloadBinder.BindOverloadCall(_returnType, target?.Expression, methods, ctx.Expression, expr_args, tinfo); } else { invocation = BindMissingMethod(ctx, tinfo, nameExpr, target, argsList, ref restrictions); } // TODO: by alias or by value return(new DynamicMetaObject(invocation, restrictions)); }
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)); }
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)); }
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)); }
public static TObjectCreator BindToCreator(ConstructorInfo[] ctors) { // (Context ctx, PhpValue[] arguments) var ps = new ParameterExpression[] { Expression.Parameter(typeof(Context), "ctx"), Expression.Parameter(typeof(PhpValue[]), "argv") }; // invoke targets var invocation = OverloadBinder.BindOverloadCall(typeof(object), null, ctors, ps[0], ps[1]); Debug.Assert(invocation.Type == typeof(object)); // compile & create delegate var lambda = Expression.Lambda <TObjectCreator>(invocation, ctors[0].Name + "#" + ctors.Length, true, ps); return(lambda.Compile()); }
public static PhpCallable BindToPhpCallable(MethodBase[] targets) { Debug.Assert(targets.All(t => t.IsStatic), "Only static methods can be bound to PhpCallable delegate."); // (Context ctx, PhpValue[] arguments) var ps = new ParameterExpression[] { Expression.Parameter(typeof(Context), "ctx"), Expression.Parameter(typeof(PhpValue[]), "argv") }; // invoke targets var invocation = OverloadBinder.BindOverloadCall(typeof(PhpValue), null, targets, ps[0], ps[1]); Debug.Assert(invocation.Type == typeof(PhpValue)); // compile & create delegate var lambda = Expression.Lambda <PhpCallable>(invocation, targets[0].Name + "#" + targets.Length, true, ps); return(lambda.Compile()); }
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)); }
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)); }
public static PhpInvokable BindToPhpInvokable(MethodInfo[] methods) { // (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]); 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()); }
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)); }
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) { invocation = OverloadBinder.BindOverloadCall(_returnType, bound.TargetInstance, methods, bound.Context, bound.Arguments, bound.TargetType); } else { invocation = BindMissingMethod(bound); } // TODO: by alias or by value return(new DynamicMetaObject(invocation, bound.Restrictions)); }
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)); }
public sealed override DynamicMetaObject Bind(DynamicMetaObject target, DynamicMetaObject[] args) { var restrictions = BindingRestrictions.Empty; var argsList = new List <DynamicMetaObject>(args); // get target and context DynamicMetaObject ctx; if (HasTarget) { ctx = args[0]; argsList.RemoveAt(0); } else { ctx = target; target = null; } // Expression invocation; var methods = ResolveMethods(ctx, ref target, argsList, ref restrictions); if (methods != null && methods.Length != 0) { var expr_args = argsList.Select(x => x.Expression).ToArray(); invocation = OverloadBinder.BindOverloadCall(_returnType, target?.Expression, methods, ctx.Expression, expr_args); } else { invocation = BindMissingMethod(ctx, target, argsList, ref restrictions); } // TODO: by alias or by value return(new DynamicMetaObject(invocation, restrictions)); }
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)); }
public static TObjectCreator BindToCreator(Type type, ConstructorInfo[] ctors) { Debug.Assert(ctors.All(ctor => ctor is ConstructorInfo)); Debug.Assert(ctors.All(ctor => ctor.DeclaringType == type)); // (Context ctx, PhpValue[] arguments) var ps = new ParameterExpression[] { Expression.Parameter(typeof(Context), "ctx"), Expression.Parameter(typeof(PhpValue[]), "argv") }; if (ctors.Length != 0) { // invoke targets var invocation = OverloadBinder.BindOverloadCall(type, null, ctors, ps[0], ps[1]); Debug.Assert(invocation.Type == type); // compile & create delegate var lambda = Expression.Lambda <TObjectCreator>(invocation, ctors[0].Name + "#" + ctors.Length, true, ps); return(lambda.Compile()); } else { // TODO: lambda {error; NULL;} throw new ArgumentException("No constructor accessible for " + type.FullName); } }
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); }