PageRenderTime 54ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/src/Libraries/NRefactory/NRefactoryASTGenerator/KeywordGenerator.cs

https://github.com/eusebiu/SharpDevelop
C# | 388 lines | 336 code | 44 blank | 8 comment | 31 complexity | 4535ec5565df41dcfefce366ffd78223 MD5 | raw file
  1. // Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
  2. // This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Diagnostics;
  6. using System.IO;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Text.RegularExpressions;
  10. namespace NRefactoryASTGenerator
  11. {
  12. static class KeywordGenerator
  13. {
  14. static readonly string baseDir = "../../../Project/Src/Lexer/";
  15. static readonly string testBaseDir = "../../../Test/Lexer/";
  16. static readonly string parserBaseDir = "../../../Project/Src/Parser/";
  17. public static void Generate()
  18. {
  19. Generate("CSharp");
  20. Generate("VBNet");
  21. }
  22. static void Generate(string language)
  23. {
  24. try {
  25. Dictionary<string, string> properties = new Dictionary<string, string>();
  26. Dictionary<string, string[]> sets = new Dictionary<string, string[]>();
  27. List<string> keywords = new List<string>();
  28. List<string> terminals = new List<string>();
  29. Dictionary<string, string> specialChars = new Dictionary<string, string>();
  30. ReadFile(properties, sets, keywords, terminals, specialChars, language);
  31. GenerateFiles(properties, sets, keywords, terminals, specialChars, language);
  32. } catch (Exception e) {
  33. Debug.Print(e.ToString());
  34. }
  35. }
  36. static void GenerateFiles(Dictionary<string, string> properties, Dictionary<string, string[]> sets,
  37. List<string> keywords, List<string> terminals, Dictionary<string, string> specialChars,
  38. string language)
  39. {
  40. GenerateKeywords(properties, keywords, language);
  41. GenerateTokens(properties, sets, keywords, terminals, specialChars, language);
  42. GenerateTests(keywords, specialChars, language);
  43. GenerateKeywordSection(keywords, terminals, specialChars, language);
  44. }
  45. static void GenerateKeywordSection(List<string> keywords, List<string> terminals, Dictionary<string, string> specialChars, string language)
  46. {
  47. string sourceDir = Path.Combine(parserBaseDir, language, (language == "CSharp" ? "cs" : language) + ".atg");
  48. StringBuilder builder = new StringBuilder();
  49. builder.AppendLine("/* START AUTOGENERATED TOKENS SECTION */");
  50. builder.AppendLine("TOKENS");
  51. builder.AppendLine("\t/* ----- terminal classes ----- */");
  52. builder.AppendLine("\t/* EOF is 0 */");
  53. foreach (string terminal in terminals) {
  54. if (terminal == "EOF")
  55. continue;
  56. if (terminal == "Identifier") {
  57. builder.AppendLine("\tident");
  58. continue;
  59. }
  60. builder.AppendLine("\t" + terminal);
  61. }
  62. builder.AppendLine();
  63. builder.AppendLine("\t/* ----- special character ----- */");
  64. foreach (string specialChar in specialChars.Values) {
  65. builder.AppendLine("\t" + specialChar);
  66. }
  67. builder.AppendLine();
  68. builder.AppendLine("\t/* ----- keywords ----- */");
  69. foreach (string keyword in keywords) {
  70. builder.AppendLine("\t\"" + keyword + "\"");
  71. }
  72. builder.AppendLine("/* END AUTOGENERATED TOKENS SECTION */");
  73. string[] generatedLines = builder.ToString().Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
  74. string[] lines = File.ReadAllLines(sourceDir);
  75. var newContent = lines
  76. .TakeWhile(l => l != "/* START AUTOGENERATED TOKENS SECTION */")
  77. .Concat(generatedLines)
  78. .Concat(lines.SkipWhile(l => l != "/* END AUTOGENERATED TOKENS SECTION */").Skip(2))
  79. .ToArray();
  80. File.WriteAllLines(sourceDir, newContent);
  81. }
  82. static void GenerateTests(List<string> keywords, Dictionary<string, string> specialChars, string language)
  83. {
  84. string sourceDir = Path.Combine(testBaseDir, language, "LexerTests.cs");
  85. using (StreamWriter writer = new StreamWriter(new FileStream(sourceDir, FileMode.Create))) {
  86. writer.WriteLine("// this file was autogenerated by a tool.");
  87. writer.WriteLine("using System;");
  88. writer.WriteLine("using System.IO;");
  89. writer.WriteLine("using NUnit.Framework;");
  90. writer.WriteLine("using ICSharpCode.NRefactory.Parser;");
  91. writer.WriteLine("using ICSharpCode.NRefactory.Parser.{0};", language == "VBNet" ? "VB" : language);
  92. writer.WriteLine("using ICSharpCode.NRefactory.PrettyPrinter;");
  93. writer.WriteLine();
  94. writer.WriteLine("namespace ICSharpCode.NRefactory.Tests.Lexer.{0}", language == "VBNet" ? "VB" : language);
  95. writer.WriteLine("{");
  96. writer.WriteLine("\t[TestFixture]");
  97. writer.WriteLine("\tpublic sealed class LexerTests");
  98. writer.WriteLine("\t{");
  99. writer.WriteLine("\t\tILexer GenerateLexer(StringReader sr)");
  100. writer.WriteLine("\t\t{");
  101. writer.WriteLine("\t\t\treturn ParserFactory.CreateLexer(SupportedLanguage.{0}, sr);", language);
  102. writer.WriteLine("\t\t}");
  103. for (int i = 0; i < specialChars.Values.Count; i++) {
  104. writer.WriteLine();
  105. writer.WriteLine("\t\t[Test]");
  106. writer.WriteLine("\t\tpublic void Test{0}()", specialChars.Keys.ElementAt(i));
  107. writer.WriteLine("\t\t{");
  108. writer.WriteLine("\t\t\tILexer lexer = GenerateLexer(new StringReader({0}));", specialChars.Values.ElementAt(i));
  109. writer.WriteLine("\t\t\tAssert.AreEqual(Tokens.{0}, lexer.NextToken().Kind);", specialChars.Keys.ElementAt(i));
  110. writer.WriteLine("\t\t}");
  111. }
  112. foreach (string keyword in keywords) {
  113. if (keyword == "Rem")
  114. continue;
  115. writer.WriteLine();
  116. writer.WriteLine("\t\t[Test]");
  117. writer.WriteLine("\t\tpublic void Test{0}()", UpperCaseFirst(keyword));
  118. writer.WriteLine("\t\t{");
  119. writer.WriteLine("\t\t\tILexer lexer = GenerateLexer(new StringReader(\"{0}\"));", keyword);
  120. writer.WriteLine("\t\t\tAssert.AreEqual(Tokens.{0}, lexer.NextToken().Kind);", UpperCaseFirst(keyword));
  121. writer.WriteLine("\t\t}");
  122. }
  123. writer.WriteLine("\t}");
  124. writer.WriteLine("}");
  125. }
  126. }
  127. static void GenerateTokens(Dictionary<string, string> properties, Dictionary<string, string[]> sets, List<string> keywords, List<string> terminals, Dictionary<string, string> specialChars, string language)
  128. {
  129. string sourceDir = Path.Combine(baseDir, language, "Tokens.cs");
  130. using (StreamWriter writer = new StreamWriter(new FileStream(sourceDir, FileMode.Create))) {
  131. writer.WriteLine("// this file was autogenerated by a tool.");
  132. writer.WriteLine("using System;");
  133. writer.WriteLine("using System.Collections;");
  134. writer.WriteLine();
  135. writer.WriteLine("namespace {0}", properties["Namespace"]);
  136. writer.WriteLine("{");
  137. writer.WriteLine("\tpublic static class Tokens");
  138. writer.WriteLine("\t{");
  139. writer.WriteLine("\t\t// ----- terminal classes -----");
  140. int tokenValue = 0;
  141. foreach (string terminal in terminals)
  142. writer.WriteToken(terminal, ref tokenValue);
  143. writer.WriteLine();
  144. writer.WriteLine("\t\t// ----- special character -----");
  145. foreach (string specialChar in specialChars.Keys)
  146. writer.WriteToken(specialChar, ref tokenValue);
  147. writer.WriteLine();
  148. writer.WriteLine("\t\t// ----- keywords -----");
  149. foreach (string keyword in keywords)
  150. writer.WriteToken(keyword, ref tokenValue);
  151. writer.WriteLine();
  152. writer.WriteLine("\t\tpublic const int MaxToken = {0};", tokenValue);
  153. if (sets.Any()) {
  154. writer.WriteLine("\t\tstatic BitArray NewSet(params int[] values)");
  155. writer.WriteLine("\t\t{");
  156. writer.WriteLine("\t\t\tBitArray bitArray = new BitArray(MaxToken);");
  157. writer.WriteLine("\t\t\tforeach (int val in values) {");
  158. writer.WriteLine("\t\t\tbitArray[val] = true;");
  159. writer.WriteLine("\t\t\t}");
  160. writer.WriteLine("\t\t\treturn bitArray;");
  161. writer.WriteLine("\t\t}");
  162. foreach (var pair in sets) {
  163. StringBuilder builder = new StringBuilder();
  164. PrintList(pair.Value, builder, sets, specialChars);
  165. writer.WriteLine("\t\tpublic static BitArray {0} = NewSet({1});", pair.Key, builder.ToString());
  166. }
  167. writer.WriteLine();
  168. }
  169. // write token number --> string function.
  170. writer.WriteLine("\t\tstatic string[] tokenList = new string[] {");
  171. writer.WriteLine("\t\t\t// ----- terminal classes -----");
  172. foreach (string terminal in terminals)
  173. writer.WriteLine("\t\t\t\"<{0}>\",", terminal);
  174. writer.WriteLine("\t\t\t// ----- special character -----");
  175. foreach (string specialChar in specialChars.Values)
  176. writer.WriteLine("\t\t\t{0},", specialChar);
  177. writer.WriteLine("\t\t\t// ----- keywords -----");
  178. foreach (string keyword in keywords)
  179. writer.WriteLine("\t\t\t\"{0}\",", keyword);
  180. writer.WriteLine("\t\t};");
  181. writer.WriteLine("\t\tpublic static string GetTokenString(int token)");
  182. writer.WriteLine("\t\t{");
  183. writer.WriteLine("\t\t\tif (token >= 0 && token < tokenList.Length) {");
  184. writer.WriteLine("\t\t\t\treturn tokenList[token];");
  185. writer.WriteLine("\t\t\t}");
  186. writer.WriteLine("\t\t\tthrow new System.NotSupportedException(\"Unknown token:\" + token);");
  187. writer.WriteLine("\t\t}");
  188. writer.WriteLine("\t}");
  189. writer.WriteLine("}");
  190. }
  191. }
  192. static void PrintList(string[] value, StringBuilder builder, Dictionary<string, string[]> sets, Dictionary<string, string> specialChars)
  193. {
  194. for (int i = 0; i < value.Length; i++) {
  195. string item = value[i];
  196. if (Regex.IsMatch(item, "\\\"(\\w+)\\\"")) // keywords
  197. builder.Append(UpperCaseFirst(item.Trim('"', ' ', '\t')));
  198. else if (Regex.IsMatch(item, "\\\"(\\W+)\\\"")) // special chars
  199. builder.Append(specialChars.Keys.ElementAt(specialChars.Values.FindIndex(it => item == it)));
  200. else if (Regex.IsMatch(item, "@(\\w+)")) // other list
  201. PrintList(sets[item.Substring(1)], builder, sets, specialChars);
  202. else
  203. builder.Append(item);
  204. if (i + 1 < value.Length)
  205. builder.Append(", ");
  206. }
  207. }
  208. static void GenerateKeywords(Dictionary<string, string> properties, List<string> keywords, string language)
  209. {
  210. string sourceDir = Path.Combine(baseDir, language, "Keywords.cs");
  211. using (StreamWriter writer = new StreamWriter(new FileStream(sourceDir, FileMode.Create))) {
  212. writer.WriteLine("// this file was autogenerated by a tool.");
  213. writer.WriteLine("using System;");
  214. writer.WriteLine();
  215. writer.WriteLine("namespace {0}", properties["Namespace"]);
  216. writer.WriteLine("{");
  217. writer.WriteLine("\tpublic static class Keywords");
  218. writer.WriteLine("\t{");
  219. writer.WriteLine("\t\tstatic readonly string[] keywordList = {");
  220. for (int i = 0; i < keywords.Count; i++) {
  221. writer.Write("\t\t\t\"{0}\"", properties["UpperCaseKeywords"] == "True" ? keywords[i].ToUpperInvariant() : keywords[i]);
  222. if (i + 1 < keywords.Count)
  223. writer.Write(",");
  224. writer.WriteLine();
  225. }
  226. writer.WriteLine("\t\t};");
  227. writer.WriteLine("\t\t");
  228. writer.WriteLine("\t\tstatic LookupTable keywords = new LookupTable({0});", properties["UpperCaseKeywords"] == "True" ? "false" : "true");
  229. writer.WriteLine("\t\t");
  230. writer.WriteLine("\t\tstatic Keywords()");
  231. writer.WriteLine("\t\t{");
  232. writer.WriteLine("\t\t\tfor (int i = 0; i < keywordList.Length; ++i) {");
  233. writer.WriteLine("\t\t\t\tkeywords[keywordList[i]] = i + Tokens.{0};", UpperCaseFirst(keywords[0]));
  234. writer.WriteLine("\t\t\t}");
  235. writer.WriteLine("\t\t}");
  236. writer.WriteLine("\t\t");
  237. writer.WriteLine("\t\tpublic static int GetToken(string keyword)");
  238. writer.WriteLine("\t\t{");
  239. writer.WriteLine("\t\t\treturn keywords[keyword];");
  240. writer.WriteLine("\t\t}");
  241. writer.WriteLine("\t\t");
  242. writer.WriteLine("\t\tpublic static bool IsNonIdentifierKeyword(string word)");
  243. writer.WriteLine("\t\t{");
  244. writer.WriteLine("\t\t\tint token = GetToken(word);");
  245. writer.WriteLine("\t\t\tif (token < 0)");
  246. writer.WriteLine("\t\t\t\treturn false;");
  247. writer.WriteLine("\t\t\treturn !Tokens.IdentifierTokens[token];");
  248. writer.WriteLine("\t\t}");
  249. writer.WriteLine("\t}");
  250. writer.WriteLine("}");
  251. writer.Close();
  252. }
  253. }
  254. #region input
  255. static void ReadFile(Dictionary<string, string> properties, Dictionary<string, string[]> sets,
  256. List<string> keywords, List<string> terminals, Dictionary<string, string> specialChars,
  257. string language)
  258. {
  259. string sourceDir = Path.Combine(baseDir, language, "KeywordList.txt");
  260. using (StreamReader reader = new StreamReader(new FileStream(sourceDir, FileMode.Open))) {
  261. string line = reader.ReadLine();
  262. while (line != null) {
  263. ReadProperty(properties, line);
  264. ReadKeyword(keywords, line);
  265. ReadSet(sets, line);
  266. ReadTerminalSymbol(terminals, line);
  267. ReadSpecialChar(specialChars, line);
  268. line = reader.ReadLine();
  269. }
  270. reader.Close();
  271. }
  272. }
  273. static void ReadProperty(Dictionary<string, string> properties, string line)
  274. {
  275. // properties form: $PROPERTY = "VALUE"
  276. Match match = Regex.Match(line, @"^\s*\$(\w+)\s*=\s*(\S+)\s*$");
  277. if (match.Success) {
  278. properties.Add(match.Groups[1].Value, match.Groups[2].Value);
  279. }
  280. }
  281. static void ReadKeyword(List<string> keywords, string line)
  282. {
  283. // special keywords form: "VALUE"
  284. Match match = Regex.Match(line, "^\\s*\\\"(\\S+)\\s*\\\"\\s*$");
  285. if (match.Success) {
  286. keywords.Add(match.Groups[1].Value);
  287. }
  288. }
  289. static void ReadSet(Dictionary<string, string[]> sets, string line)
  290. {
  291. // sets form: NAME(comma separated list)
  292. Match match = Regex.Match(line, @"^\s*(\w+)\s*\((.*)\)\s*$");
  293. if (match.Success) {
  294. sets.Add(
  295. match.Groups[1].Value,
  296. match.Groups[2].Value.Split(new[] {", "}, StringSplitOptions.None)
  297. );
  298. }
  299. }
  300. static void ReadTerminalSymbol(List<string> terminals, string line)
  301. {
  302. // special terminal classes form: name
  303. Match match = Regex.Match(line, @"^\s*(\w+)\s*$");
  304. if (match.Success) {
  305. terminals.Add(match.Groups[1].Value);
  306. }
  307. }
  308. static void ReadSpecialChar(Dictionary<string, string> specialChars, string line)
  309. {
  310. // special characters form: name = "VALUE"
  311. Match match = Regex.Match(line, @"^\s*(\w+)\s*=\s*(\S+)\s*$");
  312. if (match.Success) {
  313. specialChars.Add(match.Groups[1].Value, match.Groups[2].Value);
  314. }
  315. }
  316. #endregion
  317. #region helpers
  318. static string UpperCaseFirst(string keyword)
  319. {
  320. return char.ToUpperInvariant(keyword[0]) + keyword.Substring(1);
  321. }
  322. static void WriteToken(this StreamWriter writer, string tokenName, ref int tokenValue)
  323. {
  324. string formattedName = UpperCaseFirst(tokenName).PadRight(20);
  325. if (tokenName == "GetType" || tokenName.ToLowerInvariant() == "equals")
  326. writer.WriteLine("\t\tnew public const int {0} = {1};", formattedName, tokenValue);
  327. else
  328. writer.WriteLine("\t\tpublic const int {0} = {1};", formattedName, tokenValue);
  329. tokenValue++;
  330. }
  331. static int FindIndex<T>(this IEnumerable<T> items, Func<T, bool> f)
  332. {
  333. int index = -1;
  334. foreach (T item in items) {
  335. index++;
  336. if (f(item))
  337. return index;
  338. }
  339. return -1;
  340. }
  341. #endregion
  342. }
  343. }