Writer.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195
  1. // $Id$
  2. using System;
  3. using System.IO;
  4. using System.Collections;
  5. using System.Globalization;
  6. namespace Lisp
  7. {
  8. public sealed class Writer {
  9. private TextWriter stream;
  10. private int IndentDepth;
  11. private Stack lists = new Stack();
  12. public Writer(TextWriter stream) {
  13. this.stream = stream;
  14. }
  15. /// <summary>
  16. /// Writes a comment to the stream.
  17. /// </summary>
  18. /// <param name="comment">Contents of the comment</param>
  19. public void WriteComment(string comment) {
  20. stream.WriteLine("; " + comment);
  21. }
  22. /// <summary>
  23. /// Starts a new lisp tree.
  24. /// </summary>
  25. /// <param name="name">The name of the lisp tree.</param>
  26. /// <seealso cref="EndList"/>
  27. public void StartList(string name) {
  28. indent();
  29. stream.WriteLine("(" + name);
  30. IndentDepth += 2;
  31. lists.Push(name);
  32. }
  33. /// <summary>
  34. /// Ends a lisptree opened with <see cref="StartList"/>.
  35. /// </summary>
  36. /// <param name="name">The name of the lisp tree.</param>
  37. /// <seealso cref="StartList"/>
  38. public void EndList(string name) {
  39. if(lists.Count == 0)
  40. throw new LispException("Trying to close list while none is open");
  41. string back = (string) lists.Pop();
  42. if(name != back)
  43. throw new LispException(String.Format("Trying to close {0} which is not open", name));
  44. IndentDepth -= 2;
  45. indent();
  46. stream.WriteLine(")");
  47. }
  48. /// <summary>
  49. /// Write an object <paramref name="value"/> to
  50. /// the stream under the name
  51. /// <paramref name="name"/>.
  52. /// </summary>
  53. /// <param name="name">The name to write value to in lisp.</param>
  54. /// <param name="value">The object to write</param>
  55. /// <remarks>
  56. /// This function can write
  57. /// strings, lists that implements <see cref="IEnumerable"/>,
  58. /// and for anything else it will call <see cref="WriteValue"/>.
  59. /// </remarks>
  60. public void Write(string name, object value) {
  61. indent();
  62. stream.Write("(" + name);
  63. if((value is Lisp.List)) {
  64. stream.Write("\n");
  65. foreach(object o in (IEnumerable) value) {
  66. stream.Write(" ");
  67. WriteValue(o);
  68. }
  69. indent();
  70. } else if((value is IEnumerable) && !(value is string)) {
  71. if (value is Lisp.List)
  72. {
  73. stream.Write("\n");
  74. }
  75. foreach(object o in (IEnumerable) value) {
  76. stream.Write(" ");
  77. WriteValue(o);
  78. }
  79. } else {
  80. stream.Write(" ");
  81. WriteValue(value);
  82. }
  83. stream.WriteLine(")");
  84. }
  85. /// <summary>
  86. /// Writes a string and marks it as translatable
  87. /// (for use with gettext?).
  88. /// </summary>
  89. /// <param name="Name">The name of the element to write.</param>
  90. /// <param name="value">The value of it.</param>
  91. public void WriteTranslatable(string Name, string value) {
  92. indent();
  93. stream.Write("(" + Name + " (_ ");
  94. WriteValue(value);
  95. stream.WriteLine("))");
  96. }
  97. /// <summary>
  98. /// Processes and writes a value <paramref name="val"/>.
  99. /// </summary>
  100. /// <remarks>
  101. /// If <paramref name="val"/> is a
  102. /// <list type="table">
  103. /// <listheader>
  104. /// <term>Type</term>
  105. /// <description>What will be written</description>
  106. /// </listheader>
  107. /// <item>
  108. /// <term><see cref="Boolean"/></term>
  109. /// <description>#t or #f will be written.</description>
  110. /// </item>
  111. /// <item>
  112. /// <term><see cref="Single"/> or <see cref="Double"/></term>
  113. /// <description>
  114. /// The floating point number will be formated with
  115. /// <see cref="CultureInfo.InvariantCulture"/>
  116. /// </description>
  117. /// </item>
  118. /// <item>
  119. /// <term>Other</term>
  120. /// <description>Call ToString() of <paramref name="val"/></description>
  121. /// </item>
  122. /// </list>
  123. /// </remarks>
  124. /// <param name="val">The value to write</param>
  125. private void WriteValue(object val) {
  126. if(val is bool) {
  127. stream.Write( ((bool) val) == true ? "#t" : "#f");
  128. } else if(val is int || val is uint) {
  129. stream.Write(val.ToString());
  130. } else if(val is float || val is double) {
  131. string num = String.Format(CultureInfo.InvariantCulture, "{0:G}", val);
  132. stream.Write(num);
  133. } else if(val is string) {
  134. stream.Write("\"");
  135. foreach(char c in val.ToString()) {
  136. if(c == '\"')
  137. stream.Write("\\\"");
  138. else if(c == '\\')
  139. stream.Write("\\\\");
  140. else
  141. stream.Write(c);
  142. }
  143. stream.Write("\"");
  144. } else if(val is Lisp.Symbol) {
  145. stream.Write(((Lisp.Symbol)val).Name);
  146. } else if(val is Lisp.List) {
  147. IndentDepth += 2;
  148. indent();
  149. stream.Write("(");
  150. bool first = true;
  151. foreach(object it in (Lisp.List)val) {
  152. if (!first) {
  153. stream.Write(" ");
  154. } else {
  155. first = false;
  156. }
  157. WriteValue(it);
  158. }
  159. IndentDepth -= 2;
  160. stream.Write(")\n");
  161. } else {
  162. stream.Write("\"" + val.ToString() + "\"");
  163. }
  164. }
  165. /// <summary>
  166. /// Indents and write the string passed in <paramref name="line"/>
  167. /// without any processing of it.
  168. /// </summary>
  169. /// <param name="line">The line to write.</param>
  170. public void WriteVerbatimLine(string line) {
  171. indent();
  172. stream.WriteLine(line);
  173. }
  174. /// <summary>
  175. /// Add spaces to indent to <see cref="IndentDepth"/>.
  176. /// </summary>
  177. private void indent() {
  178. stream.Write(new String(' ', IndentDepth));
  179. }
  180. }
  181. }