private static Expression MemberSetExpressionCore(Lua lua, Token tokenStart, Expression instance, string memberName, Expression set) { if (LuaEmit.IsDynamicType(instance.Type)) // first call the dynamic interface { return(DynamicExpression.Dynamic(lua.GetSetMemberBinder(memberName), typeof(object), ConvertObjectExpression(lua, tokenStart, instance, true), ConvertObjectExpression(lua, tokenStart, set, true) )); } else { Expression result; switch (LuaEmit.TrySetMember(instance, instance.Type, memberName, false, (setType) => ConvertExpression(lua, tokenStart, set, setType), out result)) { case LuaTrySetMemberReturn.None: throw ParseError(tokenStart, LuaEmitException.GetMessageText(LuaEmitException.MemberNotFound, instance.Type.Name, memberName)); case LuaTrySetMemberReturn.NotWritable: throw ParseError(tokenStart, LuaEmitException.GetMessageText(LuaEmitException.CanNotWriteMember, instance.Type.Name, memberName)); case LuaTrySetMemberReturn.ValidExpression: return(result); default: throw new ArgumentException("Internal return type of TrySetMember"); } } } // func MemberSetExpressionCore
} // func MemberGetSandbox private static Expression MemberGetExpressionCore(Lua lua, Token tokenStart, Expression instance, string memberName) { // if this is a dynamic type, let the type deside what is to do if (LuaEmit.IsDynamicType(instance.Type)) { return(DynamicExpression.Dynamic(lua.GetGetMemberBinder(memberName), typeof(object), ConvertObjectExpression(lua, tokenStart, instance, true))); } else { Expression result; switch (LuaEmit.TryGetMember(instance, instance.Type, memberName, false, out result)) { case LuaTryGetMemberReturn.None: throw ParseError(tokenStart, LuaEmitException.GetMessageText(LuaEmitException.MemberNotFound, instance.Type.Name, memberName)); case LuaTryGetMemberReturn.NotReadable: throw ParseError(tokenStart, LuaEmitException.GetMessageText(LuaEmitException.CanNotReadMember, instance.Type.Name, memberName)); case LuaTryGetMemberReturn.ValidExpression: return(result); default: throw new ArgumentException("Internal return type of TryGetMember"); } } } // func MemberGetExpressionCore
} // func IndexSetExpression private static Expression InvokeExpression(Scope scope, Token tStart, Expression instance, InvokeResult result, ArgumentsList arguments, bool lParse) { MethodInfo mi; ConstantExpression constInstance = instance as ConstantExpression; LuaType t; if (constInstance != null && (t = constInstance.Value as LuaType) != null && t.Type != null) // we have a type, bind the ctor { var type = t.Type; var typeInfo = type.GetTypeInfo(); var ci = typeInfo.IsValueType && arguments.Count == 0 ? null : LuaEmit.FindMember(typeInfo.DeclaredConstructors.Where(c => c.IsPublic), arguments.CallInfo, arguments.Expressions, getExpressionTypeFunction, false); if (ci == null && !typeInfo.IsValueType) { throw ParseError(tStart, String.Format(Properties.Resources.rsMemberNotResolved, type.Name, "ctor")); } return(SafeExpression(() => LuaEmit.BindParameter(scope.Runtime, args => ci == null ? Expression.New(type) : Expression.New(ci, args), ci == null ? new ParameterInfo[0] : ci.GetParameters(), arguments.CallInfo, arguments.Expressions, getExpressionFunction, getExpressionTypeFunction, true), tStart)); } else if (LuaEmit.IsDynamicType(instance.Type)) { // fallback is a dynamic call return(EnsureInvokeResult(scope, tStart, DynamicExpression.Dynamic(scope.Runtime.GetInvokeBinder(arguments.CallInfo), typeof(object), new Expression[] { ConvertExpression(scope.Runtime, tStart, instance, typeof(object)) }.Concat( from c in arguments.Expressions select Lua.EnsureType(c, typeof(object)) ) ), result, instance, null )); } else if (typeof(Delegate).GetTypeInfo().IsAssignableFrom(instance.Type.GetTypeInfo()) && // test if the type is assignable from delegate (mi = instance.Type.GetRuntimeMethods().Where(c => !c.IsStatic && c.IsPublic && c.Name == "Invoke").FirstOrDefault()) != null) // Search the Invoke method for the arguments { return(EnsureInvokeResult(scope, tStart, SafeExpression(() => LuaEmit.BindParameter <Expression>( scope.Runtime, args => Expression.Invoke(instance, args), mi.GetParameters(), arguments.CallInfo, arguments.Expressions, getExpressionFunction, getExpressionTypeFunction, true), tStart), result, instance, null )); } else { throw ParseError(tStart, LuaEmitException.GetMessageText(LuaEmitException.InvokeNoDelegate, instance.Type.Name)); } } // func InvokeExpression
} // ctor public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion) { //defer the target and all arguments if (!target.HasValue || args.Any(c => !c.HasValue)) { return(Defer(target, args)); } if (target.Value == null) // Invoke on null value { return(errorSuggestion ?? new DynamicMetaObject( ThrowExpression(Properties.Resources.rsNilNotCallable), BindingRestrictions.GetInstanceRestriction(target.Expression, null) )); } else { BindingRestrictions restrictions = GetMethodSignatureRestriction(target, args); Expression expr; Delegate invokeTarget = target.Value as Delegate; if (invokeTarget == null) { if (errorSuggestion != null) { return(errorSuggestion); } expr = ThrowExpression(LuaEmitException.GetMessageText(LuaEmitException.InvokeNoDelegate, target.LimitType.Name), typeof(object)); } else { ParameterInfo[] methodParameters = invokeTarget.Method.GetParameters(); ParameterInfo[] parameters = null; MethodInfo mi = target.LimitType.GetMethod("Invoke"); if (mi != null) { ParameterInfo[] typeParameters = mi.GetParameters(); if (typeParameters.Length != methodParameters.Length) { parameters = new ParameterInfo[typeParameters.Length]; // the hidden parameters are normally at the beginning if (parameters.Length > 0) { Array.Copy(methodParameters, methodParameters.Length - typeParameters.Length, parameters, 0, parameters.Length); } } else { parameters = methodParameters; } } else { parameters = methodParameters; } try { expr = EnsureType( LuaEmit.BindParameter(lua, _args => Expression.Invoke(EnsureType(target.Expression, target.LimitType), _args), parameters, args, mo => mo.Expression, mo => mo.LimitType, false), typeof(object), true); } catch (LuaEmitException e) { if (errorSuggestion != null) { return(errorSuggestion); } expr = ThrowExpression(e.Message, ReturnType); } } return(new DynamicMetaObject(expr, restrictions)); } } // func FallbackInvoke
} // ctor public override DynamicMetaObject FallbackGetMember(DynamicMetaObject target, DynamicMetaObject errorSuggestion) { // defer the target, to get the type if (!target.HasValue) { return(Defer(target)); } if (target.Value == null) // no value for target, finish binding with an error or the suggestion { return(errorSuggestion ?? new DynamicMetaObject( ThrowExpression(Properties.Resources.rsNullReference, ReturnType), target.Restrictions.Merge(BindingRestrictions.GetInstanceRestriction(target.Expression, null)) )); } else { // restrictions var restrictions = target.Restrictions.Merge(BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType)); // try to bind the member switch (LuaEmit.TryGetMember(target.Expression, target.LimitType, Name, IgnoreCase, out var expr)) { case LuaTryGetMemberReturn.None: return(errorSuggestion ?? new DynamicMetaObject(Expression.Default(ReturnType), restrictions)); case LuaTryGetMemberReturn.NotReadable: return(errorSuggestion ?? new DynamicMetaObject(ThrowExpression(LuaEmitException.GetMessageText(LuaEmitException.CanNotReadMember, target.LimitType.Name, Name), ReturnType), restrictions)); case LuaTryGetMemberReturn.ValidExpression: return(new DynamicMetaObject(EnsureType(expr, ReturnType), restrictions)); default: throw new ArgumentException("return of TryGetMember."); } } } // func FallbackGetMember
} // ctor public override DynamicMetaObject FallbackSetMember(DynamicMetaObject target, DynamicMetaObject value, DynamicMetaObject errorSuggestion) { // defer the target if (!target.HasValue) { return(Defer(target)); } if (target.Value == null) { return(errorSuggestion ?? new DynamicMetaObject( ThrowExpression(String.Format(Properties.Resources.rsMemberNotResolved, target.LimitType.Name, Name), ReturnType), target.Restrictions.Merge(BindingRestrictions.GetInstanceRestriction(target.Expression, null)) )); } else { // restrictions var restrictions = target.Restrictions.Merge(BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType)); // try to bind the member switch (LuaEmit.TrySetMember(target.Expression, target.LimitType, Name, IgnoreCase, (setType) => LuaEmit.ConvertWithRuntime(Lua, value.Expression, value.LimitType, setType), out var expr)) { case LuaTrySetMemberReturn.None: return(errorSuggestion ?? new DynamicMetaObject(ThrowExpression(LuaEmitException.GetMessageText(LuaEmitException.MemberNotFound, target.LimitType.Name, Name), ReturnType), restrictions)); case LuaTrySetMemberReturn.NotWritable: return(errorSuggestion ?? new DynamicMetaObject(ThrowExpression(LuaEmitException.GetMessageText(LuaEmitException.CanNotWriteMember, target.LimitType.Name, Name), ReturnType), restrictions)); case LuaTrySetMemberReturn.ValidExpression: return(new DynamicMetaObject(EnsureType(expr, ReturnType), restrictions.Merge(GetSimpleRestriction(value)))); default: throw new ArgumentException("return of TryGetMember."); } } } // func FallbackSetMember