Esempio n. 1
0
        public FunctionBuilder(MemberInfo member, FunctionSignature key)
        {
            Member = member;
            var parameterTypes = new List <Type>();

            IsStatic = member.IsStatic();
            if (!IsStatic)
            {
                // handle declaring type as first parameter
                parameterTypes.Add(member.DeclaringType ?? member.ReflectedType);
            }
            if (Method != null)
            {
                // it is a method, else it is a property or field
                parameterTypes.AddRange(Method.GetParameters().Select(p => p.ParameterType));
            }
            // else it is a field or property

            ParameterTypes = parameterTypes.AsReadOnly();
            Key            = key;
            NeedTypeCast   = !Key.SequenceEqual(parameterTypes);
            HasDelegateArg = key.Any(t => typeof(Delegate).IsAssignableFrom(t));
        }
Esempio n. 2
0
 public bool IsInvokableBy(FunctionSignature other)
 {
     return(other._types.Count == _types.Count && !_types.Where((t, i) => !other._types[i].CanBeConvertedInto(t)).Any());
 }
Esempio n. 3
0
        public bool TryBuildExpression(ASTBuilder astBuilder, FunctionToken functionToken, Stack <Token> stack, ParameterExpression p, out Expression output)
        {
            output = null;

            IFunctionBuilder builder;

            if (_builders.TryGetValue(functionToken.Lexeme, out builder))
            {
                if (builder.TryBuildExpression(astBuilder, functionToken, stack, p, out output))
                {
                    return(true);
                }
            }


            ConcurrentDictionary <FunctionSignature, FunctionBuilder> lookup;

            if (!_members.TryGetValue(functionToken.Lexeme, out lookup))
            {
                return(false);
            }

            var args = new List <Expression>();

            for (var i = 0; i < functionToken.ParameterCount; i++)
            {
                args.Add(astBuilder.PopExpression(stack, p));
            }

            args.Add(p);    // always initially probe instance call

            args.Reverse(); // reverse stack order

            FunctionBuilder factory;
            FunctionSignature
                fs1 = null, // instance
                fs2 = null; // static

            if (!TryFindFactory(lookup, fs1 = new FunctionSignature(args.Select(fp => fp.Type)), out factory))
            {
                if (TryFindFactory(lookup, fs2 = new FunctionSignature(args.Skip(1).Select(fp => fp.Type)), out factory))
                {
                    args = args.Skip(1).ToList();
                }
            }

            if (factory != null)
            {
                // found
                if (args.Any() && factory.ParameterTypes.Any())
                {
                    if (factory.ParameterTypes.Last().IsArray&& !args.Last().Type.IsArray)
                    {
                        // we need an argument conversion to params <some-type>[]
                        if (fs2 != null)
                        {
                            // static invocation
                            if (factory.ParameterTypes[0] == typeof(object[]))
                            {
                                args = new List <Expression>(new[] { Expression.NewArrayInit(typeof(object), args.Select(a => a.Convert <object>())) });
                            }
                            else
                            {
                                args = new List <Expression>(new[] { Expression.NewArrayInit(args[0].Type, args) });
                            }
                        }
                        else
                        {
                            // instane invocation
                            if (factory.ParameterTypes[1] == typeof(object[]))
                            {
                                args = new List <Expression>(new[] { args[0], Expression.NewArrayInit(typeof(object), args.Skip(1).Select(a => a.Convert <object>())) });
                            }
                            else
                            {
                                args = new List <Expression>(new[] { args[0], Expression.NewArrayInit(args[0].Type, args.Skip(1)) });
                            }
                        }
                    }
                }
                output = factory.BuildExpression(args, p);
                return(true);
            }

            FunctionSignature signature;

            /////////////////////////////////////////////////////////////////////////////////////////////////////////
            // 1. try instance
            if (args.Count == 2 || args.Skip(1).Select(x => x.Type).Distinct().Count() == 1)
            {
                signature = new FunctionSignature(new[] { args[0].Type, args[1].Type.MakeArrayType() });
                if (TryFindFactory(lookup, signature, out factory))
                {
                    // probably params <type>[] arg
                    args = new List <Expression>
                    {
                        args[0],
                        Expression.NewArrayInit(args[1].Type, args.Skip(1))
                    };
                    lookup.TryAdd(fs1, factory);// register in lookup
                    output = factory.BuildExpression(args, p);
                    return(true);
                }
            }

            // any delegates?
            var args1     = args;
            var factories = lookup.Values.Where(f => f.HasDelegateArg && f.ParameterTypes.Count == args1.Count);

            foreach (var f in factories)
            {
                var ismatch = true;
                var i       = 0;
                foreach (var t in f.ParameterTypes)
                {
                    if (!(typeof(Delegate).IsAssignableFrom(t) || t.IsAssignableFrom(args[i].Type)))
                    {
                        ismatch = false;
                        break;
                    }
                    i++;
                }
                if (ismatch)
                {
                    lookup.TryAdd(fs1, f);// register in lookup
                    output = f.BuildExpression(args, p);
                    return(true);
                }
            }

            // params object[] ?
            signature = new FunctionSignature(new[] { args[0].Type, typeof(object).MakeArrayType() });
            if (TryFindFactory(lookup, signature, out factory))
            {
                // probably params object[] arg
                args = new List <Expression>
                {
                    args[0],
                    Expression.NewArrayInit(typeof(object), args.Skip(1).Select(e => e.Convert <object>()))
                };
                lookup.TryAdd(fs1, factory);// register in lookup
                output = factory.BuildExpression(args, p);
                return(true);
            }
            //
            //////////////////////////////////////////////////////////////////////////////////////////////////////

            /////////////////////////////////////////////////////////////////////////////////////////////////////
            // 2. try static
            args = args.Skip(1).ToList();

            if (args.Count == 1 || args.Select(x => x.Type).Distinct().Count() == 1)
            {
                // all argumens have same type, look for array type
                signature = new FunctionSignature(new[] { args[0].Type.MakeArrayType() });
                if (TryFindFactory(lookup, signature, out factory))
                {
                    // probably params <type>[] arg
                    args = new List <Expression>
                    {
                        Expression.NewArrayInit(args[0].Type, args)
                    };
                    lookup.TryAdd(fs2, factory);// register in lookup
                    output = factory.BuildExpression(args, p);
                    return(true);
                }
            }

            // any delegate?
            var args2 = args;

            factories = lookup.Values.Where(f => f.HasDelegateArg && f.ParameterTypes.Count - 1 == args2.Count);
            foreach (var f in factories)
            {
                var ismatch = true;
                var i       = 0;
                foreach (var t in f.ParameterTypes.Skip(1))
                {
                    if (!(typeof(Delegate).IsAssignableFrom(t) || t.IsAssignableFrom(args[i].Type)))
                    {
                        ismatch = false;
                        break;
                    }
                    i++;
                }
                if (ismatch)
                {
                    lookup.TryAdd(fs2, f);// register in lookup
                    output = f.BuildExpression(args, p);
                    return(true);
                }
            }

            // params object[] ?
            signature = new FunctionSignature(new[] { typeof(object).MakeArrayType() });
            if (TryFindFactory(lookup, signature, out factory))
            {
                // probably params object[] arg
                args = new List <Expression>
                {
                    args[0],
                    Expression.NewArrayInit(typeof(object), args.Skip(1).Select(e => e.Convert <object>()))
                };
                lookup.TryAdd(fs2, factory);// register in lookup
                output = factory.BuildExpression(args, p);
                return(true);
            }
            throw new XPressionException(functionToken.Source, "invalid arguments, overload not found for method " + functionToken.Lexeme, functionToken.Position);
        }
Esempio n. 4
0
        private static bool TryFindFactory(ConcurrentDictionary <FunctionSignature, FunctionBuilder> lookup, FunctionSignature signature, out FunctionBuilder factory)
        {
            if (lookup.TryGetValue(signature, out factory))
            {
                return(true);
            }
            var overload = lookup.Keys.FirstOrDefault(s => s.IsInvokableBy(signature));

            if (overload != null)
            {
                factory = new FunctionBuilder(lookup[overload].Member, signature);
                lookup.TryAdd(signature, factory);
                return(true);
            }
            return(false);
        }