Beispiel #1
0
        /// <summary>
        ///   Runs the emitted assembly.
        /// </summary>
        private CompilationEditor[] GetAssemblyChildren(Assembly assembly)
        {
            // Find the SelfEdit attribute on assembly
            string attrFullName          = typeof(EditSelfAttribute).FullName;
            CustomAttributeData attrData = assembly.CustomAttributes.FirstOrDefault(x => x.AttributeType.FullName == attrFullName);

            if (attrData == null)
            {
                Report(Diagnostic.Create(LoadError, Location.None, "Could not find EditSelf attribute on compiled assembly."));
                return(null);
            }

            // Construct its args
            var editorTypes = (IReadOnlyList <CustomAttributeTypedArgument>)attrData.ConstructorArguments[0].Value;

            CompilationEditor[] editors = new CompilationEditor[editorTypes.Count];

            bool failed = false;

            for (int i = 0; i < editors.Length; i++)
            {
                if (Activator.CreateInstance(editorTypes[i].Value as Type, true) is CompilationEditor editor)
                {
                    editors[i] = editor;
                    continue;
                }

                Report(Diagnostic.Create(LoadError, Location.None, $"Could not create editor of type '{editorTypes[i].Value}'."));
                failed = true;
            }

            return(failed ? null : editors);
        }
        /// <summary>
        ///   Registers a new <paramref name="edit"/> that is to be applied to any <see cref="CSharpSyntaxTree"/>
        ///   found on the <see cref="CSharpCompilation"/>.
        /// </summary>
        /// <param name="editor"></param>
        /// <param name="edit"></param>
        public static void EditSyntaxTree(this CompilationEditor editor, SyntaxTreeEdit edit)
        {
            IList <SyntaxTreeEdit> GetDefaultValue()
            {
                editor.CompilationPipeline += EditCompilation;

                return(new LightList <SyntaxTreeEdit>());
            }

            CSharpCompilation EditCompilation(CSharpCompilation compilation, CancellationToken cancellationToken)
            {
                var edits = editor.Storage.Get <IList <SyntaxTreeEdit> >(SyntaxTreeKey);

                for (int i = 0; i < compilation.SyntaxTrees.Length; i++)
                {
                    CSharpSyntaxTree tree    = compilation.SyntaxTrees[i] as CSharpSyntaxTree;
                    CSharpSyntaxTree newTree = tree;

                    if (tree == null)
                    {
                        continue;
                    }

                    foreach (var treeEdit in edits)
                    {
                        newTree = treeEdit(newTree, compilation, cancellationToken);

                        if (newTree != null)
                        {
                            continue;
                        }

                        i--;
                        compilation = compilation.RemoveSyntaxTrees(tree);

                        goto NextTree;
                    }

                    compilation = compilation.ReplaceSyntaxTree(tree, newTree);

                    NextTree :;
                }

                return(compilation);
            }

            editor.Storage.GetOrAdd(SyntaxTreeKey, GetDefaultValue).Add(edit);
        }
Beispiel #3
0
        /// <summary>
        ///   Adds the given <paramref name="component"/> to the IL emission pipeline.
        /// </summary>
        /// <param name="editor"></param>
        /// <param name="component"></param>
        public static void EditIL(this CompilationEditor editor, PipelineComponent <EmitDelegate> component)
        {
            Pipeline <EmitDelegate> GetDefaultValue()
            {
                EmitDelegate Emit(EmitDelegate next)
                {
                    var pipeline = editor.Storage.Get <Pipeline <EmitDelegate> >(Key);
                    var del      = pipeline.MakeDelegate(next);

                    return(del);
                }

                CodeGeneratorContext.EmitPipeline += Emit;
                //editor.EmissionStart += ce => CodeGeneratorContext.EmitPipeline += Emit;
                //editor.EmissionEnd += ce => CodeGeneratorContext.EmitPipeline -= Emit;

                return(new Pipeline <EmitDelegate>());
            }

            editor.Storage.GetOrAdd(Key, GetDefaultValue).Add(component);
        }
Beispiel #4
0
        /// <summary>
        ///   Defines a feature on which the calling <see cref="CompilationEditor"/> is dependant.
        /// </summary>
        public static void DefineFeatureDependency(this CompilationEditor editor, string feature, string value = "True")
        {
            IDictionary <string, string> GetDefaultValue()
            {
                editor.GetRecomputationPipeline().Add(next =>
                {
                    return(opts =>
                    {
                        if (editor.SharedStorage.TryGet(Key, out IDictionary <string, string> features))
                        {
                            opts = opts.WithFeatures(opts.Features.Concat(features));
                        }

                        return next(opts);
                    });
                });

                return(new Dictionary <string, string>());
            }

            editor.SharedStorage.GetOrAdd(Key, GetDefaultValue)[feature] = value;
        }
