public static MondFunction CreateStaticMethodShim(Type type, string name, MondBindingOptions options) => delegate(MondState state, MondValue[] args) { var target = BindingUtils.GetTarget <MethodInfo>( type, name, args, BindingFlags.Public | BindingFlags.Static, options); var values = TypeConverter.MarshalToClr(args, target.Types, state, options); var result = target.Method.Invoke(null, values); if (target.Method.ReturnType == typeof(void)) { return(MondValue.Undefined); } if (result == null) { return(MondValue.Null); } var mondType = TypeConverter.ToMondType(result.GetType()); return(TypeConverter.MarshalToMond(result, mondType, state, options)); };
public static string GetName(this MemberInfo info, MondBindingOptions options) { var name = info.GetCustomAttribute <MondAliasAttribute>(true)?.Name ?? info.Name; return(options.HasFlag(MondBindingOptions.PreserveNames) && !name.StartsWith("__") ? name : name.ChangeNameCase()); }
public static object[] MarshalToClr( MondValue[] values, Type[] expectedTypes, MondState state, MondBindingOptions options) { if (!TypeConverter.MatchTypes(values, expectedTypes)) { throw new ArgumentException("Given values do not match expected types", nameof(values)); } return(values.Zip(expectedTypes, (a, b) => new { Value = a, ExpectedType = b }) .Select(x => TypeConverter.MarshalToClr(x.Value, x.ExpectedType, state, options)) .ToArray()); }
private static ReflectedMember <T> GetTarget <T>( Type type, string name, MondValue[] args, BindingFlags flags, MondBindingOptions options) where T : MemberInfo { if ((typeof(T) != typeof(ConstructorInfo)) && (typeof(T) != typeof(MethodInfo))) { throw new ArgumentException("Generic argument must be either ConstructorInfo or MethodInfo", "T"); } var matcher = BindingUtils.CreateTargetMatcher <T>(args, name, options); var members = null as MemberInfo[]; if (typeof(T) == typeof(ConstructorInfo)) { members = type.GetConstructors(flags); } else if (typeof(T) == typeof(MethodInfo)) { members = type.GetMethods(flags); } // ReSharper disable once AssignNullToNotNullAttribute var matched = members.Select(m => matcher((T)m)) .Where(m => m.Matched); var reflectedMembers = matched as ReflectedMember <T>[] ?? matched.ToArray(); if (reflectedMembers.Length > 1) { throw new AmbiguousMatchException( $"More than one {( typeof( T ) == typeof( ConstructorInfo ) ? "constructor" : "method" )}" + $" in {type.GetName()} matches the argument list for {name}"); } if (reflectedMembers.Length == 0) { throw new MissingMethodException( $"No {( typeof( T ) == typeof( ConstructorInfo ) ? "constructor" : "method" )} in" + $" {type.GetName()} matches the argument list for {name}"); } return(reflectedMembers.First()); }
public static MondInstanceFunction CreateInstanceOverloadGroupShim( IEnumerable <MethodInfo> methods, MondBindingOptions options) => delegate(MondState state, MondValue instance, MondValue[] args) { // Remove the object instance from the argument list. // This is primarily to prevent argument mismatch exceptions // when the Mond runtime tries to dispatch a metamethod. if ((args != null) && (args.Length >= 1) && (args[0] == instance)) { args = args.Skip(1).ToArray(); } var matcher = BindingUtils.CreateTargetMatcher <MethodInfo>(args, null, options); var matched = methods.Select(matcher).Where(m => m.Matched); var reflectedMembers = matched as ReflectedMember <MethodInfo>[] ?? matched.ToArray(); if (reflectedMembers.Length > 1) { throw new AmbiguousMatchException( "More than one delegate in the invokation list matches the argument list"); } if (reflectedMembers.Length == 0) { throw new MissingMethodException( "No delegate in the invokation list matches the argument list"); } var target = reflectedMembers[0]; var values = TypeConverter.MarshalToClr(args, target.Types, state, options); var result = target.Method.Invoke(instance.UserData, values); if (target.Method.ReturnType == typeof(void)) { return(MondValue.Undefined); } if (result == null) { return(MondValue.Null); } var mondType = TypeConverter.ToMondType(result.GetType()); return(TypeConverter.MarshalToMond(result, mondType, state, options)); };
public static MondInstanceFunction CreateInstanceMethodShim( Type type, string name, MondBindingOptions options, bool isMetamethod = false) => delegate(MondState state, MondValue instance, MondValue[] args) { // Remove the object instance from the argument list. // This is primarily to prevent argument mismatch exceptions // when the Mond runtime tries to dispatch a metamethod. if ((args != null) && (args.Length >= 1) && (args[0] == instance) && (name.StartsWith("__") || isMetamethod)) { args = args.Skip(1).ToArray(); } var target = BindingUtils.GetTarget <MethodInfo>( type, name, args, BindingFlags.Public | BindingFlags.Instance, options); var values = TypeConverter.MarshalToClr(args, target.Types, state, options); var result = target.Method.Invoke(instance.UserData, values); if (target.Method.ReturnType == typeof(void)) { return(MondValue.Undefined); } if (result == null) { return(MondValue.Null); } var mondType = TypeConverter.ToMondType(result.GetType()); return(TypeConverter.MarshalToMond(result, mondType, state, options)); };
public static MondFunction CreateStaticOverloadGroupShim( IEnumerable <MethodInfo> methods, MondBindingOptions options) => delegate(MondState state, MondValue[] args) { var matcher = BindingUtils.CreateTargetMatcher <MethodInfo>(args, null, options); var matched = methods.Select(matcher).Where(m => m.Matched); var reflectedMembers = matched as ReflectedMember <MethodInfo>[] ?? matched.ToArray(); if (reflectedMembers.Length > 1) { throw new AmbiguousMatchException( "More than one delegate in the invokation list matches the argument list"); } if (reflectedMembers.Length == 0) { throw new MissingMethodException( "No delegate in the invokation list matches the argument list"); } var target = reflectedMembers[0]; var values = TypeConverter.MarshalToClr(args, target.Types, state, options); var result = target.Method.Invoke(null, values); if (target.Method.ReturnType == typeof(void)) { return(MondValue.Undefined); } if (result == null) { return(MondValue.Null); } var mondType = TypeConverter.ToMondType(result.GetType()); return(TypeConverter.MarshalToMond(result, mondType, state, options)); };
public static string ChangeNameCase(this string name, MondBindingOptions options = MondBindingOptions.None) { if (options.HasFlag(MondBindingOptions.PreserveNames)) { return(name); } if (!StringExtensions.IdentifierRegex.IsMatch(name)) { return(name); } var matches = StringExtensions.IdentifierRegex .Matches(name) .Cast <Match>() .Select( m => m.Value .ToLower() .Trim('_') ) .ToArray(); return(matches.First() + String.Join(String.Empty, matches.Skip(1).Select(s => s.ToUpperFirst()))); }
public PropertyNameComparer(MondBindingOptions options) { this._options = options; }
public MethodNameComparer(MondBindingOptions options) { this._options = options; }
public static MondValue Bind <T>(MondState state = null, MondBindingOptions options = MondBindingOptions.None) => MondObjectBinder.Bind(typeof(T), out var dummy, state, options);
private static Func <T, ReflectedMember <T> > CreateTargetMatcher <T>( MondValue[] args, string name, MondBindingOptions options) { if ((typeof(T) != typeof(ConstructorInfo)) && (typeof(T) != typeof(MethodInfo)) && (typeof(T) != typeof(Delegate))) { throw new ArgumentException( "Generic argument must be either ConstructorInfo, MethodInfo, or Delegate"); } return(delegate(T member) { if (name != null) { var memberName = null as string; if (member is ConstructorInfo) { memberName = (member as ConstructorInfo).GetName(options); } else if (member is MethodInfo) { memberName = (member as MethodInfo).GetName(options); } else if (member is Delegate) { memberName = (member as Delegate).GetMethodInfo().GetName(options); } if (memberName != name) { return new ReflectedMember <T> { Matched = false } } ; } var all = null as ParameterInfo[]; if (member is ConstructorInfo) { all = (member as ConstructorInfo).GetParameters(); } else if (member is MethodInfo) { all = (member as MethodInfo).GetParameters(); } else if (member is Delegate) { all = (member as Delegate).GetMethodInfo().GetParameters(); } var required = all.Reject(p => p.IsOptional).ToArray(); if (args.Length == 0) { return new ReflectedMember <T> { Matched = required.Length == 0, Method = member, Types = Type.EmptyTypes }; } if ((required.Length == args.Length) && TypeConverter.MatchTypes(args, required.Select(p => p.ParameterType).ToArray())) { return new ReflectedMember <T> { Matched = true, Method = member, Types = required.Select(p => p.ParameterType).ToArray() }; } // ReSharper disable once PossibleNullReferenceException if ((all.Length == args.Length) && TypeConverter.MatchTypes(args, all.Select(p => p.ParameterType).ToArray())) { return new ReflectedMember <T> { Matched = true, Method = member, Types = all.Select(p => p.ParameterType).ToArray() }; } return new ReflectedMember <T> { Matched = false }; }); }
public static MondFunction CreateConstructorShim(Type type, MondValue prototype, MondBindingOptions options) => delegate(MondState state, MondValue[] args) { var target = BindingUtils.GetTarget <ConstructorInfo>( type, null, args, BindingFlags.Public | BindingFlags.Instance, options); var values = TypeConverter.MarshalToClr(args, target.Types, state, options); return(new MondValue(state) { UserData = target.Method.Invoke(values), Prototype = prototype }); };
public static object MarshalToClr( MondValue value, Type expectedType, MondState state, MondBindingOptions options) { if (!TypeConverter.MatchType(value, expectedType)) { throw new ArgumentException("Given value does not match expected type", nameof(value)); } if (expectedType == typeof(MondValue)) { return(value); } // ReSharper disable once SwitchStatementMissingSomeCases switch (value.Type) { case MondValueType.False: case MondValueType.True: return((bool)value); case MondValueType.Null: case MondValueType.Undefined: if (!expectedType.GetTypeInfo().IsValueType) { return(null); } if (expectedType.IsConstructedGenericType && (expectedType.GetGenericTypeDefinition() == typeof(Nullable <>))) { return(Activator.CreateInstance(expectedType)); } throw new InvalidOperationException( $"Cannot bind {value.Type.GetName()} value to " + $"{expectedType.FullName} because it is a value type"); case MondValueType.String: var str = value.ToString(); if (expectedType != typeof(char)) { return(str); } if (str.Length != 1) { throw new ArgumentException("Value cannot be converted to char", nameof(value)); } return(str[0]); case MondValueType.Number: if (expectedType.IsConstructedGenericType && (expectedType.GetGenericTypeDefinition() == typeof(Nullable <>))) { var innerType = expectedType.GetGenericArguments()[0]; var converted = Convert.ChangeType((double)value, innerType); return(Activator.CreateInstance(expectedType, converted)); } if (!expectedType.GetTypeInfo().IsEnum) { return(Convert.ChangeType((double)value, expectedType)); } var underlying = Enum.GetUnderlyingType(expectedType); var rawValue = Convert.ChangeType((double)value, underlying); var valueName = Enum.GetName(expectedType, rawValue); // ReSharper disable once AssignNullToNotNullAttribute return(Enum.Parse(expectedType, valueName)); case MondValueType.Object: return(value.UserData); case MondValueType.Function: object Shim(object[] args) { MondValue result; if ((args == null) || (args.Length == 0)) { result = state.Call(value); } else { var mondTypes = TypeConverter.ToMondTypes( args.Select(a => a.GetType()).ToArray()); var mondValues = TypeConverter.MarshalToMond(args, mondTypes, state, options); result = state.Call(value, mondValues); } if ((result.Type == MondValueType.Null) || (result.Type == MondValueType.Undefined)) { return(null); } var clrType = TypeConverter.ToClrType(result); return(TypeConverter.MarshalToClr(result, clrType, state, options)); } if (!typeof(Delegate).IsAssignableFrom(expectedType)) { return((Func <object[], object>)Shim); } var invoke = expectedType.GetMethod("Invoke", BindingFlags.Public | BindingFlags.Instance); var parameters = invoke.GetParameters().Select(p => p.ParameterType).ToArray(); var delegateType = invoke.ReturnType == typeof(void) ? Expression.GetActionType(parameters) : Expression.GetFuncType(parameters.Concat(invoke.ReturnType).ToArray()); var shim = (Func <object[], object>)Shim; var paramsExpr = parameters.Select(Expression.Parameter).ToArray(); // ReSharper disable once CoVariantArrayConversion var paramsArr = Expression.NewArrayInit(typeof(object), paramsExpr); var invokeExpr = Expression.Call( Expression.Constant(shim.Target), shim.GetMethodInfo(), paramsArr); // ReSharper disable once TooWideLocalVariableScope BlockExpression body; if (invoke.ReturnType == typeof(void)) { body = Expression.Block(invokeExpr); } else { var castExpr = Expression.Convert(invokeExpr, invoke.ReturnType); body = Expression.Block(castExpr); } var method = typeof(Expression) .GetMethods(BindingFlags.Public | BindingFlags.Static) .Where(m => m.Name == "Lambda") .First(m => m.IsGenericMethodDefinition); var lambda = method.MakeGenericMethod(delegateType); return(((LambdaExpression)lambda.Invoke(null, new object[] { body, paramsExpr })).Compile()); default: TypeConverter.UnsupportedMondTypeError(value.Type); break; } return(null); // we should never get here }
public static MondValue MarshalToMond( object value, MondValueType expectedType, MondState state, MondBindingOptions options) { if (value == null) { return(MondValue.Null); } if (expectedType == MondValueType.Object) { if (state == null) { throw new ArgumentNullException( nameof(state), "Must have a valid MondState when binding an object"); } return(MondObjectBinder.Bind(value.GetType(), value, state, options)); } if (!TypeConverter.MatchType(expectedType, value.GetType())) { throw new ArgumentException("Given value does not match expected type", nameof(value)); } if (value is MondValue mond) { return(mond); } var type = value.GetType(); if (type.IsConstructedGenericType && (type.GetGenericTypeDefinition() == typeof(Nullable <>))) { var innerType = type.GetGenericArguments()[0]; dynamic nullable = value; if (!TypeConverter.MatchType(expectedType, innerType) || (!nullable.HasValue && (expectedType != MondValueType.Null) && (expectedType != MondValueType.Undefined))) { throw new ArgumentException("Given value does not match expected type", nameof(value)); } value = nullable.Value; } // ReSharper disable once SwitchStatementMissingSomeCases switch (expectedType) { case MondValueType.False: case MondValueType.True: return((bool)value); case MondValueType.Null: return(MondValue.Null); case MondValueType.Undefined: return(MondValue.Undefined); case MondValueType.String: return(value.ToString()); case MondValueType.Number: return((double)Convert.ChangeType(value, typeof(double))); case MondValueType.Function: var info = value.GetType().GetTypeInfo(); if (value is MulticastDelegate || (info.BaseType == typeof(MulticastDelegate))) { return(MondObjectBinder.Bind(value as MulticastDelegate)); } if (value is Delegate || (info.BaseType == typeof(Delegate))) { return(MondObjectBinder.Bind(value as Delegate)); } throw new NotSupportedException("Unsupported delegate type"); case MondValueType.Object: return(MondObjectBinder.Bind(value.GetType(), value, null, MondBindingOptions.AutoLock)); default: TypeConverter.UnsupportedMondTypeError(expectedType); break; } return(null); // we should never get here }