private void AddResultType(PlannedClass contextEntry, Type type) { if (type.IsClass && type.IsAbstract) { if (!plan.Exists(e => e.BaseClass == type)) { plan.Add( new PlannedClass { ClassName = MakeImplName(type), BaseClass = type }); } } else if (type.IsInterface) { if (contextEntry == null) { plan.Add( new PlannedClass { ClassName = MakeImplName(type), BaseClass = typeof(object), Contracts = { type } }); } else if (!contextEntry.Contracts.Contains(type)) { contextEntry.Contracts.Add(type); } } }
private EmitSyntax EmitFactoryCode( EmitSyntax emit, PlannedClass contextPlannedClass, Type type, bool nullAllowed) { if (type == typeof(void)) { } else if (type == typeof(int)) { emit = emit.Ldc_I4_0(); } else if (type.IsValueType) { var resultType = emit.Types.Import(type); var resultLoc = emit.Locals.Generate("result"); emit = emit .Local(resultLoc, resultType) .Ldloca(resultLoc.GetRef()) .Initobj(resultType) .Ldloc(resultLoc.GetRef()) ; } else if (nullAllowed) { emit.Ldnull(); } else if (!type.IsAbstract && !type.IsInterface) { emit = emit.Newobj( emit.Types.Import(type)); } else if (contextPlannedClass != null && contextPlannedClass.Implements(type)) { emit = emit.Ldarg(0); } else if (plan.Exists(e => e.Implements(type))) { var otherEntry = plan.Find(e => e.Implements(type)); emit = emit.Newobj( emit.Types.Class_( ClassName.Parse( otherEntry.ClassName))); } else { throw new InvalidOperationException( "Internal error: non-planned abstract result type"); } return(emit); }
private void ExpandEntry(PlannedClass entry) { var type = entry.BaseClass; const BindingFlags flags = BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.Instance; while (type != typeof(object)) { foreach (var method in type.GetMethods(flags)) { if (!method.IsAbstract) { continue; } entry.Methods.Add(method); if (forceNonNullResult(method)) { AddResultType(entry, method.ReturnType); } } type = type.BaseType; } for (int i = 0; i != entry.Contracts.Count; ++i) { var c = entry.Contracts[i]; entry.Contracts.AddRange(c.GetInterfaces().Except(entry.Contracts)); foreach (var method in c.GetMethods()) { if (forceNonNullResult(method)) { AddResultType(entry, method.ReturnType); } entry.Methods.Add(method); } } }
private CilDocumentSyntax GenerateImpl(PlannedClass entry, CilDocumentSyntax cil) { ClassExtendsSyntax wantBaseClass = cil.Class_() .Public .Named(entry.ClassName) ; var baseClassRef = cil.Types.Import(entry.BaseClass); ClassImplementsSyntax wantContract = wantBaseClass .Extends(baseClassRef); var baseCtor = entry.BaseClass.GetConstructor(Type.EmptyTypes); Ref<Methods> baseCtorRef; if (baseCtor != null) { baseCtorRef = cil.Methods.Import(baseCtor); } else { baseCtorRef = null; } foreach (Type c in entry.Contracts) { wantContract = wantContract.Implements(cil.Types.Import(c)); } ClassSyntax classCode = wantContract; classCode = classCode .Method() .Public.Instance .Returning(classCode.Types.Void) .Named(".ctor") .BeginArgs().EndArgs() .BeginBody() .Do(il => { if (baseCtorRef != null) { il = il .Ldarg(0) .Callvirt(baseCtorRef); } return il; }) .Ret() .EndBody() ; foreach (var method in entry.Methods) { WantArgsBase wantArgs = classCode.Method() .Private.Hidebysig.Newslot .Virtual.Final.Instance .Returning(classCode.Types.Import(method.ReturnType)) .Named(method.DeclaringType + "." + method.Name) .BeginArgs(); foreach (var parameter in method.GetParameters()) { wantArgs = wantArgs.Argument( classCode.Types.Import(parameter.ParameterType), wantArgs.Args.Generate(parameter.Name)); } var emit = wantArgs.EndArgs().BeginBody(); emit = emit.Override(emit.Methods.Import(method)); emit = EmitFactoryCode( emit, entry, method.ReturnType, !forceNonNullResult(method)); classCode = emit.Ret().EndBody(); } return classCode.EndClass(); }
private EmitSyntax EmitFactoryCode( EmitSyntax emit, PlannedClass contextPlannedClass, Type type, bool nullAllowed) { if (type == typeof(void)) { } else if (type == typeof(int)) { emit = emit.Ldc_I4_0(); } else if (type.IsValueType) { var resultType = emit.Types.Import(type); var resultLoc = emit.Locals.Generate("result"); emit = emit .Local(resultLoc, resultType) .Ldloca(resultLoc.GetRef()) .Initobj(resultType) .Ldloc(resultLoc.GetRef()) ; } else if (nullAllowed) { emit.Ldnull(); } else if (!type.IsAbstract && !type.IsInterface) { emit = emit.Newobj( emit.Types.Import(type)); } else if (contextPlannedClass != null && contextPlannedClass.Implements(type)) { emit = emit.Ldarg(0); } else if (plan.Exists(e => e.Implements(type))) { var otherEntry = plan.Find(e => e.Implements(type)); emit = emit.Newobj( emit.Types.Class_( ClassName.Parse( otherEntry.ClassName))); } else { throw new InvalidOperationException( "Internal error: non-planned abstract result type"); } return emit; }
private CilDocumentSyntax GenerateImpl(PlannedClass entry, CilDocumentSyntax cil) { ClassExtendsSyntax wantBaseClass = cil.Class_() .Public .Named(entry.ClassName) ; var baseClassRef = cil.Types.Import(entry.BaseClass); ClassImplementsSyntax wantContract = wantBaseClass .Extends(baseClassRef); var baseCtor = entry.BaseClass.GetConstructor(Type.EmptyTypes); Ref <Methods> baseCtorRef; if (baseCtor != null) { baseCtorRef = cil.Methods.Import(baseCtor); } else { baseCtorRef = null; } foreach (Type c in entry.Contracts) { wantContract = wantContract.Implements(cil.Types.Import(c)); } ClassSyntax classCode = wantContract; classCode = classCode .Method() .Public.Instance .Returning(classCode.Types.Void) .Named(".ctor") .BeginArgs().EndArgs() .BeginBody() .Do(il => { if (baseCtorRef != null) { il = il .Ldarg(0) .Callvirt(baseCtorRef); } return(il); }) .Ret() .EndBody() ; foreach (var method in entry.Methods) { WantArgsBase wantArgs = classCode.Method() .Private.Hidebysig.Newslot .Virtual.Final.Instance .Returning(classCode.Types.Import(method.ReturnType)) .Named(method.DeclaringType + "." + method.Name) .BeginArgs(); foreach (var parameter in method.GetParameters()) { wantArgs = wantArgs.Argument( classCode.Types.Import(parameter.ParameterType), wantArgs.Args.Generate(parameter.Name)); } var emit = wantArgs.EndArgs().BeginBody(); emit = emit.Override(emit.Methods.Import(method)); emit = EmitFactoryCode( emit, entry, method.ReturnType, !forceNonNullResult(method)); classCode = emit.Ret().EndBody(); } return(classCode.EndClass()); }