/// <summary> /// Generates Expression that throws a 'Protected method called' or 'Private method called' <see cref="PhpException"/>. /// </summary> /// <param name="method">The <see cref="DRoutineDesc"/>.</param> /// <param name="callerContext">The caller that was passed to method lookup or <B>null</B> /// if it should be determined by this method (by tracing the stack).</param> /// <remarks> /// This method is intended to be called after <see cref="DTypeDesc.GetMethod"/> has returned /// <see cref="GetMemberResult.BadVisibility"/> while performing a method lookup. /// </remarks> public static Expression/*!*/ ThrowVisibilityError(DRoutineDesc/*!*/ method, DTypeDesc/*!*/ callerContext) { if (method.IsProtected) { return ThrowError("protected_method_called", method.DeclaringType.MakeFullName(), method.MakeFullName(), callerContext == null ? String.Empty : callerContext.MakeFullName()); } else if (method.IsPrivate) { return ThrowError("private_method_called", method.DeclaringType.MakeFullName(), method.MakeFullName(), callerContext == null ? String.Empty : callerContext.MakeFullName()); } throw new NotImplementedException(); }
public virtual object __construct(ScriptContext context, object @class, object methodname) { string methodnameStr = PhpVariable.AsString(methodname); this.dtype = null; this.method = null; DObject dobj; if ((dobj = (@class as DObject)) != null) { this.dtype = dobj.TypeDesc; } else { var str = PhpVariable.AsString(@class); if (str != null) this.dtype = context.ResolveType(str, null, null, null, ResolveTypeFlags.UseAutoload); if (this.dtype == null) { PhpException.Throw(PhpError.Error, string.Format("Class {0} does not exist", str)); return false; } } if (this.dtype.GetMethod(new Name(methodnameStr), dtype, out this.method) == GetMemberResult.NotFound) { PhpException.Throw(PhpError.Error, string.Format("Method {0}::{1}() does not exist", dtype.MakeFullName(), methodnameStr)); return false; } return null; }
public virtual object __construct(ScriptContext context, object arg) { string name = PhpVariable.AsString(arg); if (!string.IsNullOrEmpty(name)) { routine = context.ResolveFunction(name, null, false); } else { PhpException.InvalidArgument("arg"); } if (routine == null) PhpException.Throw(PhpError.Error, string.Format("Function {0}() does not exist", name)); return null; }
/// <summary> /// Used by the reflection. /// </summary> public PhpRoutine(DRoutineDesc/*!*/ functionDesc) : base(functionDesc) { this.signature = null; // to be written up this.builder = null; // unused }
/// <summary> /// Used by the compiler. /// </summary> internal PhpRoutine(DRoutineDesc/*!*/ functionDesc, Signature astSignature, TypeSignature astTypeSignature) : base(functionDesc) { this.signature = null; // to be written up this.builder = new PhpRoutineBuilder(this, astSignature, astTypeSignature); }
/// <summary> /// Used by the compiler and the reflector. /// </summary> public KnownRoutine(DRoutineDesc/*!*/ routineDesc) : base(routineDesc) { }
/// <summary> /// Creates bounded PHP instance method callback. Used when we already know the routine. /// </summary> /// <param name="instance">The target PHP object.</param> /// <param name="routine">The target PHP method.</param> internal PhpCallback(DObject instance, DRoutineDesc routine) { Debug.Assert(instance != null); Debug.Assert(routine != null); this.instance = instance; this.targetName = routine.Member.FullName; this.state = State.Bound; this.routineDesc = routine; this.lateStaticBindType = instance.TypeDesc; }
/// <summary> /// Attempts to bind this callback to its target. /// </summary> /// <param name="quiet"><B>true</B> of no errors should be thrown, <B>false</B> otherwise.</param> /// <param name="nameContext">Current <see cref="NamingContext"/> for function and class name resolution.</param> /// <param name="caller">Current class context or a <see cref="UnknownTypeDesc"/> if the class context /// should be determined ad-hoc.</param> /// <returns><B>True</B> if the callback was successfully bound, <B>false</B> if an error occured.</returns> public bool Bind(bool quiet, DTypeDesc caller, NamingContext nameContext) { if (IsInvalid) return false; switch (state) { case State.UnboundFunction: { if (context == null) context = ScriptContext.CurrentContext; routineDesc = context.ResolveFunction(targetName, nameContext, quiet); if (routineDesc == null) return false; state = State.Bound; return true; } case State.UnboundStaticMethod: { if (context == null) context = ScriptContext.CurrentContext; if (caller != null && caller.IsUnknown) callingContext = PhpStackTrace.GetClassContext(); else callingContext = caller; // try to find the CLR method // find the class according to className ResolveTypeFlags flags = ResolveTypeFlags.UseAutoload; if (!quiet) flags |= ResolveTypeFlags.ThrowErrors; DTypeDesc type = context.ResolveType(className, nameContext, callingContext, null, flags); if (type == null) return false; // find the method bool is_caller_method; lateStaticBindType = type; routineDesc = Operators.GetStaticMethodDesc(type, targetName, ref instance, callingContext, context, quiet, false, out is_caller_method); if (routineDesc == null) return false; if (instance != null) dummyInstance = true; state = is_caller_method ? State.BoundToCaller : State.Bound; return true; } case State.UnboundInstanceMethod: { if (caller != null && caller.IsUnknown) callingContext = PhpStackTrace.GetClassContext(); else callingContext = caller; // ask the instance for a handle to the method bool is_caller_method; routineDesc = instance.GetMethodDesc(targetName, callingContext, quiet, out is_caller_method); if (routineDesc == null) return false; state = (is_caller_method ? State.BoundToCaller : State.Bound); return true; } } return true; }
public PhpCallback(RoutineDelegate functionDelegate, ScriptContext context) { // create a new DRoutineDesc based on the passed delegate routineDesc = new PhpRoutineDesc(PhpMemberAttributes.Static | PhpMemberAttributes.NamespacePrivate, functionDelegate, false); this.context = context; this.state = State.Bound; }
/// <summary> /// Creates a callback bound to the specified PHP method represented by a <see cref="DRoutineDesc"/>. /// </summary> /// <param name="instance">The target PHP object.</param> /// <param name="handle">The handle of the target PHP method.</param> /// <param name="context">The script context to call the method with.</param> public PhpCallback(DObject instance, DRoutineDesc handle, ScriptContext context) { if (handle == null) throw new ArgumentNullException("handle"); if (!handle.IsStatic) { if (instance == null) throw new ArgumentNullException("instance"); this.instance = instance; } this.context = context; this.routineDesc = handle; this.state = State.Bound; if (instance != null) this.lateStaticBindType = instance.TypeDesc; }
private void InvokeCallMethod(DynamicMetaObject target, DynamicMetaObject/*!*/[] args, DObject/*!*/ obj, DRoutineDesc/*!*/ method, out BindingRestrictions restrictions, out Expression invokeMethodExpr) { var insideCaller = Expression.Property( Expression.Convert(target.Expression, Types.DObject[0]), Properties.DObject_InsideCaller); if (argsArrayVariable == null) argsArrayVariable = Expression.Parameter(Types.PhpArray[0], "args"); if (retValVariable == null) retValVariable = Expression.Parameter(Types.Object[0], "retVal"); ParameterExpression[] vars = new ParameterExpression[] { argsArrayVariable, retValVariable }; // Just select real method arguments without ScriptContext and generic type arguments var justParams = BinderHelper.PackToExpressions(args, 1 + _genericParamsCount, _paramsCount); // Expression which calls ((PhpArray)argArray).add method on each real method argument. var initArgsArray = Array.ConvertAll<Expression, Expression>(justParams, (x) => Expression.Call(argsArrayVariable, Methods.PhpHashtable_Add, x)); // Argfull __call signature: (ScriptContext, object, object)->object var callerMethodArgs = new DynamicMetaObject[3] { args[0], new DynamicMetaObject(Expression.Constant(ActualMethodName),BindingRestrictions.Empty), new DynamicMetaObject(argsArrayVariable, BindingRestrictions.Empty) }; // what if method.PhpRoutine is null InvokePhpMethod(target, callerMethodArgs, /*(PhpObject)target.Value, */method.PhpRoutine, out restrictions, out invokeMethodExpr); //Expression: // if (target.insideCaller) // throw new UndefinedMethodException(); // // args = new PhpArray(paramsCount, 0); // // args.Add(arg0); // . // . // args.Add(paramsCount); // // target.insideCaller = true; // try // { // ret_val = target.__call( scriptContext, methodName, args); // } // finally // { // target.insideCaller = false; // } // return ret_val; // invokeMethodExpr = Expression.Block( vars,//local variables Expression.IfThen(Expression.Property( Expression.Convert(target.Expression, Types.DObject[0]), Properties.DObject_InsideCaller), Expression.Call(Methods.PhpException.UndefinedMethodCalled, Expression.Constant(obj.TypeName), Expression.Constant(ActualMethodName))), Expression.Assign( argsArrayVariable, Expression.New(Constructors.PhpArray.Int32_Int32, Expression.Constant(_paramsCount), Expression.Constant(0))), ((initArgsArray.Length == 0) ? (Expression)Expression.Empty() : Expression.Block(initArgsArray)), Expression.Assign(insideCaller, Expression.Constant(true)), Expression.TryFinally( //__call(caller,args) Expression.Assign(retValVariable, invokeMethodExpr), //Finally part: Expression.Assign(insideCaller, Expression.Constant(false)) ), HandleResult(retValVariable, method.PhpRoutine.ArgFullInfo.ReturnType, false)); }
private void InvokeArgLess(DynamicMetaObject target, DynamicMetaObject scriptContext, DRoutineDesc method, DynamicMetaObject[] args, out BindingRestrictions restrictions, out Expression invokeMethodExpr) { int argsWithoutScriptContext = RealMethodArgumentCount - 1; System.Reflection.MethodInfo miAddFrame = Methods.PhpStack.AddFrame.Overload(argsWithoutScriptContext); Expression[] argsExpr = null; if (miAddFrame == Methods.PhpStack.AddFrame.N) { //Create array of arguments argsExpr = new Expression[1]; argsExpr[0] = Expression.NewArrayInit(Types.Object[0], BinderHelper.PackToExpressions(args, 0, argsWithoutScriptContext)); } else { //call overload with < N arguments //argsExpr = new Expression[argsWithoutScriptContext]; argsExpr = BinderHelper.PackToExpressions(args, 0, argsWithoutScriptContext); } var stack = Expression.Field(scriptContext.Expression, Fields.ScriptContext_Stack); // scriptContext.PhpStack // PhpStack.Add( args ) // call argless stub invokeMethodExpr = Expression.Block(_returnType, Expression.Call( stack, miAddFrame, argsExpr), Expression.Assign( Expression.Field(stack, Fields.PhpStack_AllowProtectedCall), Expression.Constant(true, Types.Bool[0])), HandleResult( Expression.Call(method.ArglessStubMethod, target.Expression, stack), method.ArglessStubMethod.ReturnType)); restrictions = target.Restrictions; }
private void InvokeClrMethod(DynamicMetaObject target, DynamicMetaObject/*!*/[] args, DRoutineDesc method, out BindingRestrictions restrictions, out Expression invokeMethodExpr) { DynamicMetaObject scriptContext = args[0]; //Select arguments without scriptContext DynamicMetaObject[] realArgs = GetArgumentsRange(args, 1, RealMethodArgumentCount - 1); #if DLR_OVERLOAD_RESOLUTION // Convert arguments DynamicMetaObject[] realArgsConverted = Array.ConvertAll<DynamicMetaObject, DynamicMetaObject>(realArgs, (x) => { return x.ToPhpDynamicMetaObject(); }); //DLR overload resolution DynamicMetaObject res = PhpBinder.Instance.CallClrMethod(method.ClrMethod, target, realArgsConverted); restriction = res.Restriction; invokeMethodExpr = res.Rule; #else // Old overload resolution // TODO: in case of zero-parameters, we can call via ArgFull InvokeArgLess(target, scriptContext, method, realArgs, out restrictions, out invokeMethodExpr); #endif }
public virtual object __construct(ScriptContext context, object @class, object methodname) { string methodnameStr = PhpVariable.AsString(methodname); if (@class == null || string.IsNullOrEmpty(methodnameStr)) return false; this.dtype = null; this.method = null; DObject dobj; string str; if ((dobj = (@class as DObject)) != null) { this.dtype = dobj.TypeDesc; } else if ((str = PhpVariable.AsString(@class)) != null) { this.dtype = context.ResolveType(str, null, null, null, ResolveTypeFlags.UseAutoload); } if (this.dtype == null) return false; if (this.dtype.GetMethod(new Name(methodnameStr), dtype, out this.method) == GetMemberResult.NotFound) return false; return null; }
public virtual object __construct(ScriptContext context, object arg) { string name = PhpVariable.AsString(arg); if (!string.IsNullOrEmpty(name)) { routine = context.ResolveFunction(name, null, false); } else { PhpException.InvalidArgument("arg"); } return null; }