Beispiel #5
0
        /// <summary>
        ///   Defines a constant to be used as a preprocessor symbol name when parsing syntax trees.
        /// </summary>
        public static void DefineConstant(this CompilationEditor editor, string constant)
        {
            IList <string> GetDefaultValue()
            {
                editor.GetRecomputationPipeline().Add(next =>
                {
                    return(opts =>
                    {
                        if (editor.SharedStorage.TryGet(Key, out IList <string> preprocessorSymbolNames))
                        {
                            opts = opts.WithPreprocessorSymbols(opts.PreprocessorSymbolNames.Concat(preprocessorSymbolNames));
                        }

                        return next(opts);
                    });
                });

                return(new LightList <string>());
            }

            editor.SharedStorage.GetOrAdd(Key, GetDefaultValue).Add(constant);
        }
        /// <summary>
        ///   Registers a new <paramref name="edit"/> that is to be applied to any <see cref="SyntaxNode"/>
        ///   found on the <see cref="CSharpCompilation"/>.
        /// </summary>
        /// <param name="editor"></param>
        /// <param name="edit"></param>
        public static void EditSyntax(this CompilationEditor editor, SyntaxEdit edit)
        {
            IList <SyntaxEdit> GetDefaultValue()
            {
                editor.CompilationPipeline += EditCompilation;

                return(new LightList <SyntaxEdit>());
            }

            CSharpCompilation EditCompilation(CSharpCompilation compilation, CancellationToken cancellationToken)
            {
                IList <SyntaxEdit> edits          = editor.Storage.Get <IList <SyntaxEdit> >(SyntaxKey);
                SyntaxTreeRewriter syntaxRewriter = new SyntaxTreeRewriter(compilation, edits, cancellationToken);

                for (int i = 0; i < compilation.SyntaxTrees.Length; i++)
                {
                    CSharpSyntaxTree tree = compilation.SyntaxTrees[i] as CSharpSyntaxTree;

                    if (tree == null)
                    {
                        continue;
                    }

                    CSharpSyntaxNode root    = tree.GetRoot(cancellationToken);
                    SyntaxNode       newRoot = syntaxRewriter.Visit(root);

                    if (root != newRoot)
                    {
                        compilation = compilation.ReplaceSyntaxTree(tree, tree.WithRootAndOptions(newRoot, tree.Options));
                    }
                }

                return(compilation);
            }

            editor.Storage.GetOrAdd(SyntaxKey, GetDefaultValue).Add(edit);
        }
 /// <summary>
 ///   Returns a copy of the given <see cref="SyntaxTree"/>, with its options compatible
 ///   with Cometary's required options.
 /// </summary>
 public static SyntaxTree WithCometaryOptions(this CSharpSyntaxTree syntaxTree, CompilationEditor editor)
 {
     return(syntaxTree.WithOptions(editor.GetRecomputationPipeline().MakeDelegate(opts => opts)(syntaxTree.Options)));
 }
Beispiel #8
0
 /// <summary>
 ///   Adds the given <paramref name="component"/> to the IL emission pipeline.
 /// </summary>
 /// <param name="editor"></param>
 /// <param name="component"></param>
 public static void EditIL(this CompilationEditor editor, AlternateEmitDelegate component)
 {
     editor.EditIL(CodeGeneratorContext.ToComponent(component));
 }
Beispiel #9
0
 /// <summary>
 ///   Registers a new <paramref name="edit"/> that is to be applied to all operations
 ///   that are about to be emitted.
 /// </summary>
 /// <param name="editor"></param>
 /// <param name="edit"></param>
 public static void EditOperation(this CompilationEditor editor, Edit <IOperation> edit)
 {
     editor.EditIL(next => (context, operation, used) => next(context, edit(operation, default(CancellationToken)), used));
 }
Beispiel #10
0
 internal static Pipeline <Func <CSharpParseOptions, CSharpParseOptions> > GetRecomputationPipeline(this CompilationEditor editor)
 {
     return(editor.SharedStorage.GetOrAdd(RecomputeKey, () => new Pipeline <Func <CSharpParseOptions, CSharpParseOptions> >()));
 }