예제 #1
0
        private RedwoodType(Type cSharpType)
        {
            CSharpType = cSharpType;
            Name       = CSharpType.Name;

            Type[] genericArgs = cSharpType.GenericTypeArguments;
            GenericArguments = new RedwoodType[genericArgs.Length];

            for (int i = 0; i < genericArgs.Length; i++)
            {
                GenericArguments[i] = GetForCSharpType(genericArgs[i]);
            }

            // TODO: base type's generic arguments?
            if (cSharpType != typeof(object) && cSharpType.BaseType != null)
            {
                BaseType = GetForCSharpType(cSharpType.BaseType);
            }

            // TODO: Is LINQ too slow for a runtime context?
            Constructor = RuntimeUtil.CanonicalizeLambdas(
                cSharpType
                .GetConstructors()
                .Select(constructor => new ExternalLambda(this, constructor))
                .ToArray()
                );
        }
예제 #2
0
        internal static Lambda GetConversionLambda(RedwoodType from, RedwoodType to)
        {
            if (from.CSharpType == null)
            {
                // TODO: RedwoodType implicit conversions
                throw new NotImplementedException();
            }
            else if (to.CSharpType == null)
            {
                // CSharp type -> Redwood type
                // This shouldn't happen, I think?
                throw new NotImplementedException();
            }
            else
            {
                IEnumerable <MethodInfo> implicits =
                    from.CSharpType.GetTypeInfo().GetDeclaredMethods("op_Implicit");
                MethodInfo conversion = implicits
                                        .Where(method => method.ReturnType == to.CSharpType)
                                        .FirstOrDefault();

                if (conversion == null)
                {
                    throw new NotImplementedException();
                }

                return(new ExternalLambda(null, conversion));
            }
        }
예제 #3
0
        internal static RedwoodType GetForLambdaArgsTypes(
            Type type, // ExternalLambda, InternalLambda, etc
            RedwoodType returnType,
            RedwoodType[] paramTypes)
        {
            List <RedwoodType> signature = new List <RedwoodType>();

            signature.AddRange(paramTypes);
            signature.Add(returnType);
            // This works because each RedwoodType is unique; referential equality
            // is all that is needed
            ImmutableList <RedwoodType> signatureImmutable = signature.ToImmutableList();

            if (lambdaTypes.ContainsKey(signatureImmutable))
            {
                RedwoodType res = lambdaTypes[signatureImmutable].FirstOrDefault(t => t.CSharpType == type);
                if (res != null)
                {
                    return(res);
                }
            }
            else
            {
                lambdaTypes[signatureImmutable] = new List <RedwoodType>();
            }

            RedwoodType redwoodType = new RedwoodType();

            redwoodType.CSharpType       = type;
            redwoodType.GenericArguments = signature.ToArray();
            return(redwoodType);
        }
예제 #4
0
        internal static RedwoodType Make(ClassDefinition @class)
        {
            RedwoodType type = new RedwoodType();

            type.Name = @class.Name;
            return(type);
        }
예제 #5
0
        internal static RedwoodType Make(InterfaceDefinition @interface)
        {
            RedwoodType type = new RedwoodType();

            type.Name        = @interface.Name;
            type.IsInterface = true;
            return(type);
        }
예제 #6
0
        internal static string GetNameOfConversionToType(string typename)
        {
            if (RedwoodType.TryGetSpecialMappedType(typename, out RedwoodType type))
            {
                return("as_" + type.Name);
            }

            return("as_" + typename);
        }
예제 #7
0
        public static RedwoodType GetForCSharpType(Type type)
        {
            if (!typeAdaptors.ContainsKey(type))
            {
                typeAdaptors[type] = new RedwoodType(type);
                typeAdaptors[type].InitInterfaceIfNecessary();
            }

            return(typeAdaptors[type]);
        }
예제 #8
0
 internal static RedwoodType[] GetTypesFromMethodInfo(MethodInfo methodInfo)
 {
     ParameterInfo[] parameters = methodInfo.GetParameters();
     RedwoodType[]   types      = new RedwoodType[parameters.Length];
     for (int i = 0; i < parameters.Length; i++)
     {
         types[i] = RedwoodType.GetForCSharpType(parameters[i].ParameterType);
     }
     return(types);
 }
