PageRenderTime 13ms CodeModel.GetById 2ms app.highlight 8ms RepoModel.GetById 1ms app.codeStats 0ms

/src/CodeGenerator/TemplateProcessor.cs

https://github.com/aardvark-platform/aardvark.base
C# | 195 lines | 159 code | 33 blank | 3 comment | 5 complexity | 53d07ae3b1f517c804bf594c9b495fac MD5 | raw file
  1using System;
  2using System.CodeDom.Compiler;
  3using System.Collections.Generic;
  4using System.IO;
  5using System.Linq;
  6using System.Text;
  7using Aardvark.Base;
  8
  9namespace CodeGenerator
 10{
 11
 12    public class TemplateProcessor : TextParser<TemplateProcessor>
 13    {
 14        public string Input;
 15
 16        public StringBuilder Code;
 17        public StringBuilder Using;
 18        public StringBuilder Class;
 19
 20        public StringBuilder Active;
 21
 22        public string GeneratorSourceCode;
 23        public string Result;
 24
 25        #region Constructor
 26
 27        public TemplateProcessor()
 28        {
 29            Input = null;
 30
 31            Code = new StringBuilder();
 32            Using = new StringBuilder();
 33            Class = new StringBuilder();
 34            Active = Code;
 35
 36            GeneratorSourceCode = null;
 37            Result = null;
 38        }
 39
 40        #endregion
 41
 42        #region Constants
 43
 44        public string StandardUsing = @"using System;
 45using System.Collections.Generic;
 46using System.Linq;
 47using System.Text;
 48using System.IO;
 49using System.Xml.Linq;
 50using CodeGenerator;
 51using Aardvark.Base;
 52using Aardvark.Base.CSharp;
 53";
 54
 55        public string Prologue = @"
 56public static class SourceGenerator
 57{
 58    public static StringBuilder ___sb = new StringBuilder();
 59    public static Func<string, string> Filter = null;
 60    public static Func<string, string> ___Filter = s => Filter == null ? s : Filter(s);
 61    public static Action<string> Out = s => { ___sb.Append(___Filter(s)); };
 62    public static string Generate()
 63    {
 64";
 65
 66        public string StandardClass = @"
 67        return ___sb.ToString();
 68    }
 69";
 70
 71        public string Epilogue = @"
 72}
 73";
 74
 75        #endregion
 76
 77        #region Operations
 78
 79        public void Perform()
 80        {
 81            CreateGenerator();
 82            CompileAndRunGenerator();
 83        }
 84
 85        public void CreateGenerator() { CreateGenerator(null); }
 86
 87        public void CreateGenerator(string injectAfterPrologue)
 88        {
 89            if (injectAfterPrologue == null) injectAfterPrologue = "";
 90
 91            Parse(new Text(Input), this, State, new Nd());
 92
 93            GeneratorSourceCode = StandardUsing
 94                                    + Using.ToString()
 95                                    + Prologue
 96                                    + injectAfterPrologue
 97                                    + Code.ToString()
 98                                    + StandardClass
 99                                    + Class.ToString()
100                                    + Epilogue;
101
102            // ReportUsings();
103        }
104
105        public void CompileAndRunGenerator()
106        {
107            var lines = GeneratorSourceCode.Split('\n');
108            var generatorAssembly = CompilerServices.CompileAssembly(
109                GeneratorSourceCode.IntoArray(),
110                new string[] {
111                    "System.Xml.dll",
112                    "System.Xml.Linq.dll",
113                    "Aardvark.Base.dll",
114                    "System.ValueTuple.dll"
115                },
116                ".", out CompilerResults results);
117            if (results.Errors.Count > 0)
118            {
119                Console.WriteLine("WARNING: build of generator failed!");
120                foreach (var x in results.Errors) Console.WriteLine("{0}", x);
121                Result = null;
122                return;
123            }
124            var generatorFun = generatorAssembly.GetTypes().First().GetMethods().First();
125            Result = (string)generatorFun.Invoke(null, null);
126        }
127
128        #endregion
129
130        #region Private Methods
131
132        private void ReportUsings()
133        {
134            var nonSystemUsings = FilterNonSystemUsingsIntoList(Using.ToString());
135            foreach (var use in nonSystemUsings) Console.WriteLine("USING {0};", use);
136        }
137
138        private static List<string> FilterNonSystemUsingsIntoList(string usings)
139        {
140            var genUse = from use in
141                             (from rawUse in usings.Split(
142                                             new string[] { Environment.NewLine },
143                                             StringSplitOptions.RemoveEmptyEntries)
144                              let trimUse = rawUse.Trim()
145                              where trimUse.StartsWith("using ")
146                                      && trimUse.EndsWith(";")
147                              select trimUse.Substring(6, trimUse.Length - 7).Trim())
148                         where !use.StartsWith("System")
149                         select use;
150            return genUse.ToList();
151        }
152
153        #endregion
154
155        #region Parser States
156
157        private class Nd { }
158
159        private static readonly State<TemplateProcessor, Nd> State
160                                    = new Cases<TemplateProcessor, Nd>
161            {
162                { @"/\*CLASS#", (p, n) => { p.Skip(); p.Class.Append(p.GetToStartOf("*/"));
163                                            p.Skip(); return State; } },
164                { @"/\*USING#", (p, n) => { p.Skip(); p.Using.Append(p.GetToStartOf("*/"));
165                                            p.Skip(); return State; } },
166                { @"/\*#",      (p, n) => { p.Skip(); p.Active.Append(p.GetToStartOf("*/"));
167                                            p.Skip(); return State; } },
168                { @"//BEGIN\sCLASS#", (p, n) => { p.Skip(); p.SkipToEndOfOrEnd('\n');
169                                                  p.Active = p.Class; return State; },
170                                        (p, n, t) => t.TrimmedAtEnd(CharFun.IsSpaceOrTab) },
171                { @"//END\sCLASS#",   (p, n) => { p.Skip(); p.SkipToEndOfOrEnd('\n');
172                                                  p.Active = p.Code; return State; },
173                                        (p, n, t) => t.TrimmedAtEnd(CharFun.IsSpaceOrTab) },
174                { @"//#",       (p, n) => { p.Skip(); p.Active.Append(p.GetToEndOfOrEnd('\n'));
175                                            return State; },
176                                // indented //# comments eat the preceeding indentation
177                                // by trimming it from the preceeding text:
178                                (p, n, t) => t.TrimmedAtEnd(CharFun.IsSpaceOrTab) },
179                { @"__",        (p, n) => { p.Skip();
180                                            p.Active.Append(string.Format(
181                                                "___sb.Append(({0}).ToString());",
182                                                p.GetToStartOf("__")));
183                                            p.Skip(); return State; } },
184            }.ToState(  (p, n, t) =>    {
185                                            if (!t.IsEmpty)
186                                            {
187                                                p.Active.Append(
188                                                    string.Format("___sb.Append(___Filter(@\"{0}\"));",
189                                                                    t.ToString().Replace("\"", "\"\"")));
190                                            }
191                                        });
192
193        #endregion
194    }
195}