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