/Source/AniseLib/Core/AniseScript.cs

http://anise.codeplex.com · C# · 301 lines · 253 code · 40 blank · 8 comment · 53 complexity · 7b99034d63279ee45c5b626d216193f0 MD5 · raw file

  1. //
  2. // Anise - A user-friendly dependency injection engine
  3. // Released by Microsoft Live Labs
  4. //
  5. // This source code is released under the Microsoft Code Sharing License.
  6. // For full details, see: http://anise.codeplex.com/license
  7. //
  8. using System;
  9. using System.Collections.Generic;
  10. using System.IO;
  11. using System.Linq;
  12. using System.Text;
  13. using Microsoft.LiveLabs.Anise.API;
  14. namespace Microsoft.LiveLabs.Anise.Core
  15. {
  16. internal class AniseScript
  17. {
  18. public override String ToString()
  19. {
  20. StringBuilder builder = new StringBuilder();
  21. bool needsNewLine = false;
  22. foreach (AniseScriptLine line in m_lines)
  23. {
  24. if (needsNewLine) builder.Append('\n');
  25. builder.Append(line.Text);
  26. needsNewLine = true;
  27. }
  28. return builder.ToString();
  29. }
  30. internal AniseScript() : this("")
  31. {
  32. // Do nothing.
  33. }
  34. internal AniseScript(String text)
  35. {
  36. m_lines = new List<AniseScriptLine>();
  37. m_consumeBuilder = new StringBuilder();
  38. this.LoadText(text);
  39. }
  40. internal List<AniseScriptLine> Lines
  41. {
  42. get { return m_lines; }
  43. }
  44. internal char CurrentChar
  45. {
  46. get
  47. {
  48. AniseScriptLine line = this.CurrentLine;
  49. if (line == null) return AniseConstants.EndOfData;
  50. if (this.CurrentLine.Text.Length == m_positionIndex)
  51. {
  52. return (m_lineIndex + 1 == m_lines.Count) ? AniseConstants.EndOfData : '\n';
  53. }
  54. return this.CurrentLine.Text[m_positionIndex];
  55. }
  56. }
  57. internal AniseScriptLine CurrentLine
  58. {
  59. get
  60. {
  61. if (m_lines.Count == 0) return null;
  62. if (m_lineIndex >= m_lines.Count) return null;
  63. return m_lines[m_lineIndex];
  64. }
  65. }
  66. internal AniseScriptPosition CurrentPosition
  67. {
  68. get
  69. {
  70. AniseScriptLine line = this.CurrentLine;
  71. if ((line == null) || (line.Position == null))
  72. {
  73. return new AniseScriptPosition(AniseConstants.DefaultFile, 1, 1);
  74. }
  75. else
  76. {
  77. return new AniseScriptPosition(this.CurrentLine.Position.SourceFile,
  78. this.CurrentLine.Position.LineNumber, m_positionIndex + 1);
  79. }
  80. }
  81. }
  82. internal List<AniseScriptLine> LoadText(String text)
  83. {
  84. if (text == null) throw new ArgumentNullException("Text cannot be null");
  85. if (text == "") return new List<AniseScriptLine>();
  86. List<AniseScriptLine> newLines = this.ConvertToLines(text, AniseConstants.DefaultFile + m_inlineChunks);
  87. m_lines.AddRange(newLines);
  88. m_inlineChunks++;
  89. return newLines;
  90. }
  91. internal List<AniseScriptLine> LoadFile(String fileName, AniseScriptLine replacingLine)
  92. {
  93. List<AniseScriptLine> newLines = this.ConvertToLines(File.ReadAllText(fileName), fileName);
  94. int index = m_lines.IndexOf(replacingLine);
  95. if (index != -1)
  96. {
  97. m_lines.InsertRange(index + 1, newLines);
  98. }
  99. else
  100. {
  101. m_lines.AddRange(newLines);
  102. }
  103. return newLines;
  104. }
  105. internal void RemoveLines(List<AniseScriptLine> lines)
  106. {
  107. foreach (AniseScriptLine line in lines)
  108. {
  109. m_lines.Remove(line);
  110. }
  111. }
  112. internal char Advance()
  113. {
  114. if (this.IsFinished) return AniseConstants.EndOfData;
  115. String lineText = this.CurrentLine.Text;
  116. if (m_positionIndex + 1 > lineText.Length)
  117. {
  118. m_lineIndex++;
  119. m_positionIndex = 0;
  120. }
  121. else
  122. {
  123. m_positionIndex++;
  124. }
  125. return this.CurrentChar;
  126. }
  127. internal void AdvancePastWhitespace()
  128. {
  129. while (Char.IsWhiteSpace(this.CurrentChar))
  130. {
  131. this.Advance();
  132. }
  133. }
  134. internal String ConsumeTo(String stopChars)
  135. {
  136. m_consumeBuilder.Length = 0;
  137. bool quoted = false;
  138. bool escaped = false;
  139. bool insertWhitespace = false;
  140. while (true)
  141. {
  142. char c = this.CurrentChar;
  143. if (escaped)
  144. {
  145. if (quoted && (c != AniseConstants.DoubleQuote) && (c != AniseConstants.Backslash))
  146. {
  147. m_consumeBuilder.Append(AniseConstants.Backslash);
  148. }
  149. m_consumeBuilder.Append(c);
  150. escaped = false;
  151. }
  152. else if (c == AniseConstants.Backslash)
  153. {
  154. escaped = true;
  155. }
  156. else if (c == AniseConstants.DoubleQuote)
  157. {
  158. quoted = !quoted;
  159. }
  160. else if (quoted && (c != AniseConstants.EndOfData))
  161. {
  162. if (insertWhitespace)
  163. {
  164. m_consumeBuilder.Append(' ');
  165. insertWhitespace = false;
  166. }
  167. m_consumeBuilder.Append(c);
  168. }
  169. else if (Char.IsWhiteSpace(c))
  170. {
  171. insertWhitespace = true;
  172. }
  173. else
  174. {
  175. if (stopChars.Contains(c)) break;
  176. if (c == AniseConstants.EndOfData) throw new AniseException(
  177. "Expected '" + stopChars.ToString() + "'", this.CurrentPosition);
  178. if (insertWhitespace)
  179. {
  180. m_consumeBuilder.Append(' ');
  181. insertWhitespace = false;
  182. }
  183. m_consumeBuilder.Append(c);
  184. }
  185. this.Advance();
  186. }
  187. String result = m_consumeBuilder.ToString();
  188. return result;
  189. }
  190. internal bool IsFinished
  191. {
  192. get
  193. {
  194. return (m_lineIndex >= m_lines.Count);
  195. }
  196. }
  197. private List<AniseScriptLine> ConvertToLines(String rawText, String fileName)
  198. {
  199. List<AniseScriptLine> lines = new List<AniseScriptLine>();
  200. int lineNumber = 1;
  201. using (StringReader reader = new StringReader(rawText))
  202. {
  203. while (true)
  204. {
  205. String line = reader.ReadLine();
  206. if (line == null) break;
  207. lines.Add(new AniseScriptLine(new AniseScriptPosition(fileName, lineNumber, 1), null, line));
  208. lineNumber++;
  209. }
  210. }
  211. return lines;
  212. }
  213. private List<AniseScriptLine> m_lines;
  214. private StringBuilder m_consumeBuilder;
  215. private int m_inlineChunks;
  216. private int m_lineIndex;
  217. private int m_positionIndex;
  218. }
  219. internal class AniseScriptLine
  220. {
  221. public override string ToString()
  222. {
  223. return Path.GetFileName(this.Position.SourceFile) + "@" + this.Position.LineNumber + ": " + this.Text;
  224. }
  225. internal AniseScriptLine(AniseScriptPosition position, String namespaceText, String text)
  226. {
  227. this.Position = position;
  228. this.Namespace = namespaceText;
  229. this.Text = text;
  230. }
  231. internal AniseScriptPosition Position
  232. {
  233. get { return m_position; }
  234. set
  235. {
  236. if (value == null) throw new ArgumentNullException("Position cannot be null");
  237. m_position = value;
  238. }
  239. }
  240. internal String Namespace
  241. {
  242. get { return m_namespace; }
  243. set
  244. {
  245. m_namespace = value;
  246. }
  247. }
  248. internal String Text
  249. {
  250. get { return m_text; }
  251. set
  252. {
  253. if (value == null) throw new ArgumentNullException("Text cannot be null");
  254. m_text = value;
  255. }
  256. }
  257. private AniseScriptPosition m_position;
  258. private String m_namespace;
  259. private String m_text;
  260. }
  261. }