예제 #9
0
        internal static int[] GetSlotMapsToInterface(RedwoodType from, RedwoodType to)
        {
            // We have to map to an interface, otherwise we're just
            // shoving things where they don't belong
            if (!to.IsInterface)
            {
                throw new NotImplementedException();
            }

            // We want to fill up every slot up to the overloads, which are
            // packed at the end of the class
            // TODO: This is a bad way of counting overloads. It checks whether
            // a given overload index is "self referential", meaning that it's the
            // only option, in which case it would not constitute a "LambdaGroup"
            int numOverloads = to.overloadsMap
                               .Where(kv => kv.Key != kv.Value.Item2[0])
                               .Count();

            int[] slotsToUse = new int[to.numSlots - numOverloads];

            foreach (KeyValuePair <string, int> member in to.slotMap)
            {
                string name = member.Key;
                int    slot = member.Value;

                RedwoodType slotType = to.slotTypes[slot];
                if (slotType != null && slotType.CSharpType == typeof(LambdaGroup))
                {
                    Tuple <RedwoodType[][], int[]> overloadSlots = to.overloadsMap[slot];
                    for (int i = 0; i < overloadSlots.Item2.Length; i++)
                    {
                        int           overloadMemberSlot = overloadSlots.Item2[i];
                        RedwoodType[] overloadArgTypes   = overloadSlots.Item1[i];

                        slotsToUse[overloadMemberSlot] = from.GetSlotNumberForOverload(name, overloadArgTypes);
                    }
                }
                else if (slotType != null && typeof(Lambda).IsAssignableFrom(slotType.CSharpType))
                {
                    slotsToUse[slot] = from.GetSlotNumberForOverload(
                        name,
                        slotType.GenericArguments
                        .SkipLast(1)
                        .ToArray()
                        );
                }
                else
                {
                    // TODO: This case should only be hit for the this keyword
                    slotsToUse[slot] = from.slotMap[name];
                }
            }

            return(slotsToUse);
        }
예제 #10
0
        internal RedwoodType AncestorWithImplicitConversion(RedwoodType type)
        {
            int         slot   = implicitConversionMap[type];
            RedwoodType walker = this;

            while (walker.BaseType != null && walker.BaseType.numSlots > slot)
            {
                walker = walker.BaseType;
            }
            return(walker);
        }
