annotate src/clojure/lang/LispReader.java @ 10:ef7dbbd6452c

added clojure source goodness
author Robert McIntyre <rlm@mit.edu>
date Sat, 21 Aug 2010 06:25:44 -0400
parents
children
rev   line source
rlm@10 1 /**
rlm@10 2 * Copyright (c) Rich Hickey. All rights reserved.
rlm@10 3 * The use and distribution terms for this software are covered by the
rlm@10 4 * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
rlm@10 5 * which can be found in the file epl-v10.html at the root of this distribution.
rlm@10 6 * By using this software in any fashion, you are agreeing to be bound by
rlm@10 7 * the terms of this license.
rlm@10 8 * You must not remove this notice, or any other, from this software.
rlm@10 9 **/
rlm@10 10
rlm@10 11 package clojure.lang;
rlm@10 12
rlm@10 13 import java.io.*;
rlm@10 14 import java.util.regex.Pattern;
rlm@10 15 import java.util.regex.Matcher;
rlm@10 16 import java.util.ArrayList;
rlm@10 17 import java.util.List;
rlm@10 18 import java.util.Map;
rlm@10 19 import java.math.BigInteger;
rlm@10 20 import java.math.BigDecimal;
rlm@10 21 import java.lang.*;
rlm@10 22
rlm@10 23 public class LispReader{
rlm@10 24
rlm@10 25 static final Symbol QUOTE = Symbol.create("quote");
rlm@10 26 static final Symbol THE_VAR = Symbol.create("var");
rlm@10 27 //static Symbol SYNTAX_QUOTE = Symbol.create(null, "syntax-quote");
rlm@10 28 static Symbol UNQUOTE = Symbol.create("clojure.core", "unquote");
rlm@10 29 static Symbol UNQUOTE_SPLICING = Symbol.create("clojure.core", "unquote-splicing");
rlm@10 30 static Symbol CONCAT = Symbol.create("clojure.core", "concat");
rlm@10 31 static Symbol SEQ = Symbol.create("clojure.core", "seq");
rlm@10 32 static Symbol LIST = Symbol.create("clojure.core", "list");
rlm@10 33 static Symbol APPLY = Symbol.create("clojure.core", "apply");
rlm@10 34 static Symbol HASHMAP = Symbol.create("clojure.core", "hash-map");
rlm@10 35 static Symbol HASHSET = Symbol.create("clojure.core", "hash-set");
rlm@10 36 static Symbol VECTOR = Symbol.create("clojure.core", "vector");
rlm@10 37 static Symbol WITH_META = Symbol.create("clojure.core", "with-meta");
rlm@10 38 static Symbol META = Symbol.create("clojure.core", "meta");
rlm@10 39 static Symbol DEREF = Symbol.create("clojure.core", "deref");
rlm@10 40 //static Symbol DEREF_BANG = Symbol.create("clojure.core", "deref!");
rlm@10 41
rlm@10 42 static IFn[] macros = new IFn[256];
rlm@10 43 static IFn[] dispatchMacros = new IFn[256];
rlm@10 44 //static Pattern symbolPat = Pattern.compile("[:]?([\\D&&[^:/]][^:/]*/)?[\\D&&[^:/]][^:/]*");
rlm@10 45 static Pattern symbolPat = Pattern.compile("[:]?([\\D&&[^/]].*/)?([\\D&&[^/]][^/]*)");
rlm@10 46 //static Pattern varPat = Pattern.compile("([\\D&&[^:\\.]][^:\\.]*):([\\D&&[^:\\.]][^:\\.]*)");
rlm@10 47 //static Pattern intPat = Pattern.compile("[-+]?[0-9]+\\.?");
rlm@10 48 static Pattern intPat =
rlm@10 49 Pattern.compile(
rlm@10 50 "([-+]?)(?:(0)|([1-9][0-9]*)|0[xX]([0-9A-Fa-f]+)|0([0-7]+)|([1-9][0-9]?)[rR]([0-9A-Za-z]+)|0[0-9]+)");
rlm@10 51 static Pattern ratioPat = Pattern.compile("([-+]?[0-9]+)/([0-9]+)");
rlm@10 52 static Pattern floatPat = Pattern.compile("([-+]?[0-9]+(\\.[0-9]*)?([eE][-+]?[0-9]+)?)(M)?");
rlm@10 53 static final Symbol SLASH = Symbol.create("/");
rlm@10 54 static final Symbol CLOJURE_SLASH = Symbol.create("clojure.core","/");
rlm@10 55 //static Pattern accessorPat = Pattern.compile("\\.[a-zA-Z_]\\w*");
rlm@10 56 //static Pattern instanceMemberPat = Pattern.compile("\\.([a-zA-Z_][\\w\\.]*)\\.([a-zA-Z_]\\w*)");
rlm@10 57 //static Pattern staticMemberPat = Pattern.compile("([a-zA-Z_][\\w\\.]*)\\.([a-zA-Z_]\\w*)");
rlm@10 58 //static Pattern classNamePat = Pattern.compile("([a-zA-Z_][\\w\\.]*)\\.");
rlm@10 59
rlm@10 60 //symbol->gensymbol
rlm@10 61 static Var GENSYM_ENV = Var.create(null);
rlm@10 62 //sorted-map num->gensymbol
rlm@10 63 static Var ARG_ENV = Var.create(null);
rlm@10 64
rlm@10 65 static
rlm@10 66 {
rlm@10 67 macros['"'] = new StringReader();
rlm@10 68 macros[';'] = new CommentReader();
rlm@10 69 macros['\''] = new WrappingReader(QUOTE);
rlm@10 70 macros['@'] = new WrappingReader(DEREF);//new DerefReader();
rlm@10 71 macros['^'] = new MetaReader();
rlm@10 72 macros['`'] = new SyntaxQuoteReader();
rlm@10 73 macros['~'] = new UnquoteReader();
rlm@10 74 macros['('] = new ListReader();
rlm@10 75 macros[')'] = new UnmatchedDelimiterReader();
rlm@10 76 macros['['] = new VectorReader();
rlm@10 77 macros[']'] = new UnmatchedDelimiterReader();
rlm@10 78 macros['{'] = new MapReader();
rlm@10 79 macros['}'] = new UnmatchedDelimiterReader();
rlm@10 80 // macros['|'] = new ArgVectorReader();
rlm@10 81 macros['\\'] = new CharacterReader();
rlm@10 82 macros['%'] = new ArgReader();
rlm@10 83 macros['#'] = new DispatchReader();
rlm@10 84
rlm@10 85
rlm@10 86 dispatchMacros['^'] = new MetaReader();
rlm@10 87 dispatchMacros['\''] = new VarReader();
rlm@10 88 dispatchMacros['"'] = new RegexReader();
rlm@10 89 dispatchMacros['('] = new FnReader();
rlm@10 90 dispatchMacros['{'] = new SetReader();
rlm@10 91 dispatchMacros['='] = new EvalReader();
rlm@10 92 dispatchMacros['!'] = new CommentReader();
rlm@10 93 dispatchMacros['<'] = new UnreadableReader();
rlm@10 94 dispatchMacros['_'] = new DiscardReader();
rlm@10 95 }
rlm@10 96
rlm@10 97 static boolean isWhitespace(int ch){
rlm@10 98 return Character.isWhitespace(ch) || ch == ',';
rlm@10 99 }
rlm@10 100
rlm@10 101 static void unread(PushbackReader r, int ch) throws IOException{
rlm@10 102 if(ch != -1)
rlm@10 103 r.unread(ch);
rlm@10 104 }
rlm@10 105
rlm@10 106 public static class ReaderException extends Exception{
rlm@10 107 final int line;
rlm@10 108
rlm@10 109 public ReaderException(int line, Throwable cause){
rlm@10 110 super(cause);
rlm@10 111 this.line = line;
rlm@10 112 }
rlm@10 113 }
rlm@10 114
rlm@10 115 static public Object read(PushbackReader r, boolean eofIsError, Object eofValue, boolean isRecursive)
rlm@10 116 throws Exception{
rlm@10 117
rlm@10 118 try
rlm@10 119 {
rlm@10 120 for(; ;)
rlm@10 121 {
rlm@10 122 int ch = r.read();
rlm@10 123
rlm@10 124 while(isWhitespace(ch))
rlm@10 125 ch = r.read();
rlm@10 126
rlm@10 127 if(ch == -1)
rlm@10 128 {
rlm@10 129 if(eofIsError)
rlm@10 130 throw new Exception("EOF while reading");
rlm@10 131 return eofValue;
rlm@10 132 }
rlm@10 133
rlm@10 134 if(Character.isDigit(ch))
rlm@10 135 {
rlm@10 136 Object n = readNumber(r, (char) ch);
rlm@10 137 if(RT.suppressRead())
rlm@10 138 return null;
rlm@10 139 return n;
rlm@10 140 }
rlm@10 141
rlm@10 142 IFn macroFn = getMacro(ch);
rlm@10 143 if(macroFn != null)
rlm@10 144 {
rlm@10 145 Object ret = macroFn.invoke(r, (char) ch);
rlm@10 146 if(RT.suppressRead())
rlm@10 147 return null;
rlm@10 148 //no op macros return the reader
rlm@10 149 if(ret == r)
rlm@10 150 continue;
rlm@10 151 return ret;
rlm@10 152 }
rlm@10 153
rlm@10 154 if(ch == '+' || ch == '-')
rlm@10 155 {
rlm@10 156 int ch2 = r.read();
rlm@10 157 if(Character.isDigit(ch2))
rlm@10 158 {
rlm@10 159 unread(r, ch2);
rlm@10 160 Object n = readNumber(r, (char) ch);
rlm@10 161 if(RT.suppressRead())
rlm@10 162 return null;
rlm@10 163 return n;
rlm@10 164 }
rlm@10 165 unread(r, ch2);
rlm@10 166 }
rlm@10 167
rlm@10 168 String token = readToken(r, (char) ch);
rlm@10 169 if(RT.suppressRead())
rlm@10 170 return null;
rlm@10 171 return interpretToken(token);
rlm@10 172 }
rlm@10 173 }
rlm@10 174 catch(Exception e)
rlm@10 175 {
rlm@10 176 if(isRecursive || !(r instanceof LineNumberingPushbackReader))
rlm@10 177 throw e;
rlm@10 178 LineNumberingPushbackReader rdr = (LineNumberingPushbackReader) r;
rlm@10 179 //throw new Exception(String.format("ReaderError:(%d,1) %s", rdr.getLineNumber(), e.getMessage()), e);
rlm@10 180 throw new ReaderException(rdr.getLineNumber(), e);
rlm@10 181 }
rlm@10 182 }
rlm@10 183
rlm@10 184 static private String readToken(PushbackReader r, char initch) throws Exception{
rlm@10 185 StringBuilder sb = new StringBuilder();
rlm@10 186 sb.append(initch);
rlm@10 187
rlm@10 188 for(; ;)
rlm@10 189 {
rlm@10 190 int ch = r.read();
rlm@10 191 if(ch == -1 || isWhitespace(ch) || isTerminatingMacro(ch))
rlm@10 192 {
rlm@10 193 unread(r, ch);
rlm@10 194 return sb.toString();
rlm@10 195 }
rlm@10 196 sb.append((char) ch);
rlm@10 197 }
rlm@10 198 }
rlm@10 199
rlm@10 200 static private Object readNumber(PushbackReader r, char initch) throws Exception{
rlm@10 201 StringBuilder sb = new StringBuilder();
rlm@10 202 sb.append(initch);
rlm@10 203
rlm@10 204 for(; ;)
rlm@10 205 {
rlm@10 206 int ch = r.read();
rlm@10 207 if(ch == -1 || isWhitespace(ch) || isMacro(ch))
rlm@10 208 {
rlm@10 209 unread(r, ch);
rlm@10 210 break;
rlm@10 211 }
rlm@10 212 sb.append((char) ch);
rlm@10 213 }
rlm@10 214
rlm@10 215 String s = sb.toString();
rlm@10 216 Object n = matchNumber(s);
rlm@10 217 if(n == null)
rlm@10 218 throw new NumberFormatException("Invalid number: " + s);
rlm@10 219 return n;
rlm@10 220 }
rlm@10 221
rlm@10 222 static private int readUnicodeChar(String token, int offset, int length, int base) throws Exception{
rlm@10 223 if(token.length() != offset + length)
rlm@10 224 throw new IllegalArgumentException("Invalid unicode character: \\" + token);
rlm@10 225 int uc = 0;
rlm@10 226 for(int i = offset; i < offset + length; ++i)
rlm@10 227 {
rlm@10 228 int d = Character.digit(token.charAt(i), base);
rlm@10 229 if(d == -1)
rlm@10 230 throw new IllegalArgumentException("Invalid digit: " + (char) d);
rlm@10 231 uc = uc * base + d;
rlm@10 232 }
rlm@10 233 return (char) uc;
rlm@10 234 }
rlm@10 235
rlm@10 236 static private int readUnicodeChar(PushbackReader r, int initch, int base, int length, boolean exact) throws Exception{
rlm@10 237 int uc = Character.digit(initch, base);
rlm@10 238 if(uc == -1)
rlm@10 239 throw new IllegalArgumentException("Invalid digit: " + initch);
rlm@10 240 int i = 1;
rlm@10 241 for(; i < length; ++i)
rlm@10 242 {
rlm@10 243 int ch = r.read();
rlm@10 244 if(ch == -1 || isWhitespace(ch) || isMacro(ch))
rlm@10 245 {
rlm@10 246 unread(r, ch);
rlm@10 247 break;
rlm@10 248 }
rlm@10 249 int d = Character.digit(ch, base);
rlm@10 250 if(d == -1)
rlm@10 251 throw new IllegalArgumentException("Invalid digit: " + (char) ch);
rlm@10 252 uc = uc * base + d;
rlm@10 253 }
rlm@10 254 if(i != length && exact)
rlm@10 255 throw new IllegalArgumentException("Invalid character length: " + i + ", should be: " + length);
rlm@10 256 return uc;
rlm@10 257 }
rlm@10 258
rlm@10 259 static private Object interpretToken(String s) throws Exception{
rlm@10 260 if(s.equals("nil"))
rlm@10 261 {
rlm@10 262 return null;
rlm@10 263 }
rlm@10 264 else if(s.equals("true"))
rlm@10 265 {
rlm@10 266 return RT.T;
rlm@10 267 }
rlm@10 268 else if(s.equals("false"))
rlm@10 269 {
rlm@10 270 return RT.F;
rlm@10 271 }
rlm@10 272 else if(s.equals("/"))
rlm@10 273 {
rlm@10 274 return SLASH;
rlm@10 275 }
rlm@10 276 else if(s.equals("clojure.core//"))
rlm@10 277 {
rlm@10 278 return CLOJURE_SLASH;
rlm@10 279 }
rlm@10 280 Object ret = null;
rlm@10 281
rlm@10 282 ret = matchSymbol(s);
rlm@10 283 if(ret != null)
rlm@10 284 return ret;
rlm@10 285
rlm@10 286 throw new Exception("Invalid token: " + s);
rlm@10 287 }
rlm@10 288
rlm@10 289
rlm@10 290 private static Object matchSymbol(String s){
rlm@10 291 Matcher m = symbolPat.matcher(s);
rlm@10 292 if(m.matches())
rlm@10 293 {
rlm@10 294 int gc = m.groupCount();
rlm@10 295 String ns = m.group(1);
rlm@10 296 String name = m.group(2);
rlm@10 297 if(ns != null && ns.endsWith(":/")
rlm@10 298 || name.endsWith(":")
rlm@10 299 || s.indexOf("::", 1) != -1)
rlm@10 300 return null;
rlm@10 301 if(s.startsWith("::"))
rlm@10 302 {
rlm@10 303 Symbol ks = Symbol.intern(s.substring(2));
rlm@10 304 Namespace kns;
rlm@10 305 if(ks.ns != null)
rlm@10 306 kns = Compiler.namespaceFor(ks);
rlm@10 307 else
rlm@10 308 kns = Compiler.currentNS();
rlm@10 309 //auto-resolving keyword
rlm@10 310 if (kns != null)
rlm@10 311 return Keyword.intern(kns.name.name,ks.name);
rlm@10 312 else
rlm@10 313 return null;
rlm@10 314 }
rlm@10 315 boolean isKeyword = s.charAt(0) == ':';
rlm@10 316 Symbol sym = Symbol.intern(s.substring(isKeyword ? 1 : 0));
rlm@10 317 if(isKeyword)
rlm@10 318 return Keyword.intern(sym);
rlm@10 319 return sym;
rlm@10 320 }
rlm@10 321 return null;
rlm@10 322 }
rlm@10 323
rlm@10 324
rlm@10 325 private static Object matchNumber(String s){
rlm@10 326 Matcher m = intPat.matcher(s);
rlm@10 327 if(m.matches())
rlm@10 328 {
rlm@10 329 if(m.group(2) != null)
rlm@10 330 return 0;
rlm@10 331 boolean negate = (m.group(1).equals("-"));
rlm@10 332 String n;
rlm@10 333 int radix = 10;
rlm@10 334 if((n = m.group(3)) != null)
rlm@10 335 radix = 10;
rlm@10 336 else if((n = m.group(4)) != null)
rlm@10 337 radix = 16;
rlm@10 338 else if((n = m.group(5)) != null)
rlm@10 339 radix = 8;
rlm@10 340 else if((n = m.group(7)) != null)
rlm@10 341 radix = Integer.parseInt(m.group(6));
rlm@10 342 if(n == null)
rlm@10 343 return null;
rlm@10 344 BigInteger bn = new BigInteger(n, radix);
rlm@10 345 return Numbers.reduce(negate ? bn.negate() : bn);
rlm@10 346 }
rlm@10 347 m = floatPat.matcher(s);
rlm@10 348 if(m.matches())
rlm@10 349 {
rlm@10 350 if(m.group(4) != null)
rlm@10 351 return new BigDecimal(m.group(1));
rlm@10 352 return Double.parseDouble(s);
rlm@10 353 }
rlm@10 354 m = ratioPat.matcher(s);
rlm@10 355 if(m.matches())
rlm@10 356 {
rlm@10 357 return Numbers.divide(new BigInteger(m.group(1)), new BigInteger(m.group(2)));
rlm@10 358 }
rlm@10 359 return null;
rlm@10 360 }
rlm@10 361
rlm@10 362 static private IFn getMacro(int ch){
rlm@10 363 if(ch < macros.length)
rlm@10 364 return macros[ch];
rlm@10 365 return null;
rlm@10 366 }
rlm@10 367
rlm@10 368 static private boolean isMacro(int ch){
rlm@10 369 return (ch < macros.length && macros[ch] != null);
rlm@10 370 }
rlm@10 371
rlm@10 372 static private boolean isTerminatingMacro(int ch){
rlm@10 373 return (ch != '#' && ch < macros.length && macros[ch] != null);
rlm@10 374 }
rlm@10 375
rlm@10 376 public static class RegexReader extends AFn{
rlm@10 377 static StringReader stringrdr = new StringReader();
rlm@10 378
rlm@10 379 public Object invoke(Object reader, Object doublequote) throws Exception{
rlm@10 380 StringBuilder sb = new StringBuilder();
rlm@10 381 Reader r = (Reader) reader;
rlm@10 382 for(int ch = r.read(); ch != '"'; ch = r.read())
rlm@10 383 {
rlm@10 384 if(ch == -1)
rlm@10 385 throw new Exception("EOF while reading regex");
rlm@10 386 sb.append( (char) ch );
rlm@10 387 if(ch == '\\') //escape
rlm@10 388 {
rlm@10 389 ch = r.read();
rlm@10 390 if(ch == -1)
rlm@10 391 throw new Exception("EOF while reading regex");
rlm@10 392 sb.append( (char) ch ) ;
rlm@10 393 }
rlm@10 394 }
rlm@10 395 return Pattern.compile(sb.toString());
rlm@10 396 }
rlm@10 397 }
rlm@10 398
rlm@10 399 public static class StringReader extends AFn{
rlm@10 400 public Object invoke(Object reader, Object doublequote) throws Exception{
rlm@10 401 StringBuilder sb = new StringBuilder();
rlm@10 402 Reader r = (Reader) reader;
rlm@10 403
rlm@10 404 for(int ch = r.read(); ch != '"'; ch = r.read())
rlm@10 405 {
rlm@10 406 if(ch == -1)
rlm@10 407 throw new Exception("EOF while reading string");
rlm@10 408 if(ch == '\\') //escape
rlm@10 409 {
rlm@10 410 ch = r.read();
rlm@10 411 if(ch == -1)
rlm@10 412 throw new Exception("EOF while reading string");
rlm@10 413 switch(ch)
rlm@10 414 {
rlm@10 415 case 't':
rlm@10 416 ch = '\t';
rlm@10 417 break;
rlm@10 418 case 'r':
rlm@10 419 ch = '\r';
rlm@10 420 break;
rlm@10 421 case 'n':
rlm@10 422 ch = '\n';
rlm@10 423 break;
rlm@10 424 case '\\':
rlm@10 425 break;
rlm@10 426 case '"':
rlm@10 427 break;
rlm@10 428 case 'b':
rlm@10 429 ch = '\b';
rlm@10 430 break;
rlm@10 431 case 'f':
rlm@10 432 ch = '\f';
rlm@10 433 break;
rlm@10 434 case 'u':
rlm@10 435 {
rlm@10 436 ch = r.read();
rlm@10 437 if (Character.digit(ch, 16) == -1)
rlm@10 438 throw new Exception("Invalid unicode escape: \\u" + (char) ch);
rlm@10 439 ch = readUnicodeChar((PushbackReader) r, ch, 16, 4, true);
rlm@10 440 break;
rlm@10 441 }
rlm@10 442 default:
rlm@10 443 {
rlm@10 444 if(Character.isDigit(ch))
rlm@10 445 {
rlm@10 446 ch = readUnicodeChar((PushbackReader) r, ch, 8, 3, false);
rlm@10 447 if(ch > 0377)
rlm@10 448 throw new Exception("Octal escape sequence must be in range [0, 377].");
rlm@10 449 }
rlm@10 450 else
rlm@10 451 throw new Exception("Unsupported escape character: \\" + (char) ch);
rlm@10 452 }
rlm@10 453 }
rlm@10 454 }
rlm@10 455 sb.append((char) ch);
rlm@10 456 }
rlm@10 457 return sb.toString();
rlm@10 458 }
rlm@10 459 }
rlm@10 460
rlm@10 461 public static class CommentReader extends AFn{
rlm@10 462 public Object invoke(Object reader, Object semicolon) throws Exception{
rlm@10 463 Reader r = (Reader) reader;
rlm@10 464 int ch;
rlm@10 465 do
rlm@10 466 {
rlm@10 467 ch = r.read();
rlm@10 468 } while(ch != -1 && ch != '\n' && ch != '\r');
rlm@10 469 return r;
rlm@10 470 }
rlm@10 471
rlm@10 472 }
rlm@10 473
rlm@10 474 public static class DiscardReader extends AFn{
rlm@10 475 public Object invoke(Object reader, Object underscore) throws Exception{
rlm@10 476 PushbackReader r = (PushbackReader) reader;
rlm@10 477 read(r, true, null, true);
rlm@10 478 return r;
rlm@10 479 }
rlm@10 480 }
rlm@10 481
rlm@10 482 public static class WrappingReader extends AFn{
rlm@10 483 final Symbol sym;
rlm@10 484
rlm@10 485 public WrappingReader(Symbol sym){
rlm@10 486 this.sym = sym;
rlm@10 487 }
rlm@10 488
rlm@10 489 public Object invoke(Object reader, Object quote) throws Exception{
rlm@10 490 PushbackReader r = (PushbackReader) reader;
rlm@10 491 Object o = read(r, true, null, true);
rlm@10 492 return RT.list(sym, o);
rlm@10 493 }
rlm@10 494
rlm@10 495 }
rlm@10 496
rlm@10 497 public static class DeprecatedWrappingReader extends AFn{
rlm@10 498 final Symbol sym;
rlm@10 499 final String macro;
rlm@10 500
rlm@10 501 public DeprecatedWrappingReader(Symbol sym, String macro){
rlm@10 502 this.sym = sym;
rlm@10 503 this.macro = macro;
rlm@10 504 }
rlm@10 505
rlm@10 506 public Object invoke(Object reader, Object quote) throws Exception{
rlm@10 507 System.out.println("WARNING: reader macro " + macro +
rlm@10 508 " is deprecated; use " + sym.getName() +
rlm@10 509 " instead");
rlm@10 510 PushbackReader r = (PushbackReader) reader;
rlm@10 511 Object o = read(r, true, null, true);
rlm@10 512 return RT.list(sym, o);
rlm@10 513 }
rlm@10 514
rlm@10 515 }
rlm@10 516
rlm@10 517 public static class VarReader extends AFn{
rlm@10 518 public Object invoke(Object reader, Object quote) throws Exception{
rlm@10 519 PushbackReader r = (PushbackReader) reader;
rlm@10 520 Object o = read(r, true, null, true);
rlm@10 521 // if(o instanceof Symbol)
rlm@10 522 // {
rlm@10 523 // Object v = Compiler.maybeResolveIn(Compiler.currentNS(), (Symbol) o);
rlm@10 524 // if(v instanceof Var)
rlm@10 525 // return v;
rlm@10 526 // }
rlm@10 527 return RT.list(THE_VAR, o);
rlm@10 528 }
rlm@10 529 }
rlm@10 530
rlm@10 531 /*
rlm@10 532 static class DerefReader extends AFn{
rlm@10 533
rlm@10 534 public Object invoke(Object reader, Object quote) throws Exception{
rlm@10 535 PushbackReader r = (PushbackReader) reader;
rlm@10 536 int ch = r.read();
rlm@10 537 if(ch == -1)
rlm@10 538 throw new Exception("EOF while reading character");
rlm@10 539 if(ch == '!')
rlm@10 540 {
rlm@10 541 Object o = read(r, true, null, true);
rlm@10 542 return RT.list(DEREF_BANG, o);
rlm@10 543 }
rlm@10 544 else
rlm@10 545 {
rlm@10 546 r.unread(ch);
rlm@10 547 Object o = read(r, true, null, true);
rlm@10 548 return RT.list(DEREF, o);
rlm@10 549 }
rlm@10 550 }
rlm@10 551
rlm@10 552 }
rlm@10 553 */
rlm@10 554
rlm@10 555 public static class DispatchReader extends AFn{
rlm@10 556 public Object invoke(Object reader, Object hash) throws Exception{
rlm@10 557 int ch = ((Reader) reader).read();
rlm@10 558 if(ch == -1)
rlm@10 559 throw new Exception("EOF while reading character");
rlm@10 560 IFn fn = dispatchMacros[ch];
rlm@10 561 if(fn == null)
rlm@10 562 throw new Exception(String.format("No dispatch macro for: %c", (char) ch));
rlm@10 563 return fn.invoke(reader, ch);
rlm@10 564 }
rlm@10 565 }
rlm@10 566
rlm@10 567 static Symbol garg(int n){
rlm@10 568 return Symbol.intern(null, (n == -1 ? "rest" : ("p" + n)) + "__" + RT.nextID() + "#");
rlm@10 569 }
rlm@10 570
rlm@10 571 public static class FnReader extends AFn{
rlm@10 572 public Object invoke(Object reader, Object lparen) throws Exception{
rlm@10 573 PushbackReader r = (PushbackReader) reader;
rlm@10 574 if(ARG_ENV.deref() != null)
rlm@10 575 throw new IllegalStateException("Nested #()s are not allowed");
rlm@10 576 try
rlm@10 577 {
rlm@10 578 Var.pushThreadBindings(
rlm@10 579 RT.map(ARG_ENV, PersistentTreeMap.EMPTY));
rlm@10 580 r.unread('(');
rlm@10 581 Object form = read(r, true, null, true);
rlm@10 582
rlm@10 583 PersistentVector args = PersistentVector.EMPTY;
rlm@10 584 PersistentTreeMap argsyms = (PersistentTreeMap) ARG_ENV.deref();
rlm@10 585 ISeq rargs = argsyms.rseq();
rlm@10 586 if(rargs != null)
rlm@10 587 {
rlm@10 588 int higharg = (Integer) ((Map.Entry) rargs.first()).getKey();
rlm@10 589 if(higharg > 0)
rlm@10 590 {
rlm@10 591 for(int i = 1; i <= higharg; ++i)
rlm@10 592 {
rlm@10 593 Object sym = argsyms.valAt(i);
rlm@10 594 if(sym == null)
rlm@10 595 sym = garg(i);
rlm@10 596 args = args.cons(sym);
rlm@10 597 }
rlm@10 598 }
rlm@10 599 Object restsym = argsyms.valAt(-1);
rlm@10 600 if(restsym != null)
rlm@10 601 {
rlm@10 602 args = args.cons(Compiler._AMP_);
rlm@10 603 args = args.cons(restsym);
rlm@10 604 }
rlm@10 605 }
rlm@10 606 return RT.list(Compiler.FN, args, form);
rlm@10 607 }
rlm@10 608 finally
rlm@10 609 {
rlm@10 610 Var.popThreadBindings();
rlm@10 611 }
rlm@10 612 }
rlm@10 613 }
rlm@10 614
rlm@10 615 static Symbol registerArg(int n){
rlm@10 616 PersistentTreeMap argsyms = (PersistentTreeMap) ARG_ENV.deref();
rlm@10 617 if(argsyms == null)
rlm@10 618 {
rlm@10 619 throw new IllegalStateException("arg literal not in #()");
rlm@10 620 }
rlm@10 621 Symbol ret = (Symbol) argsyms.valAt(n);
rlm@10 622 if(ret == null)
rlm@10 623 {
rlm@10 624 ret = garg(n);
rlm@10 625 ARG_ENV.set(argsyms.assoc(n, ret));
rlm@10 626 }
rlm@10 627 return ret;
rlm@10 628 }
rlm@10 629
rlm@10 630 static class ArgReader extends AFn{
rlm@10 631 public Object invoke(Object reader, Object pct) throws Exception{
rlm@10 632 PushbackReader r = (PushbackReader) reader;
rlm@10 633 if(ARG_ENV.deref() == null)
rlm@10 634 {
rlm@10 635 return interpretToken(readToken(r, '%'));
rlm@10 636 }
rlm@10 637 int ch = r.read();
rlm@10 638 unread(r, ch);
rlm@10 639 //% alone is first arg
rlm@10 640 if(ch == -1 || isWhitespace(ch) || isTerminatingMacro(ch))
rlm@10 641 {
rlm@10 642 return registerArg(1);
rlm@10 643 }
rlm@10 644 Object n = read(r, true, null, true);
rlm@10 645 if(n.equals(Compiler._AMP_))
rlm@10 646 return registerArg(-1);
rlm@10 647 if(!(n instanceof Number))
rlm@10 648 throw new IllegalStateException("arg literal must be %, %& or %integer");
rlm@10 649 return registerArg(((Number) n).intValue());
rlm@10 650 }
rlm@10 651 }
rlm@10 652
rlm@10 653 public static class MetaReader extends AFn{
rlm@10 654 public Object invoke(Object reader, Object caret) throws Exception{
rlm@10 655 PushbackReader r = (PushbackReader) reader;
rlm@10 656 int line = -1;
rlm@10 657 if(r instanceof LineNumberingPushbackReader)
rlm@10 658 line = ((LineNumberingPushbackReader) r).getLineNumber();
rlm@10 659 Object meta = read(r, true, null, true);
rlm@10 660 if(meta instanceof Symbol || meta instanceof Keyword || meta instanceof String)
rlm@10 661 meta = RT.map(RT.TAG_KEY, meta);
rlm@10 662 else if(!(meta instanceof IPersistentMap))
rlm@10 663 throw new IllegalArgumentException("Metadata must be Symbol,Keyword,String or Map");
rlm@10 664
rlm@10 665 Object o = read(r, true, null, true);
rlm@10 666 if(o instanceof IMeta)
rlm@10 667 {
rlm@10 668 if(line != -1 && o instanceof ISeq)
rlm@10 669 meta = ((IPersistentMap) meta).assoc(RT.LINE_KEY, line);
rlm@10 670 if(o instanceof IReference)
rlm@10 671 {
rlm@10 672 ((IReference)o).resetMeta((IPersistentMap) meta);
rlm@10 673 return o;
rlm@10 674 }
rlm@10 675 return ((IObj) o).withMeta((IPersistentMap) meta);
rlm@10 676 }
rlm@10 677 else
rlm@10 678 throw new IllegalArgumentException("Metadata can only be applied to IMetas");
rlm@10 679 }
rlm@10 680
rlm@10 681 }
rlm@10 682
rlm@10 683 public static class SyntaxQuoteReader extends AFn{
rlm@10 684 public Object invoke(Object reader, Object backquote) throws Exception{
rlm@10 685 PushbackReader r = (PushbackReader) reader;
rlm@10 686 try
rlm@10 687 {
rlm@10 688 Var.pushThreadBindings(
rlm@10 689 RT.map(GENSYM_ENV, PersistentHashMap.EMPTY));
rlm@10 690
rlm@10 691 Object form = read(r, true, null, true);
rlm@10 692 return syntaxQuote(form);
rlm@10 693 }
rlm@10 694 finally
rlm@10 695 {
rlm@10 696 Var.popThreadBindings();
rlm@10 697 }
rlm@10 698 }
rlm@10 699
rlm@10 700 static Object syntaxQuote(Object form) throws Exception{
rlm@10 701 Object ret;
rlm@10 702 if(Compiler.isSpecial(form))
rlm@10 703 ret = RT.list(Compiler.QUOTE, form);
rlm@10 704 else if(form instanceof Symbol)
rlm@10 705 {
rlm@10 706 Symbol sym = (Symbol) form;
rlm@10 707 if(sym.ns == null && sym.name.endsWith("#"))
rlm@10 708 {
rlm@10 709 IPersistentMap gmap = (IPersistentMap) GENSYM_ENV.deref();
rlm@10 710 if(gmap == null)
rlm@10 711 throw new IllegalStateException("Gensym literal not in syntax-quote");
rlm@10 712 Symbol gs = (Symbol) gmap.valAt(sym);
rlm@10 713 if(gs == null)
rlm@10 714 GENSYM_ENV.set(gmap.assoc(sym, gs = Symbol.intern(null,
rlm@10 715 sym.name.substring(0, sym.name.length() - 1)
rlm@10 716 + "__" + RT.nextID() + "__auto__")));
rlm@10 717 sym = gs;
rlm@10 718 }
rlm@10 719 else if(sym.ns == null && sym.name.endsWith("."))
rlm@10 720 {
rlm@10 721 Symbol csym = Symbol.intern(null, sym.name.substring(0, sym.name.length() - 1));
rlm@10 722 csym = Compiler.resolveSymbol(csym);
rlm@10 723 sym = Symbol.intern(null, csym.name.concat("."));
rlm@10 724 }
rlm@10 725 else if(sym.ns == null && sym.name.startsWith("."))
rlm@10 726 {
rlm@10 727 // Simply quote method names.
rlm@10 728 }
rlm@10 729 else
rlm@10 730 {
rlm@10 731 Object maybeClass = null;
rlm@10 732 if(sym.ns != null)
rlm@10 733 maybeClass = Compiler.currentNS().getMapping(
rlm@10 734 Symbol.intern(null, sym.ns));
rlm@10 735 if(maybeClass instanceof Class)
rlm@10 736 {
rlm@10 737 // Classname/foo -> package.qualified.Classname/foo
rlm@10 738 sym = Symbol.intern(
rlm@10 739 ((Class)maybeClass).getName(), sym.name);
rlm@10 740 }
rlm@10 741 else
rlm@10 742 sym = Compiler.resolveSymbol(sym);
rlm@10 743 }
rlm@10 744 ret = RT.list(Compiler.QUOTE, sym);
rlm@10 745 }
rlm@10 746 else if(isUnquote(form))
rlm@10 747 return RT.second(form);
rlm@10 748 else if(isUnquoteSplicing(form))
rlm@10 749 throw new IllegalStateException("splice not in list");
rlm@10 750 else if(form instanceof IPersistentCollection)
rlm@10 751 {
rlm@10 752 if(form instanceof IPersistentMap)
rlm@10 753 {
rlm@10 754 IPersistentVector keyvals = flattenMap(form);
rlm@10 755 ret = RT.list(APPLY, HASHMAP, RT.list(SEQ, RT.cons(CONCAT, sqExpandList(keyvals.seq()))));
rlm@10 756 }
rlm@10 757 else if(form instanceof IPersistentVector)
rlm@10 758 {
rlm@10 759 ret = RT.list(APPLY, VECTOR, RT.list(SEQ, RT.cons(CONCAT, sqExpandList(((IPersistentVector) form).seq()))));
rlm@10 760 }
rlm@10 761 else if(form instanceof IPersistentSet)
rlm@10 762 {
rlm@10 763 ret = RT.list(APPLY, HASHSET, RT.list(SEQ, RT.cons(CONCAT, sqExpandList(((IPersistentSet) form).seq()))));
rlm@10 764 }
rlm@10 765 else if(form instanceof ISeq || form instanceof IPersistentList)
rlm@10 766 {
rlm@10 767 ISeq seq = RT.seq(form);
rlm@10 768 if(seq == null)
rlm@10 769 ret = RT.cons(LIST,null);
rlm@10 770 else
rlm@10 771 ret = RT.list(SEQ, RT.cons(CONCAT, sqExpandList(seq)));
rlm@10 772 }
rlm@10 773 else
rlm@10 774 throw new UnsupportedOperationException("Unknown Collection type");
rlm@10 775 }
rlm@10 776 else if(form instanceof Keyword
rlm@10 777 || form instanceof Number
rlm@10 778 || form instanceof Character
rlm@10 779 || form instanceof String)
rlm@10 780 ret = form;
rlm@10 781 else
rlm@10 782 ret = RT.list(Compiler.QUOTE, form);
rlm@10 783
rlm@10 784 if(form instanceof IObj && RT.meta(form) != null)
rlm@10 785 {
rlm@10 786 //filter line numbers
rlm@10 787 IPersistentMap newMeta = ((IObj) form).meta().without(RT.LINE_KEY);
rlm@10 788 if(newMeta.count() > 0)
rlm@10 789 return RT.list(WITH_META, ret, syntaxQuote(((IObj) form).meta()));
rlm@10 790 }
rlm@10 791 return ret;
rlm@10 792 }
rlm@10 793
rlm@10 794 private static ISeq sqExpandList(ISeq seq) throws Exception{
rlm@10 795 PersistentVector ret = PersistentVector.EMPTY;
rlm@10 796 for(; seq != null; seq = seq.next())
rlm@10 797 {
rlm@10 798 Object item = seq.first();
rlm@10 799 if(isUnquote(item))
rlm@10 800 ret = ret.cons(RT.list(LIST, RT.second(item)));
rlm@10 801 else if(isUnquoteSplicing(item))
rlm@10 802 ret = ret.cons(RT.second(item));
rlm@10 803 else
rlm@10 804 ret = ret.cons(RT.list(LIST, syntaxQuote(item)));
rlm@10 805 }
rlm@10 806 return ret.seq();
rlm@10 807 }
rlm@10 808
rlm@10 809 private static IPersistentVector flattenMap(Object form){
rlm@10 810 IPersistentVector keyvals = PersistentVector.EMPTY;
rlm@10 811 for(ISeq s = RT.seq(form); s != null; s = s.next())
rlm@10 812 {
rlm@10 813 IMapEntry e = (IMapEntry) s.first();
rlm@10 814 keyvals = (IPersistentVector) keyvals.cons(e.key());
rlm@10 815 keyvals = (IPersistentVector) keyvals.cons(e.val());
rlm@10 816 }
rlm@10 817 return keyvals;
rlm@10 818 }
rlm@10 819
rlm@10 820 }
rlm@10 821
rlm@10 822 static boolean isUnquoteSplicing(Object form){
rlm@10 823 return form instanceof ISeq && Util.equals(RT.first(form),UNQUOTE_SPLICING);
rlm@10 824 }
rlm@10 825
rlm@10 826 static boolean isUnquote(Object form){
rlm@10 827 return form instanceof ISeq && Util.equals(RT.first(form),UNQUOTE);
rlm@10 828 }
rlm@10 829
rlm@10 830 static class UnquoteReader extends AFn{
rlm@10 831 public Object invoke(Object reader, Object comma) throws Exception{
rlm@10 832 PushbackReader r = (PushbackReader) reader;
rlm@10 833 int ch = r.read();
rlm@10 834 if(ch == -1)
rlm@10 835 throw new Exception("EOF while reading character");
rlm@10 836 if(ch == '@')
rlm@10 837 {
rlm@10 838 Object o = read(r, true, null, true);
rlm@10 839 return RT.list(UNQUOTE_SPLICING, o);
rlm@10 840 }
rlm@10 841 else
rlm@10 842 {
rlm@10 843 unread(r, ch);
rlm@10 844 Object o = read(r, true, null, true);
rlm@10 845 return RT.list(UNQUOTE, o);
rlm@10 846 }
rlm@10 847 }
rlm@10 848
rlm@10 849 }
rlm@10 850
rlm@10 851 public static class CharacterReader extends AFn{
rlm@10 852 public Object invoke(Object reader, Object backslash) throws Exception{
rlm@10 853 PushbackReader r = (PushbackReader) reader;
rlm@10 854 int ch = r.read();
rlm@10 855 if(ch == -1)
rlm@10 856 throw new Exception("EOF while reading character");
rlm@10 857 String token = readToken(r, (char) ch);
rlm@10 858 if(token.length() == 1)
rlm@10 859 return Character.valueOf(token.charAt(0));
rlm@10 860 else if(token.equals("newline"))
rlm@10 861 return '\n';
rlm@10 862 else if(token.equals("space"))
rlm@10 863 return ' ';
rlm@10 864 else if(token.equals("tab"))
rlm@10 865 return '\t';
rlm@10 866 else if(token.equals("backspace"))
rlm@10 867 return '\b';
rlm@10 868 else if(token.equals("formfeed"))
rlm@10 869 return '\f';
rlm@10 870 else if(token.equals("return"))
rlm@10 871 return '\r';
rlm@10 872 else if(token.startsWith("u"))
rlm@10 873 {
rlm@10 874 char c = (char) readUnicodeChar(token, 1, 4, 16);
rlm@10 875 if(c >= '\uD800' && c <= '\uDFFF') // surrogate code unit?
rlm@10 876 throw new Exception("Invalid character constant: \\u" + Integer.toString(c, 16));
rlm@10 877 return c;
rlm@10 878 }
rlm@10 879 else if(token.startsWith("o"))
rlm@10 880 {
rlm@10 881 int len = token.length() - 1;
rlm@10 882 if(len > 3)
rlm@10 883 throw new Exception("Invalid octal escape sequence length: " + len);
rlm@10 884 int uc = readUnicodeChar(token, 1, len, 8);
rlm@10 885 if(uc > 0377)
rlm@10 886 throw new Exception("Octal escape sequence must be in range [0, 377].");
rlm@10 887 return (char) uc;
rlm@10 888 }
rlm@10 889 throw new Exception("Unsupported character: \\" + token);
rlm@10 890 }
rlm@10 891
rlm@10 892 }
rlm@10 893
rlm@10 894 public static class ListReader extends AFn{
rlm@10 895 public Object invoke(Object reader, Object leftparen) throws Exception{
rlm@10 896 PushbackReader r = (PushbackReader) reader;
rlm@10 897 int line = -1;
rlm@10 898 if(r instanceof LineNumberingPushbackReader)
rlm@10 899 line = ((LineNumberingPushbackReader) r).getLineNumber();
rlm@10 900 List list = readDelimitedList(')', r, true);
rlm@10 901 if(list.isEmpty())
rlm@10 902 return PersistentList.EMPTY;
rlm@10 903 IObj s = (IObj) PersistentList.create(list);
rlm@10 904 // IObj s = (IObj) RT.seq(list);
rlm@10 905 if(line != -1)
rlm@10 906 return s.withMeta(RT.map(RT.LINE_KEY, line));
rlm@10 907 else
rlm@10 908 return s;
rlm@10 909 }
rlm@10 910
rlm@10 911 }
rlm@10 912
rlm@10 913 static class CtorReader extends AFn{
rlm@10 914 static final Symbol cls = Symbol.create("class");
rlm@10 915
rlm@10 916 public Object invoke(Object reader, Object leftangle) throws Exception{
rlm@10 917 PushbackReader r = (PushbackReader) reader;
rlm@10 918 // #<class classname>
rlm@10 919 // #<classname args*>
rlm@10 920 // #<classname/staticMethod args*>
rlm@10 921 List list = readDelimitedList('>', r, true);
rlm@10 922 if(list.isEmpty())
rlm@10 923 throw new Exception("Must supply 'class', classname or classname/staticMethod");
rlm@10 924 Symbol s = (Symbol) list.get(0);
rlm@10 925 Object[] args = list.subList(1, list.size()).toArray();
rlm@10 926 if(s.equals(cls))
rlm@10 927 {
rlm@10 928 return RT.classForName(args[0].toString());
rlm@10 929 }
rlm@10 930 else if(s.ns != null) //static method
rlm@10 931 {
rlm@10 932 String classname = s.ns;
rlm@10 933 String method = s.name;
rlm@10 934 return Reflector.invokeStaticMethod(classname, method, args);
rlm@10 935 }
rlm@10 936 else
rlm@10 937 {
rlm@10 938 return Reflector.invokeConstructor(RT.classForName(s.name), args);
rlm@10 939 }
rlm@10 940 }
rlm@10 941
rlm@10 942 }
rlm@10 943
rlm@10 944 public static class EvalReader extends AFn{
rlm@10 945 public Object invoke(Object reader, Object eq) throws Exception{
rlm@10 946 if (!RT.booleanCast(RT.READEVAL.deref()))
rlm@10 947 {
rlm@10 948 throw new Exception("EvalReader not allowed when *read-eval* is false.");
rlm@10 949 }
rlm@10 950
rlm@10 951 PushbackReader r = (PushbackReader) reader;
rlm@10 952 Object o = read(r, true, null, true);
rlm@10 953 if(o instanceof Symbol)
rlm@10 954 {
rlm@10 955 return RT.classForName(o.toString());
rlm@10 956 }
rlm@10 957 else if(o instanceof IPersistentList)
rlm@10 958 {
rlm@10 959 Symbol fs = (Symbol) RT.first(o);
rlm@10 960 if(fs.equals(THE_VAR))
rlm@10 961 {
rlm@10 962 Symbol vs = (Symbol) RT.second(o);
rlm@10 963 return RT.var(vs.ns, vs.name); //Compiler.resolve((Symbol) RT.second(o),true);
rlm@10 964 }
rlm@10 965 if(fs.name.endsWith("."))
rlm@10 966 {
rlm@10 967 Object[] args = RT.toArray(RT.next(o));
rlm@10 968 return Reflector.invokeConstructor(RT.classForName(fs.name.substring(0, fs.name.length() - 1)), args);
rlm@10 969 }
rlm@10 970 if(Compiler.namesStaticMember(fs))
rlm@10 971 {
rlm@10 972 Object[] args = RT.toArray(RT.next(o));
rlm@10 973 return Reflector.invokeStaticMethod(fs.ns, fs.name, args);
rlm@10 974 }
rlm@10 975 Object v = Compiler.maybeResolveIn(Compiler.currentNS(), fs);
rlm@10 976 if(v instanceof Var)
rlm@10 977 {
rlm@10 978 return ((IFn) v).applyTo(RT.next(o));
rlm@10 979 }
rlm@10 980 throw new Exception("Can't resolve " + fs);
rlm@10 981 }
rlm@10 982 else
rlm@10 983 throw new IllegalArgumentException("Unsupported #= form");
rlm@10 984 }
rlm@10 985 }
rlm@10 986
rlm@10 987 //static class ArgVectorReader extends AFn{
rlm@10 988 // public Object invoke(Object reader, Object leftparen) throws Exception{
rlm@10 989 // PushbackReader r = (PushbackReader) reader;
rlm@10 990 // return ArgVector.create(readDelimitedList('|', r, true));
rlm@10 991 // }
rlm@10 992 //
rlm@10 993 //}
rlm@10 994
rlm@10 995 public static class VectorReader extends AFn{
rlm@10 996 public Object invoke(Object reader, Object leftparen) throws Exception{
rlm@10 997 PushbackReader r = (PushbackReader) reader;
rlm@10 998 return LazilyPersistentVector.create(readDelimitedList(']', r, true));
rlm@10 999 }
rlm@10 1000
rlm@10 1001 }
rlm@10 1002
rlm@10 1003 public static class MapReader extends AFn{
rlm@10 1004 public Object invoke(Object reader, Object leftparen) throws Exception{
rlm@10 1005 PushbackReader r = (PushbackReader) reader;
rlm@10 1006 return RT.map(readDelimitedList('}', r, true).toArray());
rlm@10 1007 }
rlm@10 1008
rlm@10 1009 }
rlm@10 1010
rlm@10 1011 public static class SetReader extends AFn{
rlm@10 1012 public Object invoke(Object reader, Object leftbracket) throws Exception{
rlm@10 1013 PushbackReader r = (PushbackReader) reader;
rlm@10 1014 return PersistentHashSet.createWithCheck(readDelimitedList('}', r, true));
rlm@10 1015 }
rlm@10 1016
rlm@10 1017 }
rlm@10 1018
rlm@10 1019 public static class UnmatchedDelimiterReader extends AFn{
rlm@10 1020 public Object invoke(Object reader, Object rightdelim) throws Exception{
rlm@10 1021 throw new Exception("Unmatched delimiter: " + rightdelim);
rlm@10 1022 }
rlm@10 1023
rlm@10 1024 }
rlm@10 1025
rlm@10 1026 public static class UnreadableReader extends AFn{
rlm@10 1027 public Object invoke(Object reader, Object leftangle) throws Exception{
rlm@10 1028 throw new Exception("Unreadable form");
rlm@10 1029 }
rlm@10 1030 }
rlm@10 1031
rlm@10 1032 public static List readDelimitedList(char delim, PushbackReader r, boolean isRecursive) throws Exception{
rlm@10 1033 ArrayList a = new ArrayList();
rlm@10 1034
rlm@10 1035 for(; ;)
rlm@10 1036 {
rlm@10 1037 int ch = r.read();
rlm@10 1038
rlm@10 1039 while(isWhitespace(ch))
rlm@10 1040 ch = r.read();
rlm@10 1041
rlm@10 1042 if(ch == -1)
rlm@10 1043 throw new Exception("EOF while reading");
rlm@10 1044
rlm@10 1045 if(ch == delim)
rlm@10 1046 break;
rlm@10 1047
rlm@10 1048 IFn macroFn = getMacro(ch);
rlm@10 1049 if(macroFn != null)
rlm@10 1050 {
rlm@10 1051 Object mret = macroFn.invoke(r, (char) ch);
rlm@10 1052 //no op macros return the reader
rlm@10 1053 if(mret != r)
rlm@10 1054 a.add(mret);
rlm@10 1055 }
rlm@10 1056 else
rlm@10 1057 {
rlm@10 1058 unread(r, ch);
rlm@10 1059
rlm@10 1060 Object o = read(r, true, null, isRecursive);
rlm@10 1061 if(o != r)
rlm@10 1062 a.add(o);
rlm@10 1063 }
rlm@10 1064 }
rlm@10 1065
rlm@10 1066
rlm@10 1067 return a;
rlm@10 1068 }
rlm@10 1069
rlm@10 1070 /*
rlm@10 1071 public static void main(String[] args) throws Exception{
rlm@10 1072 //RT.init();
rlm@10 1073 PushbackReader rdr = new PushbackReader( new java.io.StringReader( "(+ 21 21)" ) );
rlm@10 1074 Object input = LispReader.read(rdr, false, new Object(), false );
rlm@10 1075 System.out.println(Compiler.eval(input));
rlm@10 1076 }
rlm@10 1077
rlm@10 1078 public static void main(String[] args){
rlm@10 1079 LineNumberingPushbackReader r = new LineNumberingPushbackReader(new InputStreamReader(System.in));
rlm@10 1080 OutputStreamWriter w = new OutputStreamWriter(System.out);
rlm@10 1081 Object ret = null;
rlm@10 1082 try
rlm@10 1083 {
rlm@10 1084 for(; ;)
rlm@10 1085 {
rlm@10 1086 ret = LispReader.read(r, true, null, false);
rlm@10 1087 RT.print(ret, w);
rlm@10 1088 w.write('\n');
rlm@10 1089 if(ret != null)
rlm@10 1090 w.write(ret.getClass().toString());
rlm@10 1091 w.write('\n');
rlm@10 1092 w.flush();
rlm@10 1093 }
rlm@10 1094 }
rlm@10 1095 catch(Exception e)
rlm@10 1096 {
rlm@10 1097 e.printStackTrace();
rlm@10 1098 }
rlm@10 1099 }
rlm@10 1100 */
rlm@10 1101
rlm@10 1102 }
rlm@10 1103