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() ); }
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)); } }
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); }
internal static RedwoodType Make(ClassDefinition @class) { RedwoodType type = new RedwoodType(); type.Name = @class.Name; return(type); }
internal static RedwoodType Make(InterfaceDefinition @interface) { RedwoodType type = new RedwoodType(); type.Name = @interface.Name; type.IsInterface = true; return(type); }
internal static string GetNameOfConversionToType(string typename) { if (RedwoodType.TryGetSpecialMappedType(typename, out RedwoodType type)) { return("as_" + type.Name); } return("as_" + typename); }
public static RedwoodType GetForCSharpType(Type type) { if (!typeAdaptors.ContainsKey(type)) { typeAdaptors[type] = new RedwoodType(type); typeAdaptors[type].InitInterfaceIfNecessary(); } return(typeAdaptors[type]); }
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); }
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); }
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); }
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))
public int AncestorCount(RedwoodType type) { RedwoodType walker = this; int count = 0; while (walker != null && walker != type) { count++; walker = walker.BaseType; } return(count); }
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())); } }
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); }
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); }
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); }) ) }; }
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); }
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; } )); }
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(); }
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())); }
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()); }
internal static bool TryGetSpecialMappedType(string name, out RedwoodType type) { return(specialMappedTypes.TryGetValue(name, out type)); }
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; }
/// <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); }