PageRenderTime 59ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/System.Xronos/Builtins/SpecialMacros.cs

https://bitbucket.org/stefanrusek/xronos
C# | 369 lines | 329 code | 17 blank | 23 comment | 13 complexity | f640e4f236978eb6a599cbc04bfbbced MD5 | raw file
  1. /* ****************************************************************************
  2. *
  3. * Copyright (c) 2008 Stefan Rusek and Benjamin Pollack
  4. *
  5. * Permission is hereby granted, free of charge, to any person obtaining a copy
  6. * of this software and associated documentation files (the "Software"), to deal
  7. * in the Software without restriction, including without limitation the rights
  8. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. * copies of the Software, and to permit persons to whom the Software is
  10. * furnished to do so, subject to the following conditions:
  11. *
  12. * The above copyright notice and this permission notice shall be included in
  13. * all copies or substantial portions of the Software.
  14. *
  15. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  16. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  17. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  18. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  19. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  20. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  21. * THE SOFTWARE.
  22. *
  23. * ***************************************************************************/
  24. using System;
  25. using System.Collections.Generic;
  26. using System.Linq;
  27. using System.Text;
  28. using System.Xronos.Language;
  29. using System.Text.RegularExpressions;
  30. namespace System.Xronos.Builtins
  31. {
  32. public sealed partial class SpecialMacros
  33. {
  34. public static readonly Symbol Quote = Symbol.Create("quote");
  35. public static readonly Symbol Deref = Symbol.Create("xronos", "deref");
  36. public static readonly Symbol Meta = Symbol.Create("xronos", "meta");
  37. static ReaderBase[] macros = new ReaderBase[128];
  38. static SpecialMacros()
  39. {
  40. macros['"'] = new StringReader();
  41. macros[';'] = new CommentReader();
  42. macros['\''] = new WrappingReader(Quote);
  43. macros['@'] = new WrappingReader(Deref);
  44. macros['^'] = new WrappingReader(Meta);
  45. macros['`'] = new SyntaxQuoteReader();
  46. macros['~'] = new UnquoteReader();
  47. macros['('] = new ListReader();
  48. macros[')'] = new UnmatchedDelimiterReader();
  49. macros['['] = new VectorReader();
  50. macros[']'] = new UnmatchedDelimiterReader();
  51. macros['{'] = new MapReader();
  52. macros['}'] = new UnmatchedDelimiterReader();
  53. macros['\\'] = new CharacterReader();
  54. macros['%'] = new ArgReader();
  55. macros['#'] = new DispatchReader();
  56. }
  57. internal static object ResolveMacro(char c)
  58. {
  59. if (c >= macros.Length)
  60. return null;
  61. return macros[c];
  62. }
  63. internal static bool IsMacro(char c)
  64. {
  65. return ResolveMacro(c) != null;
  66. }
  67. internal static bool IsTerminatingMacro(char c)
  68. {
  69. return c != '#' && IsMacro(c);
  70. }
  71. #region Readers
  72. internal abstract class ReaderBase : XronosObject
  73. {
  74. protected ReaderBase() : base(null) { }
  75. public virtual object Invoke(object reader, object c) { return Read((Reader)reader, (char)c); }
  76. protected abstract object Read(Reader reader, char c);
  77. public override XronosObject withMeta(IPersistentMap meta)
  78. {
  79. throw new NotImplementedException();
  80. }
  81. }
  82. class UnmatchedDelimiterReader : ReaderBase
  83. {
  84. protected override object Read(Reader reader, char c)
  85. {
  86. throw new ReaderException("Unmatched delimiter: " + c);
  87. }
  88. }
  89. class StringReader : ReaderBase
  90. {
  91. protected override object Read(Reader reader, char quote)
  92. {
  93. reader.Advance();
  94. int slashes = 0;
  95. char prev = '\0';
  96. Func<char, bool> predicate = c =>
  97. {
  98. slashes = prev == '\\' ? slashes + 1 : 0;
  99. prev = c;
  100. return c != quote || (slashes & 1) != 0;
  101. };
  102. string str = reader.ReadString(predicate);
  103. reader.Advance();
  104. return UnescapeString(str);
  105. }
  106. private object UnescapeString(string str)
  107. {
  108. return CharacterReader.reCharEscapes.Replace(str,
  109. (Match m) => new string(CharacterReader.ParseCharacter(m.Groups[1].Value), 1));
  110. }
  111. }
  112. class CommentReader : ReaderBase
  113. {
  114. protected override object Read(Reader reader, char semiColon)
  115. {
  116. reader.ReadString((char c) => c != '\n' && c != '\r');
  117. return reader;
  118. }
  119. }
  120. class WrappingReader : ReaderBase
  121. {
  122. readonly Symbol sym;
  123. public WrappingReader(Symbol sym)
  124. {
  125. this.sym = sym;
  126. }
  127. protected override object Read(Reader reader, char c)
  128. {
  129. reader.Advance();
  130. return RT.List(sym, reader.InternalRead(false, null));
  131. }
  132. }
  133. class ListReader : ReaderBase
  134. {
  135. protected override object Read(Reader reader, char c)
  136. {
  137. reader.Advance();
  138. var list = reader.ReadList(')');
  139. reader.Advance();
  140. return PersistentList.Create(list);
  141. }
  142. }
  143. class VectorReader : ReaderBase
  144. {
  145. protected override object Read(Reader reader, char c)
  146. {
  147. reader.Advance();
  148. var list = reader.ReadList(']');
  149. reader.Advance();
  150. return PersistentVector.Create(list);
  151. }
  152. }
  153. class MapReader : ReaderBase
  154. {
  155. protected override object Read(Reader reader, char c)
  156. {
  157. reader.Advance();
  158. var result = PersistentHashMap.Create(reader.ReadList('}'));
  159. reader.Advance();
  160. return result;
  161. }
  162. }
  163. class CharacterReader : ReaderBase
  164. {
  165. public static Regex reCharEscapes = new Regex(@"\\(newline|space|tab|backspace|formfeed|return|(u[a-zA-Z0-9]{4})|(o[0-7]{1,3})|.)");
  166. protected override object Read(Reader reader, char c)
  167. {
  168. reader.Advance();
  169. return ParseCharacter(reader.ReadToken());
  170. }
  171. public static char ParseCharacter(string token)
  172. {
  173. if (token.Length == 1)
  174. return token[0];
  175. switch (token)
  176. {
  177. case "newline":
  178. return '\n';
  179. case "space":
  180. return ' ';
  181. case "tab":
  182. return '\t';
  183. case "backspace":
  184. return '\b';
  185. case "formfeed":
  186. return '\f';
  187. case "return":
  188. return '\r';
  189. default:
  190. switch (token[0])
  191. {
  192. case 'u':
  193. #if FixClojureBugs
  194. if (token.Length > 5)
  195. throw new ReaderException("Invalid hex escape sequence length: " + token.Length);
  196. #endif
  197. return ParseNumericCharacter(token, 1, 4, 16);
  198. case 'o':
  199. return ParseOctalEscape(token);
  200. }
  201. throw new ReaderException("Unsupported character: \\" + token);
  202. }
  203. }
  204. private static char ParseOctalEscape(string token)
  205. {
  206. int len = token.Length - 1;
  207. if (len > 3)
  208. throw new ReaderException("Invalid octal escape sequence length: " + len);
  209. char oc = ParseNumericCharacter(token, 1, len, 8);
  210. if (oc > 0xFF)
  211. throw new ReaderException("Octal escape sequence must be in range [0, 377].");
  212. return oc;
  213. }
  214. private static char ParseNumericCharacter(string token, int offset, int chars, int radix)
  215. {
  216. int c = 0, end = offset + chars;
  217. if (token.Length < end)
  218. throw new ArgumentException("Invalid unicode character: \\" + token, "token");
  219. for (int i = offset; i < end; i++)
  220. c = c * radix + Digit(token[i], radix);
  221. return unchecked((char)c);
  222. }
  223. private static int Digit(char c, int radix)
  224. {
  225. int result = int.MaxValue;
  226. if (c >= '0' && c <= '9')
  227. result = c - '0';
  228. else if (c >= 'a' && c <= 'z')
  229. result = c - 'a';
  230. else if (c >= 'A' && c <= 'Z')
  231. result = c - 'A';
  232. if (result > radix)
  233. throw new ArgumentException("Invalid digit: " + c, "c");
  234. return result;
  235. }
  236. }
  237. class ArgReader : ReaderBase
  238. {
  239. protected override object Read(Reader reader, char c)
  240. {
  241. throw new NotImplementedException();
  242. }
  243. }
  244. class DispatchReader : ReaderBase
  245. {
  246. ReaderBase[] macros = new ReaderBase[128];
  247. public DispatchReader()
  248. {
  249. macros['^'] = new MetaReader();
  250. macros['\''] = new WrappingReader(Reader.Var);
  251. macros['"'] = new RegexReader();
  252. macros['('] = new FnReader();
  253. macros['{'] = new SetReader();
  254. macros['!'] = new CommentReader();
  255. }
  256. protected override object Read(Reader reader, char quote)
  257. {
  258. reader.Advance();
  259. char c = reader.Peek();
  260. if (c < macros.Length)
  261. {
  262. ReaderBase fn = macros[c];
  263. if (fn != null)
  264. return fn.Invoke(reader, c);
  265. }
  266. throw new ReaderException("No dispatch macro for: " + c);
  267. }
  268. }
  269. class RegexReader : ReaderBase
  270. {
  271. readonly StringReader inner = new StringReader();
  272. protected override object Read(Reader reader, char c)
  273. {
  274. var pattern = (string)inner.Invoke(reader, c);
  275. return new Regex(pattern);
  276. }
  277. }
  278. class MetaReader : ReaderBase
  279. {
  280. protected override object Read(Reader reader, char c)
  281. {
  282. reader.Advance();
  283. var meta = reader.InternalRead(false, null);
  284. int line = reader.Line;
  285. if (meta is string || meta is Symbol || meta is Keyword)
  286. meta = RT.Map(RT.Tag, meta);
  287. else if (!(meta is IPersistentMap))
  288. throw new ReaderException("Metadata must be Symbol,Keyword,String or Map");
  289. var obj = reader.InternalRead(false, null) as XronosObject;
  290. if (obj == null)
  291. throw new ReaderException("Metadata can only be applied to XronosObjects");
  292. return obj.withMeta(((IPersistentMap)meta).assocEx(RT.Line, line));
  293. }
  294. }
  295. class FnReader : ReaderBase
  296. {
  297. protected override object Read(Reader reader, char c)
  298. {
  299. var list = reader.ReadList(')');
  300. return RT.ListStar(list).cons(PersistentVector.Empty).cons(Symbol.Create("fn"));
  301. }
  302. }
  303. class SetReader : ReaderBase
  304. {
  305. protected override object Read(Reader reader, char c)
  306. {
  307. throw new NotImplementedException();
  308. }
  309. }
  310. #endregion
  311. }
  312. }