示例#1
0
        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));
        };
示例#2
0
        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());
        }
示例#3
0
        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());
        }
示例#4
0
        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());
        }
示例#5
0
        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));
        };
示例#6
0
        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));
        };
示例#7
0
        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;
 }
示例#11
0
 public static MondValue Bind <T>(MondState state = null, MondBindingOptions options = MondBindingOptions.None)
 => MondObjectBinder.Bind(typeof(T), out var dummy, state, options);
示例#12
0
        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
                };
            });
        }
示例#13
0
 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
     });
 };
示例#14
0
        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
        }
示例#15
0
        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
        }