ReaderParens.java 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. // Copyright (c) 2001 Per M.A. Bothner
  2. // This is free software; for terms and warranty disclaimer see ./COPYING.
  3. package gnu.kawa.lispexpr;
  4. import gnu.kawa.io.InPort;
  5. import gnu.text.*;
  6. import gnu.mapping.Values;
  7. public final class ReaderParens extends ReadTableEntry
  8. {
  9. char open;
  10. char close;
  11. int kind;
  12. Object command;
  13. public int getKind()
  14. {
  15. return kind;
  16. }
  17. private static ReaderParens instance;
  18. public static ReaderParens getInstance(char open, char close)
  19. {
  20. return getInstance(open, close, ReadTable.TERMINATING_MACRO);
  21. }
  22. public static ReaderParens getInstance(char open, char close, int kind)
  23. {
  24. if (open == '(' && close == ')' && kind == ReadTable.TERMINATING_MACRO)
  25. {
  26. if (instance == null)
  27. instance = new ReaderParens(open, close, kind, null);
  28. return instance;
  29. }
  30. else
  31. {
  32. return new ReaderParens(open, close, kind, null);
  33. }
  34. }
  35. public static ReaderParens getInstance(char open, char close, int kind, Object command)
  36. {
  37. if (command == null)
  38. return getInstance(open, close, kind);
  39. else
  40. return new ReaderParens(open, close, kind, command);
  41. }
  42. public ReaderParens(char open, char close, int kind, Object command)
  43. {
  44. this.open = open;
  45. this.close = close;
  46. this.kind = kind;
  47. this.command = command;
  48. }
  49. /** Read a list (possibly improper) of zero or more Scheme forms.
  50. * Assumes '(' has been read.
  51. */
  52. public Object read (Lexer in, int ch, int count, int sharingIndex)
  53. throws java.io.IOException, SyntaxException
  54. {
  55. Object p = null;
  56. if (command != null)
  57. {
  58. InPort port = in.getPort();
  59. int startLine = port.getLineNumber();
  60. int startColumn = port.getColumnNumber();
  61. // startColumn is the 0-based position *after* reading ch.
  62. // We want the position *before* reading ch.
  63. // (makePair converts from 0-based to 1-based.)
  64. p = ((LispReader) in).makePair(command, startLine, startColumn-1);
  65. ((LispReader) in).bindSharedObject(sharingIndex, p);
  66. sharingIndex = -1;
  67. }
  68. return readList((LispReader) in, p, ch, count, close, sharingIndex);
  69. }
  70. public static Object readList (LispReader lexer, Object last,
  71. int ch, int count, int close, int sharingIndex)
  72. throws java.io.IOException, SyntaxException
  73. {
  74. InPort port = lexer.getPort();
  75. char saveReadState = lexer.pushNesting(close == ']' ? '[' : '(');
  76. int startLine = port.getLineNumber();
  77. int startColumn = port.getColumnNumber();
  78. try
  79. {
  80. Object list = last == null ? lexer.makeNil() : last;
  81. boolean sawDot = false;
  82. boolean sawDotCdr = false;
  83. ReadTable readTable = ReadTable.getCurrent();
  84. for (;;)
  85. {
  86. int line = port.getLineNumber();
  87. int column = port.getColumnNumber();
  88. ch = port.read();
  89. if (ch == close)
  90. break;
  91. if (ch < 0) {
  92. if (lexer.isTentative()) {
  93. Object value = gnu.lists.Pair.incompleteListMarker;
  94. if (last == null)
  95. list = value;
  96. else
  97. lexer.setCdr(last, value);
  98. return list;
  99. }
  100. lexer.eofError("unexpected EOF in list starting here",
  101. startLine + 1, startColumn);
  102. }
  103. ReadTableEntry entry;
  104. if (ch == '.')
  105. {
  106. ch = port.peek();
  107. entry = readTable.lookup(ch);
  108. int kind = entry.getKind();
  109. if (kind == ReadTable.WHITESPACE
  110. || kind == ReadTable.TERMINATING_MACRO
  111. || kind == ReadTable.ILLEGAL)
  112. {
  113. port.skip();
  114. column++;
  115. if (ch == close)
  116. {
  117. lexer.error("unexpected '"
  118. + ((char) close) + "' after '.'");
  119. break;
  120. }
  121. if (ch < 0)
  122. lexer.eofError("unexpected EOF in list starting here",
  123. startLine + 1, startColumn);
  124. if (sawDot)
  125. {
  126. lexer.error("multiple '.' in list");
  127. sawDotCdr = false;
  128. list = lexer.makeNil();
  129. last = null;
  130. }
  131. sawDot = true;
  132. }
  133. else
  134. {
  135. // Treat '.' as start of token.
  136. ch = '.';
  137. entry = ReadTableEntry.getConstituentInstance();
  138. }
  139. }
  140. else
  141. entry = readTable.lookup(ch);
  142. if (entry.getKind() == ReadTable.WHITESPACE)
  143. continue;
  144. Object first = null;
  145. if (! sawDot && last == null)
  146. {
  147. first = lexer.makePair(null, line, column);
  148. lexer.bindSharedObject(sharingIndex, first);
  149. }
  150. Object value = lexer.readValues(ch, entry, readTable, -1);
  151. if (value == Values.empty)
  152. continue;
  153. value = lexer.handlePostfix(value, readTable, line, column);
  154. // ( a1 ... an . cdr) creates an n-element list ended by
  155. // cdr. If n==0, a reasonable (and common) extension is to
  156. // interpret this as a 0-element list ended by cdr - i.e.
  157. // just cdr by itself.
  158. if (sawDotCdr)
  159. {
  160. lexer.error("multiple values after '.'");
  161. last = null;
  162. list = lexer.makeNil();
  163. sawDotCdr = false;
  164. continue;
  165. }
  166. else if (sawDot)
  167. {
  168. sawDotCdr = true;
  169. }
  170. else
  171. {
  172. int endline = port.getLineNumber();
  173. int endcolumn = port.getColumnNumber();
  174. if (last == null)
  175. {
  176. lexer.setCar(first, value, endline+1, endcolumn+1);
  177. value = first;
  178. sharingIndex = -1;
  179. }
  180. else
  181. value = lexer.makePair(value, line, column,
  182. endline, endcolumn);
  183. }
  184. if (last == null)
  185. list = value;
  186. else
  187. lexer.setCdr(last, value);
  188. last = value;
  189. }
  190. if (sawDot && ! sawDotCdr)
  191. lexer.error("missing value after '.'");
  192. return lexer.bindSharedObject(sharingIndex, list);
  193. }
  194. finally
  195. {
  196. lexer.popNesting(saveReadState);
  197. }
  198. }
  199. }