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
     });
 };
        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));
        };