예제 #11
0
        internal static bool TryResolve(
            object target,
            RedwoodType targetTypeHint,
            string name,
            out object result)
        {
            if (TryResolveMember(target, targetTypeHint, name, target == null, out result))
            {
                return(true);
            }

            if (TryResolveMethod(target, targetTypeHint, name, false, out MethodInfo[] group))
예제 #12
0
        public int AncestorCount(RedwoodType type)
        {
            RedwoodType walker = this;
            int         count  = 0;

            while (walker != null && walker != type)
            {
                count++;
                walker = walker.BaseType;
            }
            return(count);
        }
예제 #13
0
 internal static RedwoodType GetTypeOf(object o)
 {
     if (o == null)
     {
         return(null);
     }
     else if (o is RedwoodObject rwo)
     {
         return(rwo.Type);
     }
     else
     {
         return(RedwoodType.GetForCSharpType(o.GetType()));
     }
 }
예제 #14
0
 internal static RedwoodType[] GetTypesFromArgs(object[] args)
 {
     RedwoodType[] types = new RedwoodType[args.Length];
     for (int i = 0; i < types.Length; i++)
     {
         if (args[i] is RedwoodObject o)
         {
             types[i] = o.Type;
         }
         else
         {
             types[i] = RedwoodType.GetForCSharpType(args[i].GetType());
         }
     }
     return(types);
 }
예제 #15
0
        internal RedwoodType GetGenericSpecialization(RedwoodType[] genericArgs)
        {
            RedwoodType newType = new RedwoodType();

            newType.Name       = Name;
            newType.CSharpType = CSharpType;
            // TODO: Base type with generic specialization?
            newType.BaseType         = BaseType;
            newType.GenericArguments = genericArgs;
            newType.Constructor      = Constructor;
            // TODO: Some of these will need generic specialization
            newType.implicitConversionMap = implicitConversionMap;
            newType.slotMap      = slotMap;
            newType.slotTypes    = slotTypes;
            newType.overloadsMap = overloadsMap;
            return(newType);
        }
예제 #16
0
        static RedwoodType()
        {
            specialMappedTypes.Add("?", null);

            specialMappedTypes.Add("int", GetForCSharpType(typeof(int)));
            specialMappedTypes.Add("string", GetForCSharpType(typeof(string)));
            specialMappedTypes.Add("double", GetForCSharpType(typeof(double)));
            specialMappedTypes.Add("bool", GetForCSharpType(typeof(bool)));
            specialMappedTypes.Add("object", GetForCSharpType(typeof(object)));

            NullType.staticSlotMap = new Dictionary <string, int>();
            NullType.staticSlotMap[RuntimeUtil.NameForOperator(BinaryOperator.Equals)]    = 0;
            NullType.staticSlotMap[RuntimeUtil.NameForOperator(BinaryOperator.NotEquals)] = 1;
            NullType.staticSlotTypes = new RedwoodType[]
            {
                RedwoodType.GetForLambdaArgsTypes(
                    typeof(InPlaceLambda),
                    RedwoodType.GetForCSharpType(typeof(bool)),
                    new RedwoodType[] { null, null }
                    ),
                RedwoodType.GetForLambdaArgsTypes(
                    typeof(InPlaceLambda),
                    RedwoodType.GetForCSharpType(typeof(bool)),
                    new RedwoodType[] { null, null }
                    )
            };

            NullType.staticLambdas = new Lambda[] {
                new InPlaceLambda(
                    new RedwoodType[] { null, null },
                    GetForCSharpType(typeof(bool)),
                    new InPlaceLambdaExecutor((stack, locs) => {
                    return(stack[locs[0]] == null && stack[locs[1]] == null);
                })
                    ),
                new InPlaceLambda(
                    new RedwoodType[] { null, null },
                    GetForCSharpType(typeof(bool)),
                    new InPlaceLambdaExecutor((stack, locs) => {
                    return(stack[locs[0]] != null || stack[locs[1]] != null);
                })
                    )
            };
        }
예제 #17
0
        public bool IsAssignableFrom(RedwoodType type)
        {
            // Any type of variable can be filled with null
            if (type == NullType)
            {
                return(true);
            }

            if (GenericArguments != null)
            {
                if (type.GenericArguments != null &&
                    type.GenericArguments.Length != GenericArguments.Length)
                {
                    return(false);
                }

                // Use referential equality since a RedwoodType should
                // only exist once with a certain set of generic type
                // arguments.
                for (int i = 0; i < GenericArguments.Length; i++)
                {
                    if (GenericArguments[i] != type.GenericArguments[i])
                    {
                        return(false);
                    }
                }
            }
            if (type.CSharpType != null)
            {
                return(IsAssignableFrom(type.CSharpType));
            }

            RedwoodType walker = this;

            // TODO: will this be problematic for inheriting generic
            // arguments?
            while (walker != null && walker != type)
            {
                walker = walker.BaseType;
            }

            return(type == walker);
        }
예제 #18
0
        public bool HasImplicitConversion(RedwoodType type)
        {
            if (CSharpType == null)
            {
                return(implicitConversionMap.ContainsKey(type));
            }

            IEnumerable <MethodInfo> implicits =
                CSharpType.GetTypeInfo().GetDeclaredMethods("op_Implicit");

            return(implicits.Any(info =>
            {
                ParameterInfo[] parameters = info.GetParameters();
                return parameters.Length == 1 &&
                parameters[0].ParameterType != CSharpType &&
                info.ReturnType == type.CSharpType;
            }
                                 ));
        }
예제 #19
0
        internal void SelectOverloads(RedwoodType[] argumentTypes)
        {
            bool[]          candidates = new bool[infos.Length];
            RedwoodType[][] overloads  = new RedwoodType[infos.Length][];
            for (int i = 0; i < infos.Length; i++)
            {
                overloads[i] = RuntimeUtil.GetTypesFromMethodInfo(infos[i]);
            }
            RuntimeUtil.SelectBestOverloads(argumentTypes, overloads, candidates);

            List <MethodInfo> selectedInfos = new List <MethodInfo>();

            for (int i = 0; i < candidates.Length; i++)
            {
                if (candidates[i])
                {
                    selectedInfos.Add(infos[i]);
                }
            }
            infos = selectedInfos.ToArray();
        }
예제 #20
0
        private static Lambda SelectOverloads(RedwoodType[] args, Lambda lambda, bool single)
        {
            RedwoodType[][] overloads;
            List <Lambda>   lambdas = new List <Lambda>();

            if (lambda is LambdaGroup e)
            {
                overloads = new RedwoodType[e.lambdas.Length][];
                for (int i = 0; i < overloads.Length; i++)
                {
                    overloads[i] = e.lambdas[i].ExpectedArgs.ToArray();
                    lambdas.Add(e.lambdas[i]);
                }
            }
            else
            {
                overloads = new RedwoodType[][] { lambda.ExpectedArgs.ToArray() };
                lambdas.Add(lambda);
            }
            bool[] candidates = new bool[overloads.Length];
            SelectBestOverloads(args, overloads, candidates);


            for (int i = candidates.Length - 1; i >= 0; i--)
            {
                if (!candidates[i])
                {
                    lambdas.RemoveAt(i);
                }
            }

            if (single)
            {
                return(CanonicalizeLambdas(lambdas.FirstOrDefault()));
            }
            return(CanonicalizeLambdas(lambdas.ToArray()));
        }
예제 #21
0
        internal static Type EmitInterfaceProxyType(RedwoodType type, Type @interface)
        {
            TypeBuilder tb = interfaceModules.DefineType(
                @interface.Name + "RedwoodProxy",
                TypeAttributes.Public | TypeAttributes.AutoClass | TypeAttributes.AnsiClass,
                typeof(object),
                new Type[] { @interface });

            FieldBuilder fb = tb.DefineField("proxy", typeof(object[]), FieldAttributes.Private);

            ConstructorBuilder cb = tb.DefineConstructor(
                MethodAttributes.Public |
                MethodAttributes.HideBySig |
                MethodAttributes.SpecialName |
                MethodAttributes.RTSpecialName,
                CallingConventions.HasThis,
                new Type[] { typeof(object[]) }
                );


            ILGenerator constructorGenerator = cb.GetILGenerator();
            // Call our base constructor
            ConstructorInfo objectConstructor = typeof(object).GetConstructor(new Type[] { });

            constructorGenerator.Emit(OpCodes.Ldarg_0);
            constructorGenerator.Emit(OpCodes.Call, objectConstructor);

            // Load this, then load arg 1, then set the local field
            constructorGenerator.Emit(OpCodes.Ldarg_0);
            constructorGenerator.Emit(OpCodes.Ldarg_1);
            constructorGenerator.Emit(OpCodes.Stfld, fb);

            constructorGenerator.Emit(OpCodes.Ret);

            MethodInfo runMethod = typeof(Lambda).GetMethod("Run");

            foreach (MethodInfo method in @interface.GetMethods())
            {
                Type[] paramTypes = method
                                    .GetParameters()
                                    .Select(param => param.ParameterType)
                                    .ToArray();

                // The method is on an interface so it is guaranteed
                // to have the abstract tag so we have to reverse that
                MethodBuilder mb = tb.DefineMethod(
                    method.Name,
                    method.Attributes ^ MethodAttributes.Abstract,
                    method.ReturnType,
                    paramTypes
                    );
                int numberOfArguments = method.GetParameters().Length;

                // The index into our proxy object array holding the overload
                int index = type.GetSlotNumberForOverload(
                    method.Name,
                    paramTypes
                    .Select(type => RedwoodType.GetForCSharpType(type))
                    .ToArray()
                    );

                ILGenerator generator = mb.GetILGenerator();
                generator.DeclareLocal(typeof(int));

                // Let's load the proxy object because we're going
                // to be accessing on it a little later
                generator.Emit(OpCodes.Ldarg_0);
                generator.Emit(OpCodes.Ldfld, fb);

                // Now go fishing for our overload
                generator.Emit(OpCodes.Ldc_I4, index);
                generator.Emit(OpCodes.Ldelem_Ref);
                // ILSpy says we do this check now -- I guess the actual throw
                // is handled by the runtime?
                generator.Emit(OpCodes.Isinst, typeof(Lambda));

                // Create an array to pass as the params argument
                generator.Emit(OpCodes.Ldc_I4, numberOfArguments);
                generator.Emit(OpCodes.Newarr, typeof(object));

                // Set each argument on the params array
                for (int i = 0; i < numberOfArguments; i++)
                {
                    // Get a copy of the array
                    generator.Emit(OpCodes.Dup);
                    // Index
                    generator.Emit(OpCodes.Ldc_I4, i);
                    // Element
                    generator.Emit(OpCodes.Ldarg, i + 1);

                    // Since we're going into an object array, we need
                    // to box our value types
                    if (paramTypes[i].IsValueType)
                    {
                        // TODO: is there a separate boxed type from value type?
                        generator.Emit(OpCodes.Box, paramTypes[i]);
                    }

                    // Set
                    generator.Emit(OpCodes.Stelem_Ref);
                }

                generator.Emit(OpCodes.Callvirt, runMethod);
                if (method.ReturnType.IsValueType)
                {
                    generator.Emit(OpCodes.Unbox_Any, method.ReturnType);
                }

                // For some reason, the compiler likes to store and load before
                // returning, so lets do it here too
                // TODO: does this look different for non-value types?
                generator.Emit(OpCodes.Stloc_0);
                generator.Emit(OpCodes.Ldloc_0);

                generator.Emit(OpCodes.Ret);
            }

            return(tb.CreateType());
        }
예제 #22
0
 internal static bool TryGetSpecialMappedType(string name, out RedwoodType type)
 {
     return(specialMappedTypes.TryGetValue(name, out type));
 }
예제 #23
0
        static MemberResolver()
        {
            primitiveOperators = new Dictionary <Type, Dictionary <OperatorDescriptor, Lambda> >();

            // int operators
            RedwoodType boolType = RedwoodType.GetForCSharpType(typeof(bool));
            RedwoodType type     = RedwoodType.GetForCSharpType(typeof(int));

            RedwoodType[] unaryOperatorsType  = new RedwoodType[] { type };
            RedwoodType[] binaryOperatorsType = new RedwoodType[] { type, type };


            Dictionary <OperatorDescriptor, Lambda> intOperators =
                new Dictionary <OperatorDescriptor, Lambda>();

            intOperators.Add(
                new OperatorDescriptor(UnaryOperator.BitwiseNegate),
                new InPlaceLambda(unaryOperatorsType, type,
                                  (object[] stack, int[] locs) => ~(int)stack[locs[0]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(UnaryOperator.Negative),
                new InPlaceLambda(unaryOperatorsType, type,
                                  (object[] stack, int[] locs) => - (int)stack[locs[0]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.Multiply),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] * (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.Divide),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] / (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.Modulus),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] % (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.Add),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] + (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.Subtract),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] - (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.LeftShift),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] << (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.RightShift),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] >> (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.LessThan),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] < (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.GreaterThan),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] > (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.LessThanOrEquals),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] <= (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.GreaterThanOrEquals),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] >= (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.Equals),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] == (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.NotEquals),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] != (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.BitwiseAnd),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] & (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.BitwiseXor),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] ^ (int)stack[locs[1]]
                                  )
                );

            intOperators.Add(
                new OperatorDescriptor(BinaryOperator.BitwiseOr),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (int)stack[locs[0]] | (int)stack[locs[1]]
                                  )
                );

            primitiveOperators[typeof(int)] = intOperators;

            // string operators
            type = RedwoodType.GetForCSharpType(typeof(string));

            Dictionary <OperatorDescriptor, Lambda> stringOperators =
                new Dictionary <OperatorDescriptor, Lambda>();

            stringOperators.Add(
                new OperatorDescriptor(BinaryOperator.Add),
                new LambdaGroup(new InPlaceLambda[]
            {
                new InPlaceLambda(
                    new RedwoodType[] { type, type },
                    type,
                    (object[] stack, int[] locs) => (string)stack[locs[0]] + (string)stack[locs[1]]),
                new InPlaceLambda(
                    new RedwoodType[] { type, RedwoodType.GetForCSharpType(typeof(int)) },
                    type,
                    (object[] stack, int[] locs) => (string)stack[locs[0]] + (int)stack[locs[1]]),
                new InPlaceLambda(
                    new RedwoodType[] { type, RedwoodType.GetForCSharpType(typeof(double)) },
                    type,
                    (object[] stack, int[] locs) => (string)stack[locs[0]] + (double)stack[locs[1]]),
                new InPlaceLambda(
                    new RedwoodType[] { type, RedwoodType.GetForCSharpType(typeof(bool)) },
                    type,
                    (object[] stack, int[] locs) => (string)stack[locs[0]] + (bool)stack[locs[1]])
            })
                );

            primitiveOperators[typeof(string)] = stringOperators;

            type = RedwoodType.GetForCSharpType(typeof(double));
            unaryOperatorsType  = new RedwoodType[] { type };
            binaryOperatorsType = new RedwoodType[] { type, type };

            Dictionary <OperatorDescriptor, Lambda> doubleOperators =
                new Dictionary <OperatorDescriptor, Lambda>();

            doubleOperators.Add(
                new OperatorDescriptor(UnaryOperator.Negative),
                new InPlaceLambda(unaryOperatorsType, type,
                                  (object[] stack, int[] locs) => - (double)stack[locs[0]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.Multiply),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] * (double)stack[locs[1]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.Divide),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] / (double)stack[locs[1]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.Modulus),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] % (double)stack[locs[1]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.Add),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] + (double)stack[locs[1]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.Subtract),
                new InPlaceLambda(binaryOperatorsType, type,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] - (double)stack[locs[1]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.LessThan),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] < (double)stack[locs[1]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.GreaterThan),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] > (double)stack[locs[1]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.LessThanOrEquals),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] <= (double)stack[locs[1]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.GreaterThanOrEquals),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] >= (double)stack[locs[1]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.Equals),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] == (double)stack[locs[1]]
                                  )
                );

            doubleOperators.Add(
                new OperatorDescriptor(BinaryOperator.NotEquals),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (double)stack[locs[0]] != (double)stack[locs[1]]
                                  )
                );

            primitiveOperators[typeof(double)] = doubleOperators;

            Dictionary <OperatorDescriptor, Lambda> boolOperators =
                new Dictionary <OperatorDescriptor, Lambda>();

            binaryOperatorsType = new RedwoodType[] { boolType, boolType };

            boolOperators.Add(
                new OperatorDescriptor(BinaryOperator.Equals),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (bool)stack[locs[0]] == (bool)stack[locs[1]]
                                  )
                );

            boolOperators.Add(
                new OperatorDescriptor(BinaryOperator.NotEquals),
                new InPlaceLambda(binaryOperatorsType, boolType,
                                  (object[] stack, int[] locs) => (bool)stack[locs[0]] != (bool)stack[locs[1]]
                                  )
                );

            primitiveOperators[typeof(bool)] = boolOperators;
        }
