public void TypeRestrictionFalseForOtherType(object obj, Type type) { BindingRestrictions isType = BindingRestrictions.GetTypeRestriction(Expression.Constant(obj), type); Assert.False(Expression.Lambda <Func <bool> >(isType.ToExpression()).Compile()()); }
public override DynamicMetaObject BindInvoke(InvokeBinder binder, DynamicMetaObject[] args) { CodeContext context = PythonContext.GetPythonContext(binder).SharedContext; ArgumentMarshaller[] signature = GetArgumentMarshallers(args); BindingRestrictions restrictions = BindingRestrictions.GetTypeRestriction( Expression, Value.GetType() ).Merge( BindingRestrictions.GetExpressionRestriction( Expression.Call( typeof(ModuleOps).GetMethod("CheckFunctionId"), Expression.Convert(Expression, typeof(_CFuncPtr)), Expression.Constant(Value.Id) ) ) ); foreach (var arg in signature) { restrictions = restrictions.Merge(arg.GetRestrictions()); } int argCount = args.Length; if (Value._comInterfaceIndex != -1) { argCount--; } // need to verify we have the correct # of args if (Value._argtypes != null) { if (argCount < Value._argtypes.Count || (Value.CallingConvention != CallingConvention.Cdecl && argCount > Value._argtypes.Count)) { return(IncorrectArgCount(binder, restrictions, Value._argtypes.Count, argCount)); } } else { CFuncPtrType funcType = ((CFuncPtrType)Value.NativeType); if (funcType._argtypes != null && (argCount < funcType._argtypes.Length || (Value.CallingConvention != CallingConvention.Cdecl && argCount > funcType._argtypes.Length))) { return(IncorrectArgCount(binder, restrictions, funcType._argtypes.Length, argCount)); } } if (Value._comInterfaceIndex != -1 && args.Length == 0) { return(NoThisParam(binder, restrictions)); } Expression call = MakeCall(signature, GetNativeReturnType(), Value.Getrestype() == null, GetFunctionAddress(args)); List <Expression> block = new List <Expression>(); Expression res; if (call.Type != typeof(void)) { ParameterExpression tmp = Expression.Parameter(call.Type, "ret"); block.Add(Expression.Assign(tmp, call)); AddKeepAlives(signature, block); block.Add(tmp); res = Expression.Block(new[] { tmp }, block); } else { block.Add(call); AddKeepAlives(signature, block); res = Expression.Block(block); } res = AddReturnChecks(context, args, res); return(new DynamicMetaObject(Utils.Convert(res, typeof(object)), restrictions)); }
/// <summary> /// Returns a Restrictions object which includes our current restrictions merged /// with a restriction limiting our type /// </summary> private BindingRestrictions GetRestrictions() { return((Value == null && HasValue) ? BindingRestrictions.GetInstanceRestriction(Expression, null) : BindingRestrictions.GetTypeRestriction(Expression, LimitType)); }
public static BindingRestrictions ValueTypeRestriction(this DynamicMetaObject target) { return((target.HasValue && target.Value == null) ? BindingRestrictions.GetInstanceRestriction(target.Expression, null) : BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType)); }
public override DynamicMetaObject FallbackBinaryOperation( DynamicMetaObject target, DynamicMetaObject arg, DynamicMetaObject errorSuggestion) { // Defer if any object has no value so that we evaulate their // Expressions and nest a CallSite for the InvokeMember. if (!target.HasValue || !arg.HasValue) { return(Defer(target, arg)); } var restrictions = target.Restrictions.Merge(arg.Restrictions); if (target.Value == null) { restrictions = restrictions.Merge( BindingRestrictions.GetInstanceRestriction(target.Expression, null) ); } else { restrictions = restrictions.Merge(BindingRestrictions.GetTypeRestriction( target.Expression, target.LimitType)); } if (arg.Value == null) { restrictions = restrictions.Merge(BindingRestrictions.GetInstanceRestriction( arg.Expression, null)); } else { restrictions = restrictions.Merge(BindingRestrictions.GetTypeRestriction( arg.Expression, arg.LimitType)); } if (this.Operation == ExpressionType.Add) { if (target.LimitType == typeof(string) && arg.LimitType == typeof(string)) { return(new DynamicMetaObject( RuntimeHelpers.EnsureObjectResult(Expression.Call( typeof(string).GetMethod("Concat", new Type[] { typeof(string), typeof(string) }), Expression.Convert(target.Expression, target.LimitType), Expression.Convert(arg.Expression, arg.LimitType))), restrictions )); } if (target.LimitType == typeof(DateTime)) { return(new DynamicMetaObject( RuntimeHelpers.EnsureObjectResult(Expression.Call( typeof(BuiltInFunctions).GetMethod("DateAdd"), Expression.Constant("d"), Expression.Convert(arg.Expression, typeof(object)), target.Expression)), restrictions )); } else if (arg.LimitType == typeof(DateTime)) { return(new DynamicMetaObject( Expression.Call( typeof(BuiltInFunctions).GetMethod("DateAdd"), Expression.Constant("d"), Expression.Convert(target.Expression, typeof(object)), arg.Expression), restrictions )); } else if (!target.LimitType.IsPrimitive || !arg.LimitType.IsPrimitive) { DynamicMetaObject[] args = new DynamicMetaObject[] { target, arg }; List <MethodInfo> res = RuntimeHelpers.GetExtensionMethods("op_Addition", target, args); if (res.Count > 0) { MethodInfo mi = null; if (res.Count > 1) { //If more than one results found, attempt overload resolution mi = RuntimeHelpers.ResolveOverload(res, args); } else { mi = res[0]; } // restrictions and conversion must be done consistently. var callArgs = RuntimeHelpers.ConvertArguments(args, mi.GetParameters()); return(new DynamicMetaObject( RuntimeHelpers.EnsureObjectResult( Expression.Call(null, mi, callArgs) ), restrictions )); } } } if (target.LimitType.IsPrimitive && arg.LimitType.IsPrimitive) { Type targetType; Expression first; Expression second; if (target.LimitType == arg.LimitType || target.LimitType.IsAssignableFrom(arg.LimitType)) { targetType = target.LimitType; first = Expression.Convert(target.Expression, targetType); //if variable is object type, need to convert twice (unbox + convert) second = Expression.Convert( Expression.Convert(arg.Expression, arg.LimitType), targetType ); } else { targetType = arg.LimitType; first = Expression.Convert( Expression.Convert(target.Expression, target.LimitType), targetType ); second = Expression.Convert(arg.Expression, targetType); } return(new DynamicMetaObject( RuntimeHelpers.EnsureObjectResult( Expression.MakeBinary( this.Operation, first, second ) ), restrictions )); } else { DynamicMetaObject[] args = null; MethodInfo mi = null; mi = typeof(HelperFunctions).GetMethod("BinaryOp"); Expression op = Expression.Constant(this.Operation); DynamicMetaObject mop = new DynamicMetaObject(Expression.Constant(this.Operation), BindingRestrictions.Empty, this.Operation); args = new DynamicMetaObject[] { mop, target, arg }; // restrictions and conversion must be done consistently. var callArgs = RuntimeHelpers.ConvertArguments(args, mi.GetParameters()); return(new DynamicMetaObject( RuntimeHelpers.EnsureObjectResult( Expression.Call( mi, callArgs ) ), restrictions )); } }
public override DynamicMetaObject BindSetMember(SetMemberBinder binder, DynamicMetaObject value) { Schema.Property property; if (!_metadata.Schema.TryFindProperty(binder.Name, out property)) { return(base.BindSetMember(binder, value)); } var arguments = new List <Expression> { Expression.Constant(_metadata.PropertyIndices[property.Name]) }; MethodInfo setter = null; Type argumentType = null; switch (property.Type) { case Schema.PropertyType.Int: argumentType = typeof(long); if (property.IsNullable) { setter = GetSetMethod <long?>(dummyHandle.SetNullableInt64); } else if (property.IsPrimaryKey) { setter = GetSetMethod <long>(dummyHandle.SetInt64Unique); } else { setter = GetSetMethod <long>(dummyHandle.SetInt64); } break; case Schema.PropertyType.Bool: argumentType = typeof(bool); if (property.IsNullable) { setter = GetSetMethod <bool?>(dummyHandle.SetNullableBoolean); } else { setter = GetSetMethod <bool>(dummyHandle.SetBoolean); } break; case Schema.PropertyType.Float: argumentType = typeof(float); if (property.IsNullable) { setter = GetSetMethod <float?>(dummyHandle.SetNullableSingle); } else { setter = GetSetMethod <float>(dummyHandle.SetSingle); } break; case Schema.PropertyType.Double: argumentType = typeof(double); if (property.IsNullable) { setter = GetSetMethod <double?>(dummyHandle.SetNullableDouble); } else { setter = GetSetMethod <double>(dummyHandle.SetDouble); } break; case Schema.PropertyType.String: argumentType = typeof(string); if (property.IsPrimaryKey) { setter = GetSetMethod <string>(dummyHandle.SetStringUnique); } else { setter = GetSetMethod <string>(dummyHandle.SetString); } break; case Schema.PropertyType.Data: argumentType = typeof(byte[]); setter = GetSetMethod <byte[]>(dummyHandle.SetByteArray); break; case Schema.PropertyType.Date: argumentType = typeof(DateTimeOffset); if (property.IsNullable) { setter = GetSetMethod <DateTimeOffset?>(dummyHandle.SetNullableDateTimeOffset); } else { setter = GetSetMethod <DateTimeOffset>(dummyHandle.SetDateTimeOffset); } break; case Schema.PropertyType.Object: argumentType = typeof(RealmObject); arguments.Insert(0, Expression.Field(GetLimitedSelf(), RealmObjectRealmField)); setter = GetSetMethod <RealmObject>(dummyHandle.SetObject); break; } if (property.IsNullable && argumentType.GetTypeInfo().IsValueType) { argumentType = typeof(Nullable <>).MakeGenericType(argumentType); } var valueExpression = value.Expression; if (valueExpression.Type != argumentType) { valueExpression = Expression.Convert(valueExpression, argumentType); } arguments.Add(valueExpression); var expression = Expression.Block(Expression.Call(Expression.Field(GetLimitedSelf(), RealmObjectObjectHandleField), setter, arguments), Expression.Default(binder.ReturnType)); var argumentShouldBeDynamicRealmObject = BindingRestrictions.GetTypeRestriction(Expression, typeof(DynamicRealmObject)); var argumentShouldBeInTheSameRealm = BindingRestrictions.GetInstanceRestriction(Expression.Field(GetLimitedSelf(), RealmObjectRealmField), _realm); return(new DynamicMetaObject(expression, argumentShouldBeDynamicRealmObject.Merge(argumentShouldBeInTheSameRealm))); }
/// <summary> /// Access <paramref name="target"/> as object instance. /// </summary> /// <param name="target">Given target.</param> /// <param name="instance">Resolved instance with restrictions.</param> /// <returns>Whether <paramref name="target"/> contains an object instance.</returns> /// <remarks>Necessary restriction are already resolved within returned <paramref name="instance"/>.</remarks> public static bool TryTargetAsObject(DynamicMetaObject target, out DynamicMetaObject instance) { var expr = target.Expression; var value = target.Value; var restrictions = target.Restrictions; if (value == null) { instance = new DynamicMetaObject( expr, restrictions.Merge(BindingRestrictions.GetExpressionRestriction(Expression.ReferenceEqual(expr, Expression.Constant(null)))), null); return(false); } // dereference PhpAlias first: if (expr.Type == typeof(PhpAlias)) { // PhpAlias.Value expr = Expression.Field(expr, Cache.PhpAlias.Value); value = ((PhpAlias)value).Value; // return(TryTargetAsObject( new DynamicMetaObject(expr, restrictions, value), out instance)); } if (value is PhpAlias alias) { // PhpAlias is provided but typed as System.Object // create restriction and retry with properly typed {expr:PhpAlias} expr = Expression.Convert(expr, typeof(PhpAlias)); return(TryTargetAsObject( new DynamicMetaObject(expr, restrictions.Merge(BindingRestrictions.GetTypeRestriction(expr, typeof(PhpAlias))), alias), out instance)); } // unwrap PhpValue if (expr.Type == typeof(PhpValue)) { // PhpValue.Object expr = Expression.Property(expr, Cache.Properties.PhpValue_Object); value = ((PhpValue)value).Object; return(TryTargetAsObject( new DynamicMetaObject(expr, restrictions, value), out instance)); } // well-known non-objects: Type nonObjectType = null; if (value is PhpResource) { nonObjectType = typeof(PhpResource); } if (value is PhpArray) { nonObjectType = typeof(PhpArray); } if (value is PhpString.Blob) { nonObjectType = typeof(PhpString.Blob); } if (nonObjectType != null) { instance = new DynamicMetaObject( expr, restrictions.Merge(BindingRestrictions.GetExpressionRestriction(Expression.TypeIs(expr, nonObjectType))), // PhpValue.Object is T (including any derived class) value); return(false); } // var lt = target.Expression.Type; if (!lt.IsValueType && !lt.IsSealed && !typeof(PhpArray).IsAssignableFrom(lt) && !typeof(PhpResource).IsAssignableFrom(lt)) { // we need to set the type restriction restrictions = restrictions.Merge(BindingRestrictions.GetTypeRestriction(expr, value.GetType())); } // instance = new DynamicMetaObject(expr, restrictions, value); return(!( value is string || value is bool || value is int || value is long || value is double || value is char || value is uint || value is ulong || value is PhpString)); }
public override DynamicMetaObject BindGetMember(GetMemberBinder binder) { var ds = (DynamicStruct)this.Value; var dsP = Parameter(typeof(DynamicStruct), "ds"); var structExp = Property(dsP, "Struct"); var node = ds.SchemaNode.Node; Expression valueExp; switch (node.which) { case Node.Union.@struct: foreach (var field in [email protected]) { if (field.name.ToString() != binder.Name) { continue; } if (field.Is(out Field.groupGroup group)) { var newSchemaNode = ds.SchemaNode.Container[group.typeId]; valueExp = New( DynamicStructConstructor, Constant(newSchemaNode), structExp); } else if (field.Is(out Field.slotGroup slot)) { var dv = slot.defaultValue; string readMethod; object defaultValue; System.Type type; switch (slot.type.which) { case Type.Union.@void: throw new NotSupportedException(); case Type.Union.@bool: readMethod = "ReadBool"; defaultValue = dv.@bool; type = typeof(bool); break; case Type.Union.int8: readMethod = "ReadInt8"; defaultValue = dv.int8; type = typeof(sbyte); break; case Type.Union.int16: readMethod = "ReadInt16"; defaultValue = dv.int16; type = typeof(short); break; case Type.Union.int32: readMethod = "ReadInt32"; defaultValue = dv.int32; type = typeof(int); break; case Type.Union.int64: readMethod = "ReadInt64"; defaultValue = dv.int64; type = typeof(long); break; case Type.Union.uint8: readMethod = "ReadUInt8"; defaultValue = dv.uint8; type = typeof(byte); break; case Type.Union.uint16: readMethod = "ReadUInt16"; defaultValue = dv.uint16; type = typeof(ushort); break; case Type.Union.uint32: readMethod = "ReadUInt32"; defaultValue = dv.uint32; type = typeof(uint); break; case Type.Union.uint64: readMethod = "ReadUInt64"; defaultValue = dv.uint64; type = typeof(ulong); break; case Type.Union.float32: readMethod = "ReadFloat32"; defaultValue = dv.float32; type = typeof(float); break; case Type.Union.float64: readMethod = "ReadFloat64"; defaultValue = dv.float64; type = typeof(double); break; case Type.Union.@enum: readMethod = "ReadUInt16"; defaultValue = dv.uint16; type = typeof(ushort); // TODO: should be an enum type; dynamically generate one? break; case Type.Union.text: case Type.Union.data: case Type.Union.list: case Type.Union.@struct: case Type.Union.@interface: case Type.Union.anyPointer: readMethod = "DereferencePointer"; defaultValue = null; type = null; break; default: throw new NotSupportedException(); } if (readMethod.StartsWith("Read")) { valueExp = Call( structExp, typeof(Struct).GetTypeInfo().GetDeclaredMethod(readMethod), Constant((int)slot.offset), Constant(defaultValue)); } else if (slot.type.Is(out Type.structGroup @struct)) { var newSchemaNode = ds.SchemaNode.Container[@struct.typeId]; valueExp = New( DynamicStructConstructor, Constant(newSchemaNode), Call( structExp, typeof(Struct).GetTypeInfo().GetDeclaredMethod("DereferencePointer").MakeGenericMethod(typeof(Struct)), Constant((int)slot.offset))); } else { throw new NotImplementedException(); } } else { throw new NotSupportedException(); } var target = Block( new[] { dsP }, Assign(dsP, Convert(this.Expression, typeof(DynamicStruct))), Condition( // if 'this' refers to a new with the same schema... Equal(Property(dsP, "SchemaNode"), Constant(ds.SchemaNode)), // then: perform the get-member Convert( valueExp, binder.ReturnType), // else: try to look up the member under the other schema binder.GetUpdateExpression(binder.ReturnType))); return(new DynamicMetaObject( target, BindingRestrictions.GetTypeRestriction(this.Expression, typeof(DynamicStruct)))); } return(binder.FallbackGetMember(this)); case Node.Union.@enum: break; case Node.Union.@interface: break; case Node.Union.@const: break; case Node.Union.file: case Node.Union.annotation: default: throw new NotSupportedException(); } throw new NotImplementedException(); }
public override DynamicMetaObject BindConvert(ConvertBinder binder) { Expression convertExpression; if (binder.Type.IsAssignableFrom(LimitType)) { convertExpression = Expression.Convert(Expression, binder.Type); } else if (binder.Type == typeof(InternalHandle) && Value is IHandleBased) { Func <object, InternalHandle> toInertnalHandleConversionDelegate = _GetInternalHandleFromObject; convertExpression = Expression.Convert(Expression, typeof(InternalHandle), toInertnalHandleConversionDelegate.Method); } else if (binder.Type == typeof(Handle) && Value is IHandleBased) { Func <object, Handle> toInertnalHandleConversionDelegate = _GetHandleFromObject; convertExpression = Expression.Convert(Expression, typeof(Handle), toInertnalHandleConversionDelegate.Method); } else if (typeof(V8NativeObject).IsAssignableFrom(binder.Type) && Value is IHandleBased) { Func <object, V8NativeObject> getUnderlyingObject = _GetUnderlyingObject; convertExpression = Expression.Convert(Expression.Convert(Expression, typeof(V8NativeObject), getUnderlyingObject.Method), binder.Type); } else { MethodInfo conversionMethodInfo; if (Value is IHandleBased) // (if this is a handle, read the 'Value' property, which returns all values as objects. { var valueMemberInfo = typeof(InternalHandle).GetProperty(nameof(InternalHandle.Value)); Func <object, InternalHandle> toInertnalHandleConversionDelegate = _GetInternalHandleFromObject; var valueMemberExpr = Expression.MakeMemberAccess(Expression.Convert(Expression, typeof(InternalHandle), toInertnalHandleConversionDelegate.Method), valueMemberInfo); convertExpression = Expression.Convert(valueMemberExpr, binder.Type); } else { if (binder.Type == typeof(InternalHandle)) { conversionMethodInfo = ((Func <object, InternalHandle>)_GetInternalHandleFromObject).Method; } else if (binder.Type == typeof(Handle)) { conversionMethodInfo = ((Func <object, Handle>)_GetHandleFromObject).Method; } else { conversionMethodInfo = null; } if (conversionMethodInfo != null) { convertExpression = Expression.Convert(Expression, binder.Type, conversionMethodInfo); } else { convertExpression = Expression.Convert(Expression, binder.Type); } } } BindingRestrictions restrictions = Restrictions.Merge(BindingRestrictions.GetTypeRestriction(convertExpression, binder.Type)); return(new DynamicMetaObject(convertExpression, Restrictions)); }
private BindingRestrictions GetRestrictions() { return(BindingRestrictions.GetTypeRestriction(Expression, Value.GetType())); }
static BindingRestrictions CreateRestrictionsOnTarget(DynamicMetaObject arg) { return(arg.HasValue && arg.Value == null? BindingRestrictions.GetInstanceRestriction(arg.Expression, null) : BindingRestrictions.GetTypeRestriction(arg.Expression, arg.LimitType)); }
/// <summary> /// This method binds rules for PhpMethod /// </summary> private void InvokePhpMethod(DynamicMetaObject /*!*/ target, DynamicMetaObject[] /*!!*/ args, /*object targetObj,*/ PhpRoutine /*!*/ routine, out BindingRestrictions restrictions, out Expression invokeMethodExpr) { Debug.Assert(target != null && target.Value != null); Debug.Assert(!(target.Value is IClrValue), "PhpRoutine should not be declared on CLR value type!"); /*if (target.Value is PhpObject) * { * // Restriction: typeof(target) == |target.TypeDesc.RealType| * var targetPhpObj = (PhpObject)target.Value; * Debug.Assert(targetPhpObj.TypeDesc.RealType == target.LimitType); * Debug.Assert(target.Value.GetType() == target.LimitType); * restrictions = BindingRestrictions.GetTypeRestriction(target.Expression, targetPhpObj.TypeDesc.RealType); * } * else*/ Debug.Assert(typeof(ClrObject).IsSealed); // just to ensure following condition is correct if (target.Value.GetType() == typeof(ClrObject)) { target = new ClrDynamicMetaObject(target); // unwrap the real object, get restrictions restrictions = target.Restrictions; } else { Debug.Assert(target.Value.GetType() == target.LimitType); // just for sure Debug.Assert(!(target.Value is PhpObject) || ((PhpObject)target.Value).TypeDesc.RealType == target.LimitType); restrictions = BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType); } BindingRestrictions argumentsRestrictions; Expression[] arguments; if (routine.Name != PHP.Core.Reflection.DObject.SpecialMethodNames.Call) { args = GetArgumentsRange(args, 0, RealMethodArgumentCount);// This can't be done when _call method is invoked //Check if method has ArgAware attribute if ((routine.Properties & RoutineProperties.IsArgsAware) != 0 || routine.IsStatic)// this is because of hack in PHP.Library.XML library static methods that can be also called like instance methods { DynamicMetaObject scriptContext = args[0]; //Select arguments without scriptContext DynamicMetaObject[] realArgs = GetArgumentsRange(args, 1, RealMethodArgumentCount - 1); InvokeArgLess(target, scriptContext, routine.RoutineDesc, realArgs, out argumentsRestrictions, out invokeMethodExpr); restrictions = restrictions.Merge(argumentsRestrictions); return; } arguments = routine.PrepareArguments(args, _genericParamsCount, _paramsCount, out argumentsRestrictions); restrictions = restrictions.Merge(argumentsRestrictions); } else { arguments = BinderHelper.PackToExpressions(args); } //((PhpObject)target)) var realObjEx = Expression.Convert(target.Expression, routine.ArgFullInfo.DeclaringType);//targetObj.TypeDesc.RealType); //ArgFull( ((PhpObject)target), ScriptContext, args, ... ) invokeMethodExpr = Expression.Call(BinderHelper.WrapInstanceMethodCall(routine.ArgFullInfo), BinderHelper.CombineArguments(realObjEx, arguments)); invokeMethodExpr = ReturnArgumentHelpers.ReturnValueConversion(routine.ArgFullInfo, invokeMethodExpr); invokeMethodExpr = HandleResult(invokeMethodExpr, routine.ArgFullInfo.ReturnType, false); }
protected override DynamicMetaObject /*!*/ FallbackInvokeMember(DynamicMetaObject target /*!*/, DynamicMetaObject /*!*/[] /*!*/ args) { Expression invokeMethodExpr; DObject obj = target.Value as DObject;// target.Value can be something else which isn't DObject ? WrappedClrDynamicMetaObject wrappedTarget = null; bool invokeCallMethod = false; // Restrictions BindingRestrictions restrictions; BindingRestrictions classContextRestrictions = BindingRestrictions.Empty; BindingRestrictions defaultRestrictions = BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType); DTypeDesc classContext = this._classContext; if (!ClassContextIsKnown)//ClassContext wasn't supplied during creation of binder => put it into restriction { Debug.Assert(args.Length > RealMethodArgumentCount, "Not enough arguments!"); DynamicMetaObject dmoRuntimeClassContext = GetRuntimeClassContext(args); Debug.Assert(dmoRuntimeClassContext.Value == null || Types.DTypeDesc[0].IsAssignableFrom(dmoRuntimeClassContext.LimitType), "Wrong class context type!"); classContext = (DTypeDesc)dmoRuntimeClassContext.Value; Debug.Assert(classContext == null || !classContext.IsUnknown, "Class context should be known at run time!"); classContextRestrictions = BindingRestrictions.GetInstanceRestriction(dmoRuntimeClassContext.Expression, classContext); defaultRestrictions = defaultRestrictions.Merge(classContextRestrictions); } if (obj == null) { if (target.Value != null && Configuration.Application.Compiler.ClrSemantics) { // TODO: some normalizing conversions (PhpString, PhpBytes -> string): target = new WrappedClrDynamicMetaObject(target); obj = target.Value as DObject; wrappedTarget = target as WrappedClrDynamicMetaObject; Debug.Assert(obj != null); } else { //defaultRestrictions = defaultRestrictions.Merge(BindingRestrictions.GetTypeRestriction if (target.Value == null) { defaultRestrictions = BindingRestrictions.GetInstanceRestriction(target.Expression, null); } return(DoAndReturnDefault( BinderHelper.ThrowError("method_called_on_non_object", ActualMethodName), defaultRestrictions)); } } // obtain the appropriate method table DTypeDesc type_desc = obj.TypeDesc; // perform method lookup DRoutineDesc method; GetMemberResult result = type_desc.GetMethod(new Name(ActualMethodName), classContext, out method); //PhpStack stack = context.Stack; if (result == GetMemberResult.NotFound) { if ((result = type_desc.GetMethod(DObject.SpecialMethodNames.Call, classContext, out method)) == GetMemberResult.NotFound) { return(DoAndReturnDefault( Expression.Call(Methods.PhpException.UndefinedMethodCalled, Expression.Constant(obj.TypeName), Expression.Constant(ActualMethodName)), defaultRestrictions )); // TODO: alter restrictions } else { invokeCallMethod = true; } } // throw an error if the method was found but the caller is not allowed to call it due to its visibility if (result == GetMemberResult.BadVisibility) { return(DoAndReturnDefault( BinderHelper.ThrowVisibilityError(method, classContext), defaultRestrictions)); } if (invokeCallMethod) { InvokeCallMethod(target, args, obj, method, out restrictions, out invokeMethodExpr); return(new DynamicMetaObject(invokeMethodExpr, restrictions.Merge(classContextRestrictions))); } else { // we are invoking the method // PhpRoutine (function or method) if (method.Member is PhpRoutine) { InvokePhpMethod(target, args, method.PhpRoutine, out restrictions, out invokeMethodExpr); return(new DynamicMetaObject(invokeMethodExpr, restrictions.Merge(classContextRestrictions))); } // ClrMethod else if (method.Member is ClrMethod) { var targetwrapper = (target.LimitType == typeof(ClrObject)) ? (DynamicMetaObject) new ClrDynamicMetaObject(target) : // ((ClrObject)target).RealType restriction (DynamicMetaObject) new ClrValueDynamicMetaObject(target); // simple type restriction, IClrValue<T> or any .NET class inheriting PhpObject InvokeClrMethod(targetwrapper, args, method, out restrictions, out invokeMethodExpr); if (wrappedTarget != null) { return(new DynamicMetaObject(Expression.Block(wrappedTarget.WrapIt(), invokeMethodExpr), wrappedTarget.Restrictions.Merge(classContextRestrictions))); } return(new DynamicMetaObject(invokeMethodExpr, restrictions.Merge(classContextRestrictions))); } } throw new NotImplementedException(); }
private BindingRestrictions GetRestrictions() { return(BindingRestrictions.GetTypeRestriction(Expression, typeof(T))); }
private BindingRestrictions ComTypeLibInfoRestrictions(params DynamicMetaObject[] args) { return(BindingRestrictions.Combine(args).Merge(BindingRestrictions.GetTypeRestriction(Expression, typeof(ComTypeLibInfo)))); }
public override DynamicMetaObject FallbackSetMember( DynamicMetaObject targetMO, DynamicMetaObject value, DynamicMetaObject errorSuggestion) { #if !NETSTANDARD // First try COM binding. DynamicMetaObject result; if (ComBinder.TryBindSetMember(this, targetMO, value, out result)) { return(result); } #endif // Defer if any object has no value so that we evaulate their // Expressions and nest a CallSite for the InvokeMember. if (!targetMO.HasValue) { return(Defer(targetMO)); } // Find our own binding. var flags = BindingFlags.IgnoreCase | BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public; var members = targetMO.LimitType.GetMember(this.Name, flags); if (members.Length == 1) { MemberInfo mem = members[0]; Expression val; // Should check for member domain type being Type and value being // TypeModel, similar to ConvertArguments, and building an // expression like GetRuntimeTypeMoFromModel. if (mem.MemberType == MemberTypes.Property) { val = Expression.Convert(value.Expression, ((PropertyInfo)mem).PropertyType); } else if (mem.MemberType == MemberTypes.Field) { val = Expression.Convert(value.Expression, ((FieldInfo)mem).FieldType); } else { return(errorSuggestion ?? RuntimeHelpers.CreateThrow( targetMO, null, BindingRestrictions.GetTypeRestriction( targetMO.Expression, targetMO.LimitType), typeof(InvalidOperationException), "Sympl only supports setting Properties and " + "fields at this time.")); } return(new DynamicMetaObject( // Assign returns the stored value, so we're good for Sympl. RuntimeHelpers.EnsureObjectResult( Expression.Assign( Expression.MakeMemberAccess( Expression.Convert(targetMO.Expression, members[0].DeclaringType), members[0]), val)), // Don't need restriction test for name since this // rule is only used where binder is used, which is // only used in sites with this binder.Name. BindingRestrictions.GetTypeRestriction(targetMO.Expression, targetMO.LimitType))); } else { return(errorSuggestion ?? RuntimeHelpers.CreateThrow( targetMO, null, BindingRestrictions.GetTypeRestriction(targetMO.Expression, targetMO.LimitType), typeof(MissingMemberException), "IDynObj member name conflict.")); } }
public override DynamicMetaObject BindGetMember(GetMemberBinder binder) { var invoke = Expression.Call(GetDynamicMemberMethodInfo, this.Expression, Expression.Constant(binder.Name)); return(new DynamicMetaObject(invoke, BindingRestrictions.GetTypeRestriction(this.Expression, this.LimitType))); }
private DynamicMetaObject /*!*/ FallbackInvokeMember(DynamicMetaObject target /*!*/, DynamicMetaObject /*!*/[] /*!*/ args) { // determine run time values and additional restrictions: DTypeDesc classContext = this._classContext; string fieldName = this._fieldName; BindingRestrictions restrictions = BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType); //target.Restrictions; int currentArg = 0; if (!ClassContextIsKnown) { Debug.Assert(args.Length > currentArg, "Not enough arguments!"); Debug.Assert(args[currentArg].Value == null || Types.DTypeDesc[0].IsAssignableFrom(args[currentArg].LimitType), "Wrong class context type!"); classContext = (DTypeDesc)args[currentArg].Value; Debug.Assert(classContext == null || !classContext.IsUnknown, "Class context should be known at run time!"); restrictions = restrictions.Merge(BindingRestrictions.GetInstanceRestriction(args[currentArg].Expression, classContext)); currentArg++; } if (IsIndirect) { Debug.Assert(args.Length > currentArg, "Not enough arguments!"); Debug.Assert(Types.String[0].IsAssignableFrom(args[currentArg].LimitType), "Wrong field name type!"); fieldName = (string)args[currentArg].Value; restrictions = restrictions.Merge( BindingRestrictions.GetExpressionRestriction( Expression.Equal( args[currentArg].Expression, Expression.Constant(fieldName, Types.String[0])))); currentArg++; } // ////Debug.Assert(!(var is PhpReference) && name != null); Debug.Assert(target.HasValue && target.LimitType != Types.PhpReference[0], "Target should not be PhpReference!"); ////if (ReferenceEquals(obj, ScriptContext.SetterChainSingletonObject)) ////{ //// ScriptContext.CurrentContext.AbortSetterChain(false); //// return new PhpReference(); ////} if (WantReference && ReferenceEquals(target.Value, ScriptContext.SetterChainSingletonObject)) { // GetObjectPropertyRef: Func <PhpReference> abortSetterChain = () => { ScriptContext.CurrentContext.AbortSetterChain(false); return(new PhpReference()); }; return(new DynamicMetaObject( Expression.Call(abortSetterChain.Method), BindingRestrictions.GetInstanceRestriction(target.Expression, ScriptContext.SetterChainSingletonObject) )); } DObject obj; ////// a property of a DObject: if ((obj = target.Value as DObject) != null) { if (obj is ClrObject /*|| obj is IClrValue // IClrValue -> ClrValue<T> -> already in restriction */) { // ((DObject)target).RealType == <obj>.RealType restrictions = restrictions.Merge( BindingRestrictions.GetInstanceRestriction( Expression.Property(Expression.Convert(target.Expression, Types.DObject[0]), Properties.DObject_RealType), obj.RealType)); } //// return GetObjectProperty(obj, name, caller, quiet); DPropertyDesc property; GetMemberResult result = obj.TypeDesc.GetInstanceProperty(new VariableName(fieldName), classContext, out property); switch (result) { case GetMemberResult.OK: ////object value = property.Get(this); ////PhpReference reference = value as PhpReference; if (property.Member is PhpField || property.Member is PhpVisibleProperty) { var realType = property.DeclaringType.RealType; FieldInfo realField = (property.Member is PhpField) ? property.PhpField.RealField : null; PropertyInfo realProperty = (property.Member is PhpVisibleProperty) ? ((PhpVisibleProperty)property.Member).RealProperty : null; Debug.Assert(realField != null ^ realProperty != null); MemberExpression getter = null; if (realField != null) { getter = Expression.Field(Expression.Convert(target.Expression, realType), realField); } else if (realProperty != null) { getter = Expression.Property(Expression.Convert(target.Expression, realType), realProperty); } if (Types.PhpReference[0].IsAssignableFrom(getter.Type)) { var reference = Expression.Variable(Types.PhpReference[0]); var assignment = Expression.Assign(reference, getter); if (WantReference) { ////value = property.Get(this); ////reference = value as PhpReference; var returnLabel = Expression.Label(this._returnType); ////if (reference != null && reference.IsSet) ////{ //// reference.IsAliased = true; //// return reference; ////} var isset = Expression.IfThen( Expression.Property(assignment, Properties.PhpReference_IsSet), Expression.Block( Expression.Assign(Expression.Property(reference, Properties.PhpReference_IsAliased), Expression.Constant(true)), Expression.Return(returnLabel, reference))); ////// the CT property has been unset -> try to invoke __get ////PhpReference get_ref = InvokeGetterRef(name, caller, out getter_exists); ////if (getter_exists) return (get_ref == null ? new PhpReference() : get_ref); ////if (reference == null) ////{ //// reference = new PhpReference(value); //// property.Set(this, reference); ////} ////else ////{ //// reference.IsAliased = true; //// reference.IsSet = true; ////} Func <DObject, string, DTypeDesc, PhpReference, PhpReference> notsetOperation = (self, name, caller, refrnc) => { bool getter_exists; // the CT property has been unset -> try to invoke __get PhpReference get_ref = self.InvokeGetterRef(name, caller, out getter_exists); if (getter_exists) { return(get_ref ?? new PhpReference()); } Debug.Assert(refrnc != null); refrnc.IsAliased = true; refrnc.IsSet = true; return(refrnc); }; ////return reference; return(new DynamicMetaObject( Expression.Block(this._returnType, new[] { reference }, new Expression[] { isset, Expression.Label(returnLabel, Expression.Call(null, notsetOperation.Method, Expression.Convert(target.Expression, Types.DObject[0]), Expression.Constant(fieldName), Expression.Constant(classContext, Types.DTypeDesc[0]), reference)) }), restrictions)); } else { ////if (reference != null && !reference.IsSet) ////{ //// // the property is CT but has been unset //// if (issetSemantics) //// { //// bool handled; //// return PropertyIssetHandler(name, caller, out handled); //// } //// else return GetRuntimeField(name, caller); ////} ////else return value; Func <DObject, string, DTypeDesc, object> notsetOperation; if (_issetSemantics) { notsetOperation = (self, name, caller) => { return(PhpVariable.Dereference(self.GetRuntimeField(name, caller))); } } ; else { notsetOperation = (self, name, caller) => { bool handled; return(PhpVariable.Dereference(self.PropertyIssetHandler(name, caller, out handled))); } }; var value = Expression.Block(this._returnType, new[] { reference }, Expression.Condition( Expression.Property(assignment, Properties.PhpReference_IsSet), Expression.Field(reference, Fields.PhpReference_Value), Expression.Call(null, notsetOperation.Method, Expression.Convert(target.Expression, Types.DObject[0]), Expression.Constant(fieldName), Expression.Constant(classContext, Types.DTypeDesc[0])) )); return(new DynamicMetaObject(value, restrictions)); } } else { if (WantReference) { return(new DynamicMetaObject( Expression.New(Constructors.PhpReference_Object, Expression.Convert(getter, Types.Object[0])), restrictions)); } else { return(new DynamicMetaObject( Expression.Call(Methods.PhpVariable.Dereference, Expression.Convert(getter, Types.Object[0])), restrictions)); } } } else if (property.Member is ClrProperty) { var realType = property.DeclaringType.RealType; var realProperty = property.ClrProperty.RealProperty; // (target.{RealObject|realValue}).<realProperty> Expression value = Expression.Convert( BinderHelper.ClrObjectWrapDynamic( Expression.Property( BinderHelper.ClrRealObject(target, realType), realProperty)), Types.Object[0]); if (WantReference) { value = BinderHelper.MakePhpReference(value); } return(new DynamicMetaObject(value, restrictions)); } else if (property.Member is ClrField) { var realType = property.DeclaringType.RealType; var realField = property.ClrField.FieldInfo; // (target.{RealObject|realValue}).<realField> Expression value = Expression.Convert( BinderHelper.ClrObjectWrapDynamic( Expression.Field( BinderHelper.ClrRealObject(target, realType), realField)), Types.Object[0]); if (WantReference) { value = BinderHelper.MakePhpReference(value); } return(new DynamicMetaObject(value, restrictions)); } else if (property.Member is ClrEvent) { var clrEvent = (ClrEvent)property.Member; var realType = property.DeclaringType.RealType; // emit stub that Wraps event as [ ClrEventObject<handlerType>.Wrap(<SC>, <event name>, <addMethod>, <removeMethod>) ] var stub = new System.Reflection.Emit.DynamicMethod( string.Format("event<{0}>", fieldName), Types.DObject[0], new[] { realType }, realType); var il = new ILEmitter(stub); clrEvent.EmitGetEventObject( il, new Place(null, Properties.ScriptContext_CurrentContext), new IndexedPlace(PlaceHolder.Argument, 0), false); il.Emit(System.Reflection.Emit.OpCodes.Ret); Expression value = Expression.Call(stub, BinderHelper.ClrRealObject(target, realType)); if (WantReference) { value = BinderHelper.MakePhpReference(value); } return(new DynamicMetaObject(value, restrictions)); } else { throw new NotImplementedException(); } case GetMemberResult.NotFound: if (WantReference) { Func <DObject, string, DTypeDesc, PhpReference> op = (self, name, caller) => { PhpReference reference; bool getter_exists; // search in RT fields if (self.RuntimeFields != null && self.RuntimeFields.ContainsKey(name)) { var namekey = new IntStringKey(name); return(self.RuntimeFields.table._ensure_item_ref(ref namekey, self.RuntimeFields)); } // property is not present -> try to invoke __get reference = self.InvokeGetterRef(name, caller, out getter_exists); if (getter_exists) { return((reference == null) ? new PhpReference() : reference); } // (no notice/warning/error thrown by PHP) // add the field reference = new PhpReference(); if (self.RuntimeFields == null) { self.RuntimeFields = new PhpArray(); } self.RuntimeFields[name] = reference; return(reference); }; return(new DynamicMetaObject( Expression.Call(null, op.Method, Expression.Convert(target.Expression, Types.DObject[0]), Expression.Constant(fieldName), Expression.Constant(classContext, Types.DTypeDesc[0])), restrictions)); } else { ////if (issetSemantics) ////{ //// OrderedHashtable<string>.Element element; //// if (RuntimeFields != null && (element = RuntimeFields.GetElement(name)) != null) //// { //// return element.Value; //// } //// else //// { //// bool handled; //// return PropertyIssetHandler(name, caller, out handled); //// } ////} ////else return GetRuntimeField(name, caller); if (_issetSemantics) { Func <DObject, string, DTypeDesc, object> notsetOperation = (self, name, caller) => { if (self.RuntimeFields != null) { object value; if (self.RuntimeFields.TryGetValue(name, out value)) { return(value); } } bool handled; return(self.PropertyIssetHandler(name, caller, out handled)); }; return(new DynamicMetaObject( Expression.Call(Methods.PhpVariable.Dereference, Expression.Call(null, notsetOperation.Method, Expression.Convert(target.Expression, Types.DObject[0]), Expression.Constant(fieldName), Expression.Constant(classContext, Types.DTypeDesc[0]))), restrictions)); } else { return(new DynamicMetaObject( Expression.Call( Methods.PhpVariable.Dereference, Expression.Call( Expression.Convert(target.Expression, Types.DObject[0]), Methods.DObject_GetRuntimeField, Expression.Constant(fieldName), Expression.Constant(classContext, Types.DTypeDesc[0]))), restrictions)); }; } case GetMemberResult.BadVisibility: { ////PhpException.PropertyNotAccessible( //// property.DeclaringType.MakeFullName(), //// name.ToString(), //// (caller == null ? String.Empty : caller.MakeFullName()), //// property.IsProtected); string stringResourceKey = property.IsProtected ? "protected_property_accessed" : "private_property_accessed"; return(new DynamicMetaObject( Expression.Block(this._returnType, Expression.Call(null, Methods.PhpException.Throw, Expression.Constant(PhpError.Error, Types.PhpError_String[0]), Expression.Constant(CoreResources.GetString(stringResourceKey, property.DeclaringType.MakeFullName(), fieldName, (classContext == null ? String.Empty : classContext.MakeFullName())))), WantReference ? (Expression)Expression.New(Constructors.PhpReference_Void) : Expression.Constant(null) ), restrictions)); } } } ////// warnings: ////if (!quiet) // not in isset() operator only ////{ if (!_issetSemantics) { //// if (PhpVariable.IsEmpty(var)) //// // empty: //// PhpException.Throw(PhpError.Notice, CoreResources.GetString("empty_used_as_object")); //// else //// // PhpArray, string, scalar type: //// PhpException.VariableMisusedAsObject(var, false); Action <object> error = (var) => { if (PhpVariable.IsEmpty(var)) { // empty: PhpException.Throw(PhpError.Notice, CoreResources.GetString("empty_used_as_object")); } else { // PhpArray, string, scalar type: PhpException.VariableMisusedAsObject(var, false); } }; return(new DynamicMetaObject( Expression.Block(this._returnType, Expression.Call(error.Method, target.Expression), WantReference ? (Expression)Expression.New(Constructors.PhpReference_Void) : Expression.Constant(null)), (target.HasValue && target.Value == null) ? BindingRestrictions.GetInstanceRestriction(target.Expression, null) : BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType))); } ////} ////// property does not exist ////return null; return(new DynamicMetaObject( Expression.Constant(null), (target.HasValue && target.Value == null) ? BindingRestrictions.GetInstanceRestriction(target.Expression, null) : BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType))); }
public override DynamicMetaObject BindGetMember(GetMemberBinder binder) { Schema.Property property; if (!_metadata.Schema.TryFindProperty(binder.Name, out property)) { return(base.BindGetMember(binder)); } var arguments = new List <Expression> { Expression.Constant(_metadata.PropertyIndices[property.Name]) }; MethodInfo getter = null; switch (property.Type) { case Schema.PropertyType.Int: if (property.IsNullable) { getter = GetGetMethod(dummyHandle.GetNullableInt64); } else { getter = GetGetMethod(dummyHandle.GetInt64); } break; case Schema.PropertyType.Bool: if (property.IsNullable) { getter = GetGetMethod(dummyHandle.GetNullableBoolean); } else { getter = GetGetMethod(dummyHandle.GetBoolean); } break; case Schema.PropertyType.Float: if (property.IsNullable) { getter = GetGetMethod(dummyHandle.GetNullableSingle); } else { getter = GetGetMethod(dummyHandle.GetSingle); } break; case Schema.PropertyType.Double: if (property.IsNullable) { getter = GetGetMethod(dummyHandle.GetNullableDouble); } else { getter = GetGetMethod(dummyHandle.GetDouble); } break; case Schema.PropertyType.String: getter = GetGetMethod(dummyHandle.GetString); break; case Schema.PropertyType.Data: getter = GetGetMethod(dummyHandle.GetByteArray); break; case Schema.PropertyType.Date: if (property.IsNullable) { getter = GetGetMethod(dummyHandle.GetNullableDateTimeOffset); } else { getter = GetGetMethod(dummyHandle.GetDateTimeOffset); } break; case Schema.PropertyType.Object: arguments.Insert(0, Expression.Field(GetLimitedSelf(), RealmObjectRealmField)); arguments.Add(Expression.Constant(property.ObjectType)); getter = GetGetMethod(dummyHandle.GetObject <DynamicRealmObject>); break; case Schema.PropertyType.Array: arguments.Insert(0, Expression.Field(GetLimitedSelf(), RealmObjectRealmField)); arguments.Add(Expression.Constant(property.ObjectType)); getter = GetGetMethod(dummyHandle.GetList <DynamicRealmObject>); break; case Schema.PropertyType.LinkingObjects: getter = GetGetMethod(dummyHandle.GetBacklinks); break; } var self = GetLimitedSelf(); var instance = Expression.Field(self, RealmObjectObjectHandleField); Expression expression = Expression.Call(instance, getter, arguments); if (property.Type == Schema.PropertyType.LinkingObjects) { expression = Expression.Call(self, RealmObjectGetBacklinksForHandleMethod, Expression.Constant(binder.Name), expression); } if (binder.ReturnType != expression.Type) { expression = Expression.Convert(expression, binder.ReturnType); } var argumentShouldBeDynamicRealmObject = BindingRestrictions.GetTypeRestriction(Expression, typeof(DynamicRealmObject)); var argumentShouldBeInTheSameRealm = BindingRestrictions.GetInstanceRestriction(Expression.Field(self, RealmObjectRealmField), _realm); return(new DynamicMetaObject(expression, argumentShouldBeDynamicRealmObject.Merge(argumentShouldBeInTheSameRealm))); }
public override DynamicMetaObject FallbackInvokeMember( DynamicMetaObject targetMO, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion) { #if !NETSTANDARD // First try COM binding. DynamicMetaObject result; if (ComBinder.TryBindInvokeMember(this, targetMO, args, out result)) { return(result); } #endif // Defer if any object has no value so that we evaulate their // Expressions and nest a CallSite for the InvokeMember. if (!targetMO.HasValue || args.Any((a) => !a.HasValue)) { var deferArgs = new DynamicMetaObject[args.Length + 1]; for (int i = 0; i < args.Length; i++) { deferArgs[i + 1] = args[i]; } deferArgs[0] = targetMO; return(Defer(deferArgs)); } // Find our own binding. // Could consider allowing invoking static members from an instance. var flags = BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public; var members = targetMO.LimitType.GetMember(this.Name, flags); var restrictions = RuntimeHelpers.GetTargetArgsRestrictions( targetMO, args, false); // Assigned a Null if (targetMO.HasValue && targetMO.Value == null) { return(RuntimeHelpers.CreateThrow(targetMO, args, restrictions, typeof(NullReferenceException), "Object reference not set to an instance of an object.")); } if ((members.Length == 1) && (members[0] is PropertyInfo || members[0] is FieldInfo)) { // NEED TO TEST, should check for delegate value too var mem = members[0]; var target = new DynamicMetaObject( RuntimeHelpers.EnsureObjectResult( Expression.MakeMemberAccess( Expression.Convert(targetMO.Expression, members[0].DeclaringType), members[0])), // Don't need restriction test for name since this // rule is only used where binder is used, which is // only used in sites with this binder.Name. BindingRestrictions.GetTypeRestriction(targetMO.Expression, targetMO.LimitType)); //If no arguments, to allow scenario like Request.QueryString() if (args == null || args.Length == 0) { return(target); } return(new DynamicMetaObject( RuntimeHelpers.GetIndexingExpression(target, args), restrictions )); // Don't test for eventinfos since we do nothing with them now. } else { bool isExtension = false; // Get MethodInfos with right arg counts. var mi_mems = members. Select(m => m as MethodInfo). Where(m => m is MethodInfo && ((MethodInfo)m).GetParameters().Length == args.Length); // Get MethodInfos with param types that work for args. This works // except for value args that need to pass to reftype params. // We could detect that to be smarter and then explicitly StrongBox // the args. List <MethodInfo> res = new List <MethodInfo>(); foreach (var mem in mi_mems) { if (RuntimeHelpers.ParametersMatchArguments( mem.GetParameters(), args)) { res.Add(mem); } } List <DynamicMetaObject> argList = new List <DynamicMetaObject>(args); //Try extension methods if no methods found if (res.Count == 0) { isExtension = true; argList.Insert(0, targetMO); res = RuntimeHelpers.GetExtensionMethods(this.Name, targetMO, argList.ToArray()); } // False below means generate a type restriction on the MO. // We are looking at the members targetMO's Type. if (res.Count == 0) { return(errorSuggestion ?? RuntimeHelpers.CreateThrow( targetMO, args, restrictions, typeof(MissingMemberException), string.Format("Can't bind member invoke {0}.{1}({2})", targetMO.RuntimeType.Name, this.Name, args.ToString()))); } //If more than one results found, attempt overload resolution MethodInfo mi = null; if (res.Count > 1) { mi = RuntimeHelpers.ResolveOverload(res, argList.ToArray()); } else { mi = res[0]; } // restrictions and conversion must be done consistently. var callArgs = RuntimeHelpers.ConvertArguments( argList.ToArray(), mi.GetParameters()); if (isExtension) { return(new DynamicMetaObject( RuntimeHelpers.EnsureObjectResult( Expression.Call( null, mi, callArgs)), restrictions)); } else { return(new DynamicMetaObject( RuntimeHelpers.EnsureObjectResult( Expression.Call( Expression.Convert(targetMO.Expression, targetMO.LimitType), mi, callArgs)), restrictions)); } // Could hve tried just letting Expr.Call factory do the work, // but if there is more than one applicable method using just // assignablefrom, Expr.Call throws. It does not pick a "most // applicable" method or any method. } }
internal DynamicMetaObject FallbackConvert(Type returnType, DynamicMetaObject self, DynamicMetaObject errorSuggestion) { Type type = Type; DynamicMetaObject res = null; switch (type.GetTypeCode()) { case TypeCode.Boolean: res = MakeToBoolConversion(self); break; case TypeCode.Char: res = TryToCharConversion(self); break; case TypeCode.String: var limitType = self.GetLimitType(); if ((limitType == typeof(Bytes) || limitType == typeof(PythonBuffer) || limitType == typeof(ByteArray)) && !_context.PythonOptions.Python30) { res = new DynamicMetaObject( Ast.Call( typeof(PythonOps).GetMethod("MakeString"), AstUtils.Convert(self.Expression, typeof(IList <byte>)) ), BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, limitType) ); } break; case TypeCode.Object: // !!! Deferral? if (type.IsArray && self.Value is PythonTuple && type.GetArrayRank() == 1) { res = MakeToArrayConversion(self, type); } else if (type.IsGenericType && !type.IsAssignableFrom(CompilerHelpers.GetType(self.Value))) { Type genTo = type.GetGenericTypeDefinition(); // Interface conversion helpers... if (genTo == typeof(IList <>)) { if (self.LimitType == typeof(string)) { res = new DynamicMetaObject( Ast.Call( typeof(PythonOps).GetMethod("MakeByteArray"), AstUtils.Convert(self.Expression, typeof(string)) ), BindingRestrictions.GetTypeRestriction( self.Expression, typeof(string) ) ); } else { res = TryToGenericInterfaceConversion(self, type, typeof(IList <object>), typeof(ListGenericWrapper <>)); } } else if (genTo == typeof(IDictionary <,>)) { res = TryToGenericInterfaceConversion(self, type, typeof(IDictionary <object, object>), typeof(DictionaryGenericWrapper <,>)); } else if (genTo == typeof(IEnumerable <>)) { res = TryToGenericInterfaceConversion(self, type, typeof(IEnumerable), typeof(IEnumerableOfTWrapper <>)); } } else if (type == typeof(IEnumerable)) { if (!typeof(IEnumerable).IsAssignableFrom(self.GetLimitType()) && IsIndexless(self)) { res = ConvertToIEnumerable(this, self.Restrict(self.GetLimitType())); } } else if (type == typeof(IEnumerator)) { if (!typeof(IEnumerator).IsAssignableFrom(self.GetLimitType()) && !typeof(IEnumerable).IsAssignableFrom(self.GetLimitType()) && IsIndexless(self)) { res = ConvertToIEnumerator(this, self.Restrict(self.GetLimitType())); } } break; } if (type.IsEnum() && Enum.GetUnderlyingType(type) == self.GetLimitType()) { // numeric type to enum, this is ok if the value is zero object value = Activator.CreateInstance(type); return(new DynamicMetaObject( Ast.Condition( Ast.Equal( AstUtils.Convert(self.Expression, Enum.GetUnderlyingType(type)), AstUtils.Constant(Activator.CreateInstance(self.GetLimitType())) ), AstUtils.Constant(value), Ast.Call( typeof(PythonOps).GetMethod("TypeErrorForBadEnumConversion").MakeGenericMethod(type), AstUtils.Convert(self.Expression, typeof(object)) ) ), self.Restrictions.Merge(BindingRestrictionsHelpers.GetRuntimeTypeRestriction(self.Expression, self.GetLimitType())), value )); } return(res ?? EnsureReturnType(returnType, Context.Binder.ConvertTo(Type, ResultKind, self, _context.SharedOverloadResolverFactory, errorSuggestion))); }
public override DynamicMetaObject FallbackDeleteIndex(DynamicMetaObject target, DynamicMetaObject[] indexes, DynamicMetaObject errorSuggestion) { if (indexes[0].LimitType == typeof(string)) { return(new DynamicMetaObject( Expression.Dynamic(new TjsDeleteMemberBinder(_context, (string)indexes[0].Value, false), ReturnType, target.Expression), BindingRestrictions.Combine(ArrayUtils.Insert(target, indexes)).Merge( BindingRestrictions.GetInstanceRestriction(indexes[0].Expression, indexes[0].Value) ).Merge( BindingRestrictions.GetTypeRestriction(indexes[0].Expression, indexes[0].LimitType) ) )); } return(errorSuggestion ?? new DynamicMetaObject( Expression.Throw(Expression.Constant(new MissingMemberException(indexes[0].Value.ToString())), typeof(object)), BindingRestrictions.Combine(ArrayUtils.Insert(target, indexes)).Merge(BindingRestrictions.GetTypeRestriction(indexes[0].Expression, indexes[0].LimitType)) )); }
private BindingRestrictions GetBindingRestrictions() { var restrictions = BindingRestrictions.GetTypeRestriction(this.Expression, this.LimitType); return(restrictions.Merge(BindingRestrictions.GetInstanceRestriction(this.Expression, this.Host))); }
public DynamicMetaObject GetMetaObject(Expression parameter) { return(new Meta(parameter, BindingRestrictions.GetTypeRestriction(parameter, typeof(Function)), this)); }
public override BindingRestrictions GetRestrictions() { return(BindingRestrictions.GetTypeRestriction(ArgumentExpression, typeof(NativeArgument))); }
private BindingRestrictions GetRestrictions() { return(BindingRestrictions.GetTypeRestriction(Expression, typeof(AttributesAdapter))); }
public override DynamicMetaObject BindGetMember(GetMemberBinder binder) { System.Linq.Expressions.Expression s = System.Linq.Expressions.Expression.Convert(this.Expression, typeof(ModelItemImpl)); System.Linq.Expressions.Expression value = System.Linq.Expressions.Expression.Call(s, getPropertyValueMethodInfo, System.Linq.Expressions.Expression.Constant(binder.Name)); return(new DynamicMetaObject(value, BindingRestrictions.GetTypeRestriction(this.Expression, this.LimitType))); }
/// <summary> /// Access <paramref name="target"/> as object instance. /// </summary> /// <param name="target">Given target.</param> /// <param name="instance">Resolved instance with restrictions.</param> /// <returns>Whether <paramref name="target"/> contains an object instance.</returns> /// <remarks>Necessary restriction are already resolved within returned <paramref name="instance"/>.</remarks> public static bool TryTargetAsObject(DynamicMetaObject target, out DynamicMetaObject instance) { var value = target.Value; if (value == null) { instance = new DynamicMetaObject( target.Expression, target.Restrictions.Merge(BindingRestrictions.GetInstanceRestriction(target.Expression, Expression.Constant(null))), null); return(false); } var expr = target.Expression; // dereference PhpAlias first: if (target.LimitType == typeof(PhpAlias)) { expr = Expression.Field(expr, "Value"); value = ((PhpAlias)value).Value; target = new DynamicMetaObject(expr, target.Restrictions, value); // continue } // unwrap PhpValue if (target.LimitType == typeof(PhpValue)) { var phpvalue = (PhpValue)value; if (phpvalue.IsAlias) { // target of PhpValue.Alias when PhpValue.IsAlias return(TryTargetAsObject( new DynamicMetaObject( Expression.Property(expr, "Alias"), target.Restrictions.Merge(BindingRestrictions.GetExpressionRestriction(Expression.Property(expr, "IsAlias"))), phpvalue.Alias), out instance)); } if (phpvalue.IsObject) { expr = Expression.Property(expr, "Object"); // PhpValue.Object when PhpValue.IsObject instance = new DynamicMetaObject( expr, // PhpValue.Object target.Restrictions.Merge(BindingRestrictions.GetTypeRestriction(expr, phpvalue.Object.GetType())), // PhpValue.Object.GetType() == TYPE phpvalue.Object); // PhpResource is an exception, not acting like an object in PHP if (phpvalue.Object is PhpResource) { // "PhpValue.Object is PhpResource" // ignore the "PhpValue.IsObject" restriction (not needed) instance = new DynamicMetaObject( expr, // PhpValue.Object target.Restrictions.Merge(BindingRestrictions.GetExpressionRestriction(Expression.TypeIs(expr, typeof(PhpResource)))), // PhpValue.Object is PhpResource instance.Value); return(false); } // return(true); } // anything else is not an object, PhpValue.TypeCode == value.TypeCode instance = new DynamicMetaObject( expr, target.Restrictions.Merge(BindingRestrictions.GetExpressionRestriction(Expression.Equal(Expression.Property(expr, "TypeCode"), Expression.Constant(phpvalue.TypeCode)))), value); return(false); } // var restrictions = target.Restrictions; var lt = target.Expression.Type.GetTypeInfo(); if (!lt.IsValueType && !lt.IsSealed && !typeof(PhpArray).IsAssignableFrom(lt.AsType()) && !typeof(PhpResource).IsAssignableFrom(lt.AsType())) { // we need to set the type restriction restrictions = restrictions.Merge(BindingRestrictions.GetTypeRestriction(expr, value.GetType())); } // instance = new DynamicMetaObject(expr, restrictions, value); return(!( // TODO: ReflectionUtils.IsClassType value is PhpResource || value is PhpArray || value is bool || value is int || value is long || value is double || value is string || value is PhpString)); }
public override DynamicMetaObject FallbackSetMember( DynamicMetaObject target, DynamicMetaObject value, DynamicMetaObject errorSuggestion) { // Used by (set-attr obj name value) if (!target.HasValue) { return(Defer(target)); } var name = Name.LispToPascalCaseName(); if (target.Value == null) { var id = target.LimitType.Name + "." + name; return(Runtime.CheckTargetNullReference(target, "Cannot set property on null reference:" + id + "(null)")); } var flags = BindingFlags.IgnoreCase | BindingFlags.Instance | BindingFlags.Public | BindingFlags.FlattenHierarchy; var members = target.LimitType.GetMember(name, flags); if (members.Length == 1 && members[0] is PropertyInfo) { var prop = (PropertyInfo)members[0]; var val = Runtime.ConvertArgument(value, prop.PropertyType); var expr = Expression.Assign(Expression.MakeMemberAccess(Expression.Convert(target.Expression, prop.DeclaringType), prop), val); return(new DynamicMetaObject(Runtime.EnsureObjectResult(expr), BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType))); } else if (members.Length == 1 && members[0] is FieldInfo) { var field = (FieldInfo)members[0]; var val = Runtime.ConvertArgument(value, field.FieldType); var expr = Expression.Assign(Expression.MakeMemberAccess(Expression.Convert(target.Expression, field.DeclaringType), field), val); return(new DynamicMetaObject(Runtime.EnsureObjectResult(expr), BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType))); } else if (members.Length == 1 && members[0] is EventInfo) { //public static void AddEventHandler( System.Reflection.EventInfo eventinfo, object target, object func ) var evt = (EventInfo)members[0]; var expr = Expression.Call(Runtime.AddEventHandlerMethod, Expression.Constant(evt, typeof(EventInfo)), Expression.Convert(target.Expression, evt.DeclaringType), Expression.Convert(value.Expression, typeof(IApply))); return(new DynamicMetaObject(Runtime.EnsureObjectResult(expr), BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType))); } else { return(errorSuggestion ?? Runtime.CreateThrow( target, null, BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType), typeof(MissingMemberException), "Property or field not found: " + target.LimitType.Name + "." + name + Runtime.CollectParameterInfo(target))); } }
public void TypeRestrictionTrueForMatchType(object obj) { BindingRestrictions isType = BindingRestrictions.GetTypeRestriction(Expression.Constant(obj), obj.GetType()); Assert.True(Expression.Lambda <Func <bool> >(isType.ToExpression()).Compile()()); }