public void write_method() { // SAMPLE: write-new-method // Configures the code generation rules // and policies var rules = new GenerationRules("GeneratedNamespace"); // Adds the "now : DateTime" variable rule to // our generated code rules.Sources.Add(new NowTimeVariableSource()); // Start the definition for a new generated assembly var assembly = new GeneratedAssembly(rules); // Add a new generated type called "WhatTimeIsIt" that will // implement the var type = assembly.AddType("WhatTimeIsIt", typeof(ISaySomething)); // Getting the definition for the method named "Speak" var method = type.MethodFor(nameof(ISaySomething.Speak)); // Adding a frame that calls the NowSpeaker.Speak() method and // adding it to the generated method var @call = new MethodCall(typeof(NowSpeaker), nameof(NowSpeaker.Speak)); method.Frames.Add(@call); // Compile the new code! assembly.CompileAll(); // ENDSAMPLE // Write the generated code to the console here _output.WriteLine(type.SourceCode); }
public void generate_dynamic_types_with_no_fields() { var rules = new GenerationRules("Lamar.Compilation"); var assembly = new GeneratedAssembly(rules); var adder = assembly.AddType("Adder", typeof(INumberGenerator)); adder.MethodFor("Generate").Frames.Append <AddFrame>(); var multiplier = assembly.AddType("Multiplier", typeof(INumberGenerator)); multiplier.MethodFor(nameof(INumberGenerator.Generate)) .Frames.Append <MultiplyFrame>(); assembly.CompileAll(); Activator.CreateInstance(adder.CompiledType) .As <INumberGenerator>() .Generate(3, 4).ShouldBe(7); Activator.CreateInstance(multiplier.CompiledType) .As <INumberGenerator>() .Generate(3, 4).ShouldBe(12); adder.SourceCode.ShouldContain("public class Adder"); multiplier.SourceCode.ShouldContain("public class Multiplier"); }
public void generate_code_with_base_type_that_is_generic() { var assembly = new GeneratedAssembly(new GenerationRules()); var type = assembly.AddType("SomeClass", typeof(ClassWithGenericParameter <string>)); assembly.CompileAll(); }
/// <summary> /// Generate a new method for the basic base class. The base class "TObject" should /// only have a single declared method /// </summary> /// <param name="configuration"></param> /// <param name="rules"></param> /// <typeparam name="TObject"></typeparam> /// <returns></returns> public static CodegenResult <TObject> ForBaseOf <TObject>(Action <GeneratedType, GeneratedMethod> configuration, GenerationRules rules = null) { if (typeof(TObject).GetMethods().Length != 1) { throw new ArgumentOutOfRangeException(nameof(TObject), "The supplied base type or interface can only have exactly one declared method"); } rules = rules ?? new GenerationRules("LamarCodegenScenario"); var assembly = new GeneratedAssembly(rules); if (typeof(TObject).IsGenericType) { foreach (var genericTypeArgument in typeof(TObject).GenericTypeArguments) { rules.Assemblies.Fill(genericTypeArgument.Assembly); } } var generatedType = assembly.AddType("GeneratedType", typeof(TObject)); var method = generatedType.Methods.Single(); configuration(generatedType, method); assembly.CompileAll(); return(new CodegenResult <TObject>(generatedType.CreateInstance <TObject>(), generatedType.SourceCode)); }
/// <summary> /// Generate a new method for the basic base class. The base class "TObject" should /// only have a single declared method /// </summary> /// <param name="configuration"></param> /// <param name="rules"></param> /// <typeparam name="TObject"></typeparam> /// <returns></returns> private static CodegenResult <TObject> ForBaseOf <TObject>(Action <GeneratedType, GeneratedMethod> configuration) { if (typeof(TObject).GetMethods().Length != 1) { throw new ArgumentOutOfRangeException(nameof(TObject), "The supplied base type or interface can only have exactly one declared method"); } var rules = Builder.Rules(); var assembly = new GeneratedAssembly(rules); var generatedType = assembly.AddType("Tests", "GeneratedType", typeof(TObject)); var method = generatedType.Methods.Single(); configuration(generatedType, method); var generator = new AssemblyGenerator(new NullLogger <AssemblyGenerator>(), new InMemoryOnlyCompileStrategy(new NullLogger <InMemoryOnlyCompileStrategy>())); if (typeof(TObject).IsGenericType) { foreach (var genericTypeArgument in typeof(TObject).GenericTypeArguments) { generator.ReferenceAssembly(genericTypeArgument.Assembly); } } assembly.CompileAll(generator); return(new CodegenResult <TObject>(generatedType.CreateInstance <TObject>(), generatedType.SourceCode)); }
public void generate_code_with_base_type_that_is_generic_using_an_inner_type_as_the_parameter() { var assembly = new GeneratedAssembly(new GenerationRules()); var type = assembly.AddType("SomeClass", typeof(ClassWithGenericParameter <SomeInnerClass>)); assembly.CompileAll(); _output.WriteLine(type.SourceCode); }
public void can_use_Task_as_the_class_name() { var assembly = new GeneratedAssembly(new GenerationRules()); var type = assembly.AddType("Task", typeof(Thing)); var method = type.MethodFor("Do").Frames.Code("// stuff"); assembly.CompileAll(); _output.WriteLine(type.SourceCode); }
public void do_not_do_a_stackoverflow_here() { var assembly = new GeneratedAssembly(new GenerationRules("Jasper.Generated")); var type = assembly.AddType("MyGuy", typeof(IHandler)); var method = type.MethodFor("Go"); method.Frames.Add(new CustomFrame()); method.Frames.Add(new CustomFrame()); method.Frames.Add(new CustomFrame()); assembly.CompileAll(); }
public void write_footer_into_source_code() { var assembly = new GeneratedAssembly(new GenerationRules()); var type = assembly.AddType("SomeClass", typeof(ClassWithGenericParameter <SomeInnerClass>)); type.Footer = new OneLineComment("Hey, look at this!"); assembly.CompileAll(); type.SourceCode.ReadLines() .ShouldContain(" // Hey, look at this!"); _output.WriteLine(type.SourceCode); }
public async Task can_generate_method() { var assembly = new GeneratedAssembly(new GenerationRules("Jasper.Generated")); var generatedType = assembly.AddType("NumberGetter", typeof(INumberGetter)); generatedType.MethodFor("GetNumber").Add(new ReturnFive()); assembly.CompileAll(); var getter = generatedType.CreateInstance <INumberGetter>(); var number = await getter.GetNumber(); number.ShouldBe(5); }
public static Task Warmup() { if (_warmup == null) { _warmup = Task.Factory.StartNew(() => { var generatedAssembly = new GeneratedAssembly(new GenerationRules("Lamar.Generated")); generatedAssembly.AddType("Tracer", typeof(IStub)); generatedAssembly.CompileAll(); _warmup = Task.CompletedTask; }); } return(_warmup); }
public void CompileWithInlineServices(GeneratedAssembly assembly) { assembly.CompileAll(new ServiceVariableSource(ServiceGraph)); }
public void CompileWithInlineServices(GeneratedAssembly assembly) { assembly.CompileAll(ServiceGraph); }
public static void CompileAll(this GeneratedAssembly assembly) { assembly.CompileAll(new AssemblyGenerator(new NullLogger <AssemblyGenerator>(), new InMemoryOnlyCompileStrategy(new NullLogger <InMemoryOnlyCompileStrategy>()))); }
/// <summary> /// Given the specified <see cref="BlueprintApiOptions" /> will generate and compile an /// <see cref="IApiOperationExecutor" /> that can be used to execute any operation that /// has been identified by the model of the options passed. /// </summary> /// <param name="options">The configured options.</param> /// <param name="serviceProvider">The configured service provider.</param> /// <returns>An executor built from the given options and data model.</returns> public CodeGennedExecutor Build(BlueprintApiOptions options, IServiceProvider serviceProvider) { var model = options.Model; // We have multiple ways in which we work with generated assemblies, depending on context: // // - We are writing unit tests which create many pipelines (within Blueprint itself). Here we // would want to use in-memory compilation and assembly loading only // // - We have deployed an app using generated code. We want to use pre-compiled DLLs loaded as // part of the usual loading process. This is done by creating an assembly and PDB that is // deployed with the application and loaded below (see step 1) // // - We are in development. Here we wish to generate and load a new DLL on application startup and // store in the temp folder of the machine. This means the DLL is _not_ loaded as normal part // of .NET process and therefore we can (re)create at will on startup without worrying about // the existence of an existing DLL // 1. Try and find an already loaded assembly foreach (var loadedAssembly in AppDomain.CurrentDomain.GetAssemblies()) { if (loadedAssembly.GetName().Name == options.GenerationRules.AssemblyName) { // The assembly exists in the current domain, therefore it has either already been generated in this // process OR it has previously been compiled and loaded as part of normal assembly loading (pre-compiled // as part of dotnet publish) this._logger.LogInformation("Assembly {AssemblyName} already exists, using to create executor.", options.GenerationRules.AssemblyName); return(CreateFromAssembly(options, serviceProvider, model, loadedAssembly)); } } // 2. Do we have the DLL stored alongside this application but NOT loaded? var directory = Path.GetDirectoryName(typeof(ApiOperationExecutorBuilder).Assembly.Location); var assemblyPath = Path.Combine(directory, options.GenerationRules.AssemblyName) + ".dll"; if (File.Exists(assemblyPath)) { this._logger.LogInformation( "Assembly {AssemblyName} found at {AssemblyLocation}. Loading and using to create executor.", options.GenerationRules.AssemblyName, assemblyPath); var loadedPipelineDll = AssemblyLoadContext.Default.LoadFromAssemblyPath(assemblyPath); return(CreateFromAssembly(options, serviceProvider, model, loadedPipelineDll)); } // 2. We DO NOT have any existing DLLs. In that case we are going to generate the source code using our configured // middlewares and then hand off to AssemblyGenerator to compile and load the assembly (which may be in-memory, stored // to a temp folder or stored to the project output folder) this._logger.LogInformation("Building Blueprint API operation executor for {0} operations", options.Model.Operations.Count()); using var serviceScope = serviceProvider.CreateScope(); foreach (var middleware in options.MiddlewareBuilders) { this.Use(middleware); } var typeToCreationMappings = new Dictionary <Type, Func <Type> >(); // Start the definition for a new generated assembly var assembly = new GeneratedAssembly(options.GenerationRules); foreach (var operation in model.Operations) { this._references.Add(operation.OperationType.Assembly); } foreach (var a in this._references) { this._logger.LogDebug("Referencing assembly {0}", a.FullName); assembly.ReferenceAssembly(a); } foreach (var operation in model.Operations) { this._logger.LogDebug("Generating executor for {0}", operation.OperationType.FullName); var typeName = NormaliseTypeName(operation); var pipelineExecutorType = assembly.AddType( operation.OperationType.Namespace, typeName, typeof(IOperationExecutorPipeline)); // We need to set up a LoggerVariable once, to be shared between methods pipelineExecutorType.AllInjectedFields.Add(new LoggerVariable(typeName)); var executeMethod = pipelineExecutorType.MethodFor(nameof(IOperationExecutorPipeline.ExecuteAsync)); var executeNestedMethod = pipelineExecutorType.MethodFor(nameof(IOperationExecutorPipeline.ExecuteNestedAsync)); this.Generate(options, serviceProvider, executeMethod, operation, model, serviceScope, false); this.Generate(options, serviceProvider, executeNestedMethod, operation, model, serviceScope, true); typeToCreationMappings.Add( operation.OperationType, () => pipelineExecutorType.CompiledType); } this._logger.LogInformation("Compiling {0} pipeline executors", typeToCreationMappings.Count); assembly.CompileAll(serviceProvider.GetRequiredService <ICompileStrategy>()); this._logger.LogInformation("Done compiling {0} pipeline executors", typeToCreationMappings.Count); return(new CodeGennedExecutor( serviceProvider, model, assembly, typeToCreationMappings)); }