예제 #24
0
        /// <summary>
        /// For the most part, the MemberResolver is able to resolve the
        /// methods, fields, and properties on C# types, but populating the
        /// slots for an interface will allow us to map to a specific order
        /// needed by the interface stitching done by the Emitter.
        /// </summary>
        private void InitInterfaceIfNecessary()
        {
            if (CSharpType == null || !CSharpType.IsInterface)
            {
                return;
            }

            IsInterface = true;

            var overloads = new Dictionary <string, Tuple <List <RedwoodType[]>, List <int> > >();
            int slot      = 0;
            List <RedwoodType> slotTypes = new List <RedwoodType>();

            slotMap      = new Dictionary <string, int>();
            overloadsMap = new Dictionary <int, Tuple <RedwoodType[][], int[]> >();

            foreach (MethodInfo method in CSharpType.GetMethods())
            {
                RedwoodType[] parameterTypes = method
                                               .GetParameters()
                                               .Select(param => RedwoodType.GetForCSharpType(param.ParameterType))
                                               .ToArray();
                if (!overloads.ContainsKey(method.Name))
                {
                    overloads[method.Name] = new Tuple <List <RedwoodType[]>, List <int> >(
                        new List <RedwoodType[]>(),
                        new List <int>()
                        );
                }

                slotTypes.Add(RedwoodType.GetForLambdaArgsTypes(
                                  typeof(ExternalLambda),
                                  RedwoodType.GetForCSharpType(method.ReturnType),
                                  parameterTypes
                                  ));

                overloads[method.Name].Item1.Add(parameterTypes);
                overloads[method.Name].Item2.Add(slot);
                slot++;
            }

            // For interfaces, the methods are all at the beginnings, overloads
            // all at the end
            foreach (string overloadName in overloads.Keys)
            {
                // TODO: Do we care about the overload type here?
                int[] overloadSlots = overloads[overloadName].Item2.ToArray();
                slotTypes.Add(RedwoodType
                              .GetForCSharpType(typeof(LambdaGroup))
                              .GetGenericSpecialization(
                                  overloadSlots
                                  .Select(slot => slotTypes[slot])
                                  .ToArray()
                                  )
                              );;


                slotMap[overloadName] = slot;
                overloadsMap[slot]    = new Tuple <RedwoodType[][], int[]>(
                    overloads[overloadName].Item1.ToArray(),
                    overloadSlots
                    );
                slot++;
            }

            numSlots       = slot;
            this.slotTypes = slotTypes.ToArray();
            // Technically a proxy type can occur from any redwood type to
            // any C# interface, but we emit for the interface we created
            // and then reuse it so that we can keep a cceiling on the
            // number of these classes that we create
            proxyType = Emitter.EmitInterfaceProxyType(this, CSharpType);
            ConstructorInfo constructor = proxyType.GetConstructor(new Type[] { typeof(object[]) });

            Constructor = new ExternalLambda(this, constructor);
        }