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