Mercurial > lasercutter
diff 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 |
line wrap: on
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/clojure/lang/LispReader.java Sat Aug 21 06:25:44 2010 -0400 1.3 @@ -0,0 +1,1103 @@ 1.4 +/** 1.5 + * Copyright (c) Rich Hickey. All rights reserved. 1.6 + * The use and distribution terms for this software are covered by the 1.7 + * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) 1.8 + * which can be found in the file epl-v10.html at the root of this distribution. 1.9 + * By using this software in any fashion, you are agreeing to be bound by 1.10 + * the terms of this license. 1.11 + * You must not remove this notice, or any other, from this software. 1.12 + **/ 1.13 + 1.14 +package clojure.lang; 1.15 + 1.16 +import java.io.*; 1.17 +import java.util.regex.Pattern; 1.18 +import java.util.regex.Matcher; 1.19 +import java.util.ArrayList; 1.20 +import java.util.List; 1.21 +import java.util.Map; 1.22 +import java.math.BigInteger; 1.23 +import java.math.BigDecimal; 1.24 +import java.lang.*; 1.25 + 1.26 +public class LispReader{ 1.27 + 1.28 +static final Symbol QUOTE = Symbol.create("quote"); 1.29 +static final Symbol THE_VAR = Symbol.create("var"); 1.30 +//static Symbol SYNTAX_QUOTE = Symbol.create(null, "syntax-quote"); 1.31 +static Symbol UNQUOTE = Symbol.create("clojure.core", "unquote"); 1.32 +static Symbol UNQUOTE_SPLICING = Symbol.create("clojure.core", "unquote-splicing"); 1.33 +static Symbol CONCAT = Symbol.create("clojure.core", "concat"); 1.34 +static Symbol SEQ = Symbol.create("clojure.core", "seq"); 1.35 +static Symbol LIST = Symbol.create("clojure.core", "list"); 1.36 +static Symbol APPLY = Symbol.create("clojure.core", "apply"); 1.37 +static Symbol HASHMAP = Symbol.create("clojure.core", "hash-map"); 1.38 +static Symbol HASHSET = Symbol.create("clojure.core", "hash-set"); 1.39 +static Symbol VECTOR = Symbol.create("clojure.core", "vector"); 1.40 +static Symbol WITH_META = Symbol.create("clojure.core", "with-meta"); 1.41 +static Symbol META = Symbol.create("clojure.core", "meta"); 1.42 +static Symbol DEREF = Symbol.create("clojure.core", "deref"); 1.43 +//static Symbol DEREF_BANG = Symbol.create("clojure.core", "deref!"); 1.44 + 1.45 +static IFn[] macros = new IFn[256]; 1.46 +static IFn[] dispatchMacros = new IFn[256]; 1.47 +//static Pattern symbolPat = Pattern.compile("[:]?([\\D&&[^:/]][^:/]*/)?[\\D&&[^:/]][^:/]*"); 1.48 +static Pattern symbolPat = Pattern.compile("[:]?([\\D&&[^/]].*/)?([\\D&&[^/]][^/]*)"); 1.49 +//static Pattern varPat = Pattern.compile("([\\D&&[^:\\.]][^:\\.]*):([\\D&&[^:\\.]][^:\\.]*)"); 1.50 +//static Pattern intPat = Pattern.compile("[-+]?[0-9]+\\.?"); 1.51 +static Pattern intPat = 1.52 + Pattern.compile( 1.53 + "([-+]?)(?:(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]+)"); 1.54 +static Pattern ratioPat = Pattern.compile("([-+]?[0-9]+)/([0-9]+)"); 1.55 +static Pattern floatPat = Pattern.compile("([-+]?[0-9]+(\\.[0-9]*)?([eE][-+]?[0-9]+)?)(M)?"); 1.56 +static final Symbol SLASH = Symbol.create("/"); 1.57 +static final Symbol CLOJURE_SLASH = Symbol.create("clojure.core","/"); 1.58 +//static Pattern accessorPat = Pattern.compile("\\.[a-zA-Z_]\\w*"); 1.59 +//static Pattern instanceMemberPat = Pattern.compile("\\.([a-zA-Z_][\\w\\.]*)\\.([a-zA-Z_]\\w*)"); 1.60 +//static Pattern staticMemberPat = Pattern.compile("([a-zA-Z_][\\w\\.]*)\\.([a-zA-Z_]\\w*)"); 1.61 +//static Pattern classNamePat = Pattern.compile("([a-zA-Z_][\\w\\.]*)\\."); 1.62 + 1.63 +//symbol->gensymbol 1.64 +static Var GENSYM_ENV = Var.create(null); 1.65 +//sorted-map num->gensymbol 1.66 +static Var ARG_ENV = Var.create(null); 1.67 + 1.68 + static 1.69 + { 1.70 + macros['"'] = new StringReader(); 1.71 + macros[';'] = new CommentReader(); 1.72 + macros['\''] = new WrappingReader(QUOTE); 1.73 + macros['@'] = new WrappingReader(DEREF);//new DerefReader(); 1.74 + macros['^'] = new MetaReader(); 1.75 + macros['`'] = new SyntaxQuoteReader(); 1.76 + macros['~'] = new UnquoteReader(); 1.77 + macros['('] = new ListReader(); 1.78 + macros[')'] = new UnmatchedDelimiterReader(); 1.79 + macros['['] = new VectorReader(); 1.80 + macros[']'] = new UnmatchedDelimiterReader(); 1.81 + macros['{'] = new MapReader(); 1.82 + macros['}'] = new UnmatchedDelimiterReader(); 1.83 +// macros['|'] = new ArgVectorReader(); 1.84 + macros['\\'] = new CharacterReader(); 1.85 + macros['%'] = new ArgReader(); 1.86 + macros['#'] = new DispatchReader(); 1.87 + 1.88 + 1.89 + dispatchMacros['^'] = new MetaReader(); 1.90 + dispatchMacros['\''] = new VarReader(); 1.91 + dispatchMacros['"'] = new RegexReader(); 1.92 + dispatchMacros['('] = new FnReader(); 1.93 + dispatchMacros['{'] = new SetReader(); 1.94 + dispatchMacros['='] = new EvalReader(); 1.95 + dispatchMacros['!'] = new CommentReader(); 1.96 + dispatchMacros['<'] = new UnreadableReader(); 1.97 + dispatchMacros['_'] = new DiscardReader(); 1.98 + } 1.99 + 1.100 +static boolean isWhitespace(int ch){ 1.101 + return Character.isWhitespace(ch) || ch == ','; 1.102 +} 1.103 + 1.104 +static void unread(PushbackReader r, int ch) throws IOException{ 1.105 + if(ch != -1) 1.106 + r.unread(ch); 1.107 +} 1.108 + 1.109 +public static class ReaderException extends Exception{ 1.110 + final int line; 1.111 + 1.112 + public ReaderException(int line, Throwable cause){ 1.113 + super(cause); 1.114 + this.line = line; 1.115 + } 1.116 +} 1.117 + 1.118 +static public Object read(PushbackReader r, boolean eofIsError, Object eofValue, boolean isRecursive) 1.119 + throws Exception{ 1.120 + 1.121 + try 1.122 + { 1.123 + for(; ;) 1.124 + { 1.125 + int ch = r.read(); 1.126 + 1.127 + while(isWhitespace(ch)) 1.128 + ch = r.read(); 1.129 + 1.130 + if(ch == -1) 1.131 + { 1.132 + if(eofIsError) 1.133 + throw new Exception("EOF while reading"); 1.134 + return eofValue; 1.135 + } 1.136 + 1.137 + if(Character.isDigit(ch)) 1.138 + { 1.139 + Object n = readNumber(r, (char) ch); 1.140 + if(RT.suppressRead()) 1.141 + return null; 1.142 + return n; 1.143 + } 1.144 + 1.145 + IFn macroFn = getMacro(ch); 1.146 + if(macroFn != null) 1.147 + { 1.148 + Object ret = macroFn.invoke(r, (char) ch); 1.149 + if(RT.suppressRead()) 1.150 + return null; 1.151 + //no op macros return the reader 1.152 + if(ret == r) 1.153 + continue; 1.154 + return ret; 1.155 + } 1.156 + 1.157 + if(ch == '+' || ch == '-') 1.158 + { 1.159 + int ch2 = r.read(); 1.160 + if(Character.isDigit(ch2)) 1.161 + { 1.162 + unread(r, ch2); 1.163 + Object n = readNumber(r, (char) ch); 1.164 + if(RT.suppressRead()) 1.165 + return null; 1.166 + return n; 1.167 + } 1.168 + unread(r, ch2); 1.169 + } 1.170 + 1.171 + String token = readToken(r, (char) ch); 1.172 + if(RT.suppressRead()) 1.173 + return null; 1.174 + return interpretToken(token); 1.175 + } 1.176 + } 1.177 + catch(Exception e) 1.178 + { 1.179 + if(isRecursive || !(r instanceof LineNumberingPushbackReader)) 1.180 + throw e; 1.181 + LineNumberingPushbackReader rdr = (LineNumberingPushbackReader) r; 1.182 + //throw new Exception(String.format("ReaderError:(%d,1) %s", rdr.getLineNumber(), e.getMessage()), e); 1.183 + throw new ReaderException(rdr.getLineNumber(), e); 1.184 + } 1.185 +} 1.186 + 1.187 +static private String readToken(PushbackReader r, char initch) throws Exception{ 1.188 + StringBuilder sb = new StringBuilder(); 1.189 + sb.append(initch); 1.190 + 1.191 + for(; ;) 1.192 + { 1.193 + int ch = r.read(); 1.194 + if(ch == -1 || isWhitespace(ch) || isTerminatingMacro(ch)) 1.195 + { 1.196 + unread(r, ch); 1.197 + return sb.toString(); 1.198 + } 1.199 + sb.append((char) ch); 1.200 + } 1.201 +} 1.202 + 1.203 +static private Object readNumber(PushbackReader r, char initch) throws Exception{ 1.204 + StringBuilder sb = new StringBuilder(); 1.205 + sb.append(initch); 1.206 + 1.207 + for(; ;) 1.208 + { 1.209 + int ch = r.read(); 1.210 + if(ch == -1 || isWhitespace(ch) || isMacro(ch)) 1.211 + { 1.212 + unread(r, ch); 1.213 + break; 1.214 + } 1.215 + sb.append((char) ch); 1.216 + } 1.217 + 1.218 + String s = sb.toString(); 1.219 + Object n = matchNumber(s); 1.220 + if(n == null) 1.221 + throw new NumberFormatException("Invalid number: " + s); 1.222 + return n; 1.223 +} 1.224 + 1.225 +static private int readUnicodeChar(String token, int offset, int length, int base) throws Exception{ 1.226 + if(token.length() != offset + length) 1.227 + throw new IllegalArgumentException("Invalid unicode character: \\" + token); 1.228 + int uc = 0; 1.229 + for(int i = offset; i < offset + length; ++i) 1.230 + { 1.231 + int d = Character.digit(token.charAt(i), base); 1.232 + if(d == -1) 1.233 + throw new IllegalArgumentException("Invalid digit: " + (char) d); 1.234 + uc = uc * base + d; 1.235 + } 1.236 + return (char) uc; 1.237 +} 1.238 + 1.239 +static private int readUnicodeChar(PushbackReader r, int initch, int base, int length, boolean exact) throws Exception{ 1.240 + int uc = Character.digit(initch, base); 1.241 + if(uc == -1) 1.242 + throw new IllegalArgumentException("Invalid digit: " + initch); 1.243 + int i = 1; 1.244 + for(; i < length; ++i) 1.245 + { 1.246 + int ch = r.read(); 1.247 + if(ch == -1 || isWhitespace(ch) || isMacro(ch)) 1.248 + { 1.249 + unread(r, ch); 1.250 + break; 1.251 + } 1.252 + int d = Character.digit(ch, base); 1.253 + if(d == -1) 1.254 + throw new IllegalArgumentException("Invalid digit: " + (char) ch); 1.255 + uc = uc * base + d; 1.256 + } 1.257 + if(i != length && exact) 1.258 + throw new IllegalArgumentException("Invalid character length: " + i + ", should be: " + length); 1.259 + return uc; 1.260 +} 1.261 + 1.262 +static private Object interpretToken(String s) throws Exception{ 1.263 + if(s.equals("nil")) 1.264 + { 1.265 + return null; 1.266 + } 1.267 + else if(s.equals("true")) 1.268 + { 1.269 + return RT.T; 1.270 + } 1.271 + else if(s.equals("false")) 1.272 + { 1.273 + return RT.F; 1.274 + } 1.275 + else if(s.equals("/")) 1.276 + { 1.277 + return SLASH; 1.278 + } 1.279 + else if(s.equals("clojure.core//")) 1.280 + { 1.281 + return CLOJURE_SLASH; 1.282 + } 1.283 + Object ret = null; 1.284 + 1.285 + ret = matchSymbol(s); 1.286 + if(ret != null) 1.287 + return ret; 1.288 + 1.289 + throw new Exception("Invalid token: " + s); 1.290 +} 1.291 + 1.292 + 1.293 +private static Object matchSymbol(String s){ 1.294 + Matcher m = symbolPat.matcher(s); 1.295 + if(m.matches()) 1.296 + { 1.297 + int gc = m.groupCount(); 1.298 + String ns = m.group(1); 1.299 + String name = m.group(2); 1.300 + if(ns != null && ns.endsWith(":/") 1.301 + || name.endsWith(":") 1.302 + || s.indexOf("::", 1) != -1) 1.303 + return null; 1.304 + if(s.startsWith("::")) 1.305 + { 1.306 + Symbol ks = Symbol.intern(s.substring(2)); 1.307 + Namespace kns; 1.308 + if(ks.ns != null) 1.309 + kns = Compiler.namespaceFor(ks); 1.310 + else 1.311 + kns = Compiler.currentNS(); 1.312 + //auto-resolving keyword 1.313 + if (kns != null) 1.314 + return Keyword.intern(kns.name.name,ks.name); 1.315 + else 1.316 + return null; 1.317 + } 1.318 + boolean isKeyword = s.charAt(0) == ':'; 1.319 + Symbol sym = Symbol.intern(s.substring(isKeyword ? 1 : 0)); 1.320 + if(isKeyword) 1.321 + return Keyword.intern(sym); 1.322 + return sym; 1.323 + } 1.324 + return null; 1.325 +} 1.326 + 1.327 + 1.328 +private static Object matchNumber(String s){ 1.329 + Matcher m = intPat.matcher(s); 1.330 + if(m.matches()) 1.331 + { 1.332 + if(m.group(2) != null) 1.333 + return 0; 1.334 + boolean negate = (m.group(1).equals("-")); 1.335 + String n; 1.336 + int radix = 10; 1.337 + if((n = m.group(3)) != null) 1.338 + radix = 10; 1.339 + else if((n = m.group(4)) != null) 1.340 + radix = 16; 1.341 + else if((n = m.group(5)) != null) 1.342 + radix = 8; 1.343 + else if((n = m.group(7)) != null) 1.344 + radix = Integer.parseInt(m.group(6)); 1.345 + if(n == null) 1.346 + return null; 1.347 + BigInteger bn = new BigInteger(n, radix); 1.348 + return Numbers.reduce(negate ? bn.negate() : bn); 1.349 + } 1.350 + m = floatPat.matcher(s); 1.351 + if(m.matches()) 1.352 + { 1.353 + if(m.group(4) != null) 1.354 + return new BigDecimal(m.group(1)); 1.355 + return Double.parseDouble(s); 1.356 + } 1.357 + m = ratioPat.matcher(s); 1.358 + if(m.matches()) 1.359 + { 1.360 + return Numbers.divide(new BigInteger(m.group(1)), new BigInteger(m.group(2))); 1.361 + } 1.362 + return null; 1.363 +} 1.364 + 1.365 +static private IFn getMacro(int ch){ 1.366 + if(ch < macros.length) 1.367 + return macros[ch]; 1.368 + return null; 1.369 +} 1.370 + 1.371 +static private boolean isMacro(int ch){ 1.372 + return (ch < macros.length && macros[ch] != null); 1.373 +} 1.374 + 1.375 +static private boolean isTerminatingMacro(int ch){ 1.376 + return (ch != '#' && ch < macros.length && macros[ch] != null); 1.377 +} 1.378 + 1.379 +public static class RegexReader extends AFn{ 1.380 + static StringReader stringrdr = new StringReader(); 1.381 + 1.382 + public Object invoke(Object reader, Object doublequote) throws Exception{ 1.383 + StringBuilder sb = new StringBuilder(); 1.384 + Reader r = (Reader) reader; 1.385 + for(int ch = r.read(); ch != '"'; ch = r.read()) 1.386 + { 1.387 + if(ch == -1) 1.388 + throw new Exception("EOF while reading regex"); 1.389 + sb.append( (char) ch ); 1.390 + if(ch == '\\') //escape 1.391 + { 1.392 + ch = r.read(); 1.393 + if(ch == -1) 1.394 + throw new Exception("EOF while reading regex"); 1.395 + sb.append( (char) ch ) ; 1.396 + } 1.397 + } 1.398 + return Pattern.compile(sb.toString()); 1.399 + } 1.400 +} 1.401 + 1.402 +public static class StringReader extends AFn{ 1.403 + public Object invoke(Object reader, Object doublequote) throws Exception{ 1.404 + StringBuilder sb = new StringBuilder(); 1.405 + Reader r = (Reader) reader; 1.406 + 1.407 + for(int ch = r.read(); ch != '"'; ch = r.read()) 1.408 + { 1.409 + if(ch == -1) 1.410 + throw new Exception("EOF while reading string"); 1.411 + if(ch == '\\') //escape 1.412 + { 1.413 + ch = r.read(); 1.414 + if(ch == -1) 1.415 + throw new Exception("EOF while reading string"); 1.416 + switch(ch) 1.417 + { 1.418 + case 't': 1.419 + ch = '\t'; 1.420 + break; 1.421 + case 'r': 1.422 + ch = '\r'; 1.423 + break; 1.424 + case 'n': 1.425 + ch = '\n'; 1.426 + break; 1.427 + case '\\': 1.428 + break; 1.429 + case '"': 1.430 + break; 1.431 + case 'b': 1.432 + ch = '\b'; 1.433 + break; 1.434 + case 'f': 1.435 + ch = '\f'; 1.436 + break; 1.437 + case 'u': 1.438 + { 1.439 + ch = r.read(); 1.440 + if (Character.digit(ch, 16) == -1) 1.441 + throw new Exception("Invalid unicode escape: \\u" + (char) ch); 1.442 + ch = readUnicodeChar((PushbackReader) r, ch, 16, 4, true); 1.443 + break; 1.444 + } 1.445 + default: 1.446 + { 1.447 + if(Character.isDigit(ch)) 1.448 + { 1.449 + ch = readUnicodeChar((PushbackReader) r, ch, 8, 3, false); 1.450 + if(ch > 0377) 1.451 + throw new Exception("Octal escape sequence must be in range [0, 377]."); 1.452 + } 1.453 + else 1.454 + throw new Exception("Unsupported escape character: \\" + (char) ch); 1.455 + } 1.456 + } 1.457 + } 1.458 + sb.append((char) ch); 1.459 + } 1.460 + return sb.toString(); 1.461 + } 1.462 +} 1.463 + 1.464 +public static class CommentReader extends AFn{ 1.465 + public Object invoke(Object reader, Object semicolon) throws Exception{ 1.466 + Reader r = (Reader) reader; 1.467 + int ch; 1.468 + do 1.469 + { 1.470 + ch = r.read(); 1.471 + } while(ch != -1 && ch != '\n' && ch != '\r'); 1.472 + return r; 1.473 + } 1.474 + 1.475 +} 1.476 + 1.477 +public static class DiscardReader extends AFn{ 1.478 + public Object invoke(Object reader, Object underscore) throws Exception{ 1.479 + PushbackReader r = (PushbackReader) reader; 1.480 + read(r, true, null, true); 1.481 + return r; 1.482 + } 1.483 +} 1.484 + 1.485 +public static class WrappingReader extends AFn{ 1.486 + final Symbol sym; 1.487 + 1.488 + public WrappingReader(Symbol sym){ 1.489 + this.sym = sym; 1.490 + } 1.491 + 1.492 + public Object invoke(Object reader, Object quote) throws Exception{ 1.493 + PushbackReader r = (PushbackReader) reader; 1.494 + Object o = read(r, true, null, true); 1.495 + return RT.list(sym, o); 1.496 + } 1.497 + 1.498 +} 1.499 + 1.500 +public static class DeprecatedWrappingReader extends AFn{ 1.501 + final Symbol sym; 1.502 + final String macro; 1.503 + 1.504 + public DeprecatedWrappingReader(Symbol sym, String macro){ 1.505 + this.sym = sym; 1.506 + this.macro = macro; 1.507 + } 1.508 + 1.509 + public Object invoke(Object reader, Object quote) throws Exception{ 1.510 + System.out.println("WARNING: reader macro " + macro + 1.511 + " is deprecated; use " + sym.getName() + 1.512 + " instead"); 1.513 + PushbackReader r = (PushbackReader) reader; 1.514 + Object o = read(r, true, null, true); 1.515 + return RT.list(sym, o); 1.516 + } 1.517 + 1.518 +} 1.519 + 1.520 +public static class VarReader extends AFn{ 1.521 + public Object invoke(Object reader, Object quote) throws Exception{ 1.522 + PushbackReader r = (PushbackReader) reader; 1.523 + Object o = read(r, true, null, true); 1.524 +// if(o instanceof Symbol) 1.525 +// { 1.526 +// Object v = Compiler.maybeResolveIn(Compiler.currentNS(), (Symbol) o); 1.527 +// if(v instanceof Var) 1.528 +// return v; 1.529 +// } 1.530 + return RT.list(THE_VAR, o); 1.531 + } 1.532 +} 1.533 + 1.534 +/* 1.535 +static class DerefReader extends AFn{ 1.536 + 1.537 + public Object invoke(Object reader, Object quote) throws Exception{ 1.538 + PushbackReader r = (PushbackReader) reader; 1.539 + int ch = r.read(); 1.540 + if(ch == -1) 1.541 + throw new Exception("EOF while reading character"); 1.542 + if(ch == '!') 1.543 + { 1.544 + Object o = read(r, true, null, true); 1.545 + return RT.list(DEREF_BANG, o); 1.546 + } 1.547 + else 1.548 + { 1.549 + r.unread(ch); 1.550 + Object o = read(r, true, null, true); 1.551 + return RT.list(DEREF, o); 1.552 + } 1.553 + } 1.554 + 1.555 +} 1.556 +*/ 1.557 + 1.558 +public static class DispatchReader extends AFn{ 1.559 + public Object invoke(Object reader, Object hash) throws Exception{ 1.560 + int ch = ((Reader) reader).read(); 1.561 + if(ch == -1) 1.562 + throw new Exception("EOF while reading character"); 1.563 + IFn fn = dispatchMacros[ch]; 1.564 + if(fn == null) 1.565 + throw new Exception(String.format("No dispatch macro for: %c", (char) ch)); 1.566 + return fn.invoke(reader, ch); 1.567 + } 1.568 +} 1.569 + 1.570 +static Symbol garg(int n){ 1.571 + return Symbol.intern(null, (n == -1 ? "rest" : ("p" + n)) + "__" + RT.nextID() + "#"); 1.572 +} 1.573 + 1.574 +public static class FnReader extends AFn{ 1.575 + public Object invoke(Object reader, Object lparen) throws Exception{ 1.576 + PushbackReader r = (PushbackReader) reader; 1.577 + if(ARG_ENV.deref() != null) 1.578 + throw new IllegalStateException("Nested #()s are not allowed"); 1.579 + try 1.580 + { 1.581 + Var.pushThreadBindings( 1.582 + RT.map(ARG_ENV, PersistentTreeMap.EMPTY)); 1.583 + r.unread('('); 1.584 + Object form = read(r, true, null, true); 1.585 + 1.586 + PersistentVector args = PersistentVector.EMPTY; 1.587 + PersistentTreeMap argsyms = (PersistentTreeMap) ARG_ENV.deref(); 1.588 + ISeq rargs = argsyms.rseq(); 1.589 + if(rargs != null) 1.590 + { 1.591 + int higharg = (Integer) ((Map.Entry) rargs.first()).getKey(); 1.592 + if(higharg > 0) 1.593 + { 1.594 + for(int i = 1; i <= higharg; ++i) 1.595 + { 1.596 + Object sym = argsyms.valAt(i); 1.597 + if(sym == null) 1.598 + sym = garg(i); 1.599 + args = args.cons(sym); 1.600 + } 1.601 + } 1.602 + Object restsym = argsyms.valAt(-1); 1.603 + if(restsym != null) 1.604 + { 1.605 + args = args.cons(Compiler._AMP_); 1.606 + args = args.cons(restsym); 1.607 + } 1.608 + } 1.609 + return RT.list(Compiler.FN, args, form); 1.610 + } 1.611 + finally 1.612 + { 1.613 + Var.popThreadBindings(); 1.614 + } 1.615 + } 1.616 +} 1.617 + 1.618 +static Symbol registerArg(int n){ 1.619 + PersistentTreeMap argsyms = (PersistentTreeMap) ARG_ENV.deref(); 1.620 + if(argsyms == null) 1.621 + { 1.622 + throw new IllegalStateException("arg literal not in #()"); 1.623 + } 1.624 + Symbol ret = (Symbol) argsyms.valAt(n); 1.625 + if(ret == null) 1.626 + { 1.627 + ret = garg(n); 1.628 + ARG_ENV.set(argsyms.assoc(n, ret)); 1.629 + } 1.630 + return ret; 1.631 +} 1.632 + 1.633 +static class ArgReader extends AFn{ 1.634 + public Object invoke(Object reader, Object pct) throws Exception{ 1.635 + PushbackReader r = (PushbackReader) reader; 1.636 + if(ARG_ENV.deref() == null) 1.637 + { 1.638 + return interpretToken(readToken(r, '%')); 1.639 + } 1.640 + int ch = r.read(); 1.641 + unread(r, ch); 1.642 + //% alone is first arg 1.643 + if(ch == -1 || isWhitespace(ch) || isTerminatingMacro(ch)) 1.644 + { 1.645 + return registerArg(1); 1.646 + } 1.647 + Object n = read(r, true, null, true); 1.648 + if(n.equals(Compiler._AMP_)) 1.649 + return registerArg(-1); 1.650 + if(!(n instanceof Number)) 1.651 + throw new IllegalStateException("arg literal must be %, %& or %integer"); 1.652 + return registerArg(((Number) n).intValue()); 1.653 + } 1.654 +} 1.655 + 1.656 +public static class MetaReader extends AFn{ 1.657 + public Object invoke(Object reader, Object caret) throws Exception{ 1.658 + PushbackReader r = (PushbackReader) reader; 1.659 + int line = -1; 1.660 + if(r instanceof LineNumberingPushbackReader) 1.661 + line = ((LineNumberingPushbackReader) r).getLineNumber(); 1.662 + Object meta = read(r, true, null, true); 1.663 + if(meta instanceof Symbol || meta instanceof Keyword || meta instanceof String) 1.664 + meta = RT.map(RT.TAG_KEY, meta); 1.665 + else if(!(meta instanceof IPersistentMap)) 1.666 + throw new IllegalArgumentException("Metadata must be Symbol,Keyword,String or Map"); 1.667 + 1.668 + Object o = read(r, true, null, true); 1.669 + if(o instanceof IMeta) 1.670 + { 1.671 + if(line != -1 && o instanceof ISeq) 1.672 + meta = ((IPersistentMap) meta).assoc(RT.LINE_KEY, line); 1.673 + if(o instanceof IReference) 1.674 + { 1.675 + ((IReference)o).resetMeta((IPersistentMap) meta); 1.676 + return o; 1.677 + } 1.678 + return ((IObj) o).withMeta((IPersistentMap) meta); 1.679 + } 1.680 + else 1.681 + throw new IllegalArgumentException("Metadata can only be applied to IMetas"); 1.682 + } 1.683 + 1.684 +} 1.685 + 1.686 +public static class SyntaxQuoteReader extends AFn{ 1.687 + public Object invoke(Object reader, Object backquote) throws Exception{ 1.688 + PushbackReader r = (PushbackReader) reader; 1.689 + try 1.690 + { 1.691 + Var.pushThreadBindings( 1.692 + RT.map(GENSYM_ENV, PersistentHashMap.EMPTY)); 1.693 + 1.694 + Object form = read(r, true, null, true); 1.695 + return syntaxQuote(form); 1.696 + } 1.697 + finally 1.698 + { 1.699 + Var.popThreadBindings(); 1.700 + } 1.701 + } 1.702 + 1.703 + static Object syntaxQuote(Object form) throws Exception{ 1.704 + Object ret; 1.705 + if(Compiler.isSpecial(form)) 1.706 + ret = RT.list(Compiler.QUOTE, form); 1.707 + else if(form instanceof Symbol) 1.708 + { 1.709 + Symbol sym = (Symbol) form; 1.710 + if(sym.ns == null && sym.name.endsWith("#")) 1.711 + { 1.712 + IPersistentMap gmap = (IPersistentMap) GENSYM_ENV.deref(); 1.713 + if(gmap == null) 1.714 + throw new IllegalStateException("Gensym literal not in syntax-quote"); 1.715 + Symbol gs = (Symbol) gmap.valAt(sym); 1.716 + if(gs == null) 1.717 + GENSYM_ENV.set(gmap.assoc(sym, gs = Symbol.intern(null, 1.718 + sym.name.substring(0, sym.name.length() - 1) 1.719 + + "__" + RT.nextID() + "__auto__"))); 1.720 + sym = gs; 1.721 + } 1.722 + else if(sym.ns == null && sym.name.endsWith(".")) 1.723 + { 1.724 + Symbol csym = Symbol.intern(null, sym.name.substring(0, sym.name.length() - 1)); 1.725 + csym = Compiler.resolveSymbol(csym); 1.726 + sym = Symbol.intern(null, csym.name.concat(".")); 1.727 + } 1.728 + else if(sym.ns == null && sym.name.startsWith(".")) 1.729 + { 1.730 + // Simply quote method names. 1.731 + } 1.732 + else 1.733 + { 1.734 + Object maybeClass = null; 1.735 + if(sym.ns != null) 1.736 + maybeClass = Compiler.currentNS().getMapping( 1.737 + Symbol.intern(null, sym.ns)); 1.738 + if(maybeClass instanceof Class) 1.739 + { 1.740 + // Classname/foo -> package.qualified.Classname/foo 1.741 + sym = Symbol.intern( 1.742 + ((Class)maybeClass).getName(), sym.name); 1.743 + } 1.744 + else 1.745 + sym = Compiler.resolveSymbol(sym); 1.746 + } 1.747 + ret = RT.list(Compiler.QUOTE, sym); 1.748 + } 1.749 + else if(isUnquote(form)) 1.750 + return RT.second(form); 1.751 + else if(isUnquoteSplicing(form)) 1.752 + throw new IllegalStateException("splice not in list"); 1.753 + else if(form instanceof IPersistentCollection) 1.754 + { 1.755 + if(form instanceof IPersistentMap) 1.756 + { 1.757 + IPersistentVector keyvals = flattenMap(form); 1.758 + ret = RT.list(APPLY, HASHMAP, RT.list(SEQ, RT.cons(CONCAT, sqExpandList(keyvals.seq())))); 1.759 + } 1.760 + else if(form instanceof IPersistentVector) 1.761 + { 1.762 + ret = RT.list(APPLY, VECTOR, RT.list(SEQ, RT.cons(CONCAT, sqExpandList(((IPersistentVector) form).seq())))); 1.763 + } 1.764 + else if(form instanceof IPersistentSet) 1.765 + { 1.766 + ret = RT.list(APPLY, HASHSET, RT.list(SEQ, RT.cons(CONCAT, sqExpandList(((IPersistentSet) form).seq())))); 1.767 + } 1.768 + else if(form instanceof ISeq || form instanceof IPersistentList) 1.769 + { 1.770 + ISeq seq = RT.seq(form); 1.771 + if(seq == null) 1.772 + ret = RT.cons(LIST,null); 1.773 + else 1.774 + ret = RT.list(SEQ, RT.cons(CONCAT, sqExpandList(seq))); 1.775 + } 1.776 + else 1.777 + throw new UnsupportedOperationException("Unknown Collection type"); 1.778 + } 1.779 + else if(form instanceof Keyword 1.780 + || form instanceof Number 1.781 + || form instanceof Character 1.782 + || form instanceof String) 1.783 + ret = form; 1.784 + else 1.785 + ret = RT.list(Compiler.QUOTE, form); 1.786 + 1.787 + if(form instanceof IObj && RT.meta(form) != null) 1.788 + { 1.789 + //filter line numbers 1.790 + IPersistentMap newMeta = ((IObj) form).meta().without(RT.LINE_KEY); 1.791 + if(newMeta.count() > 0) 1.792 + return RT.list(WITH_META, ret, syntaxQuote(((IObj) form).meta())); 1.793 + } 1.794 + return ret; 1.795 + } 1.796 + 1.797 + private static ISeq sqExpandList(ISeq seq) throws Exception{ 1.798 + PersistentVector ret = PersistentVector.EMPTY; 1.799 + for(; seq != null; seq = seq.next()) 1.800 + { 1.801 + Object item = seq.first(); 1.802 + if(isUnquote(item)) 1.803 + ret = ret.cons(RT.list(LIST, RT.second(item))); 1.804 + else if(isUnquoteSplicing(item)) 1.805 + ret = ret.cons(RT.second(item)); 1.806 + else 1.807 + ret = ret.cons(RT.list(LIST, syntaxQuote(item))); 1.808 + } 1.809 + return ret.seq(); 1.810 + } 1.811 + 1.812 + private static IPersistentVector flattenMap(Object form){ 1.813 + IPersistentVector keyvals = PersistentVector.EMPTY; 1.814 + for(ISeq s = RT.seq(form); s != null; s = s.next()) 1.815 + { 1.816 + IMapEntry e = (IMapEntry) s.first(); 1.817 + keyvals = (IPersistentVector) keyvals.cons(e.key()); 1.818 + keyvals = (IPersistentVector) keyvals.cons(e.val()); 1.819 + } 1.820 + return keyvals; 1.821 + } 1.822 + 1.823 +} 1.824 + 1.825 +static boolean isUnquoteSplicing(Object form){ 1.826 + return form instanceof ISeq && Util.equals(RT.first(form),UNQUOTE_SPLICING); 1.827 +} 1.828 + 1.829 +static boolean isUnquote(Object form){ 1.830 + return form instanceof ISeq && Util.equals(RT.first(form),UNQUOTE); 1.831 +} 1.832 + 1.833 +static class UnquoteReader extends AFn{ 1.834 + public Object invoke(Object reader, Object comma) throws Exception{ 1.835 + PushbackReader r = (PushbackReader) reader; 1.836 + int ch = r.read(); 1.837 + if(ch == -1) 1.838 + throw new Exception("EOF while reading character"); 1.839 + if(ch == '@') 1.840 + { 1.841 + Object o = read(r, true, null, true); 1.842 + return RT.list(UNQUOTE_SPLICING, o); 1.843 + } 1.844 + else 1.845 + { 1.846 + unread(r, ch); 1.847 + Object o = read(r, true, null, true); 1.848 + return RT.list(UNQUOTE, o); 1.849 + } 1.850 + } 1.851 + 1.852 +} 1.853 + 1.854 +public static class CharacterReader extends AFn{ 1.855 + public Object invoke(Object reader, Object backslash) throws Exception{ 1.856 + PushbackReader r = (PushbackReader) reader; 1.857 + int ch = r.read(); 1.858 + if(ch == -1) 1.859 + throw new Exception("EOF while reading character"); 1.860 + String token = readToken(r, (char) ch); 1.861 + if(token.length() == 1) 1.862 + return Character.valueOf(token.charAt(0)); 1.863 + else if(token.equals("newline")) 1.864 + return '\n'; 1.865 + else if(token.equals("space")) 1.866 + return ' '; 1.867 + else if(token.equals("tab")) 1.868 + return '\t'; 1.869 + else if(token.equals("backspace")) 1.870 + return '\b'; 1.871 + else if(token.equals("formfeed")) 1.872 + return '\f'; 1.873 + else if(token.equals("return")) 1.874 + return '\r'; 1.875 + else if(token.startsWith("u")) 1.876 + { 1.877 + char c = (char) readUnicodeChar(token, 1, 4, 16); 1.878 + if(c >= '\uD800' && c <= '\uDFFF') // surrogate code unit? 1.879 + throw new Exception("Invalid character constant: \\u" + Integer.toString(c, 16)); 1.880 + return c; 1.881 + } 1.882 + else if(token.startsWith("o")) 1.883 + { 1.884 + int len = token.length() - 1; 1.885 + if(len > 3) 1.886 + throw new Exception("Invalid octal escape sequence length: " + len); 1.887 + int uc = readUnicodeChar(token, 1, len, 8); 1.888 + if(uc > 0377) 1.889 + throw new Exception("Octal escape sequence must be in range [0, 377]."); 1.890 + return (char) uc; 1.891 + } 1.892 + throw new Exception("Unsupported character: \\" + token); 1.893 + } 1.894 + 1.895 +} 1.896 + 1.897 +public static class ListReader extends AFn{ 1.898 + public Object invoke(Object reader, Object leftparen) throws Exception{ 1.899 + PushbackReader r = (PushbackReader) reader; 1.900 + int line = -1; 1.901 + if(r instanceof LineNumberingPushbackReader) 1.902 + line = ((LineNumberingPushbackReader) r).getLineNumber(); 1.903 + List list = readDelimitedList(')', r, true); 1.904 + if(list.isEmpty()) 1.905 + return PersistentList.EMPTY; 1.906 + IObj s = (IObj) PersistentList.create(list); 1.907 +// IObj s = (IObj) RT.seq(list); 1.908 + if(line != -1) 1.909 + return s.withMeta(RT.map(RT.LINE_KEY, line)); 1.910 + else 1.911 + return s; 1.912 + } 1.913 + 1.914 +} 1.915 + 1.916 +static class CtorReader extends AFn{ 1.917 + static final Symbol cls = Symbol.create("class"); 1.918 + 1.919 + public Object invoke(Object reader, Object leftangle) throws Exception{ 1.920 + PushbackReader r = (PushbackReader) reader; 1.921 + // #<class classname> 1.922 + // #<classname args*> 1.923 + // #<classname/staticMethod args*> 1.924 + List list = readDelimitedList('>', r, true); 1.925 + if(list.isEmpty()) 1.926 + throw new Exception("Must supply 'class', classname or classname/staticMethod"); 1.927 + Symbol s = (Symbol) list.get(0); 1.928 + Object[] args = list.subList(1, list.size()).toArray(); 1.929 + if(s.equals(cls)) 1.930 + { 1.931 + return RT.classForName(args[0].toString()); 1.932 + } 1.933 + else if(s.ns != null) //static method 1.934 + { 1.935 + String classname = s.ns; 1.936 + String method = s.name; 1.937 + return Reflector.invokeStaticMethod(classname, method, args); 1.938 + } 1.939 + else 1.940 + { 1.941 + return Reflector.invokeConstructor(RT.classForName(s.name), args); 1.942 + } 1.943 + } 1.944 + 1.945 +} 1.946 + 1.947 +public static class EvalReader extends AFn{ 1.948 + public Object invoke(Object reader, Object eq) throws Exception{ 1.949 + if (!RT.booleanCast(RT.READEVAL.deref())) 1.950 + { 1.951 + throw new Exception("EvalReader not allowed when *read-eval* is false."); 1.952 + } 1.953 + 1.954 + PushbackReader r = (PushbackReader) reader; 1.955 + Object o = read(r, true, null, true); 1.956 + if(o instanceof Symbol) 1.957 + { 1.958 + return RT.classForName(o.toString()); 1.959 + } 1.960 + else if(o instanceof IPersistentList) 1.961 + { 1.962 + Symbol fs = (Symbol) RT.first(o); 1.963 + if(fs.equals(THE_VAR)) 1.964 + { 1.965 + Symbol vs = (Symbol) RT.second(o); 1.966 + return RT.var(vs.ns, vs.name); //Compiler.resolve((Symbol) RT.second(o),true); 1.967 + } 1.968 + if(fs.name.endsWith(".")) 1.969 + { 1.970 + Object[] args = RT.toArray(RT.next(o)); 1.971 + return Reflector.invokeConstructor(RT.classForName(fs.name.substring(0, fs.name.length() - 1)), args); 1.972 + } 1.973 + if(Compiler.namesStaticMember(fs)) 1.974 + { 1.975 + Object[] args = RT.toArray(RT.next(o)); 1.976 + return Reflector.invokeStaticMethod(fs.ns, fs.name, args); 1.977 + } 1.978 + Object v = Compiler.maybeResolveIn(Compiler.currentNS(), fs); 1.979 + if(v instanceof Var) 1.980 + { 1.981 + return ((IFn) v).applyTo(RT.next(o)); 1.982 + } 1.983 + throw new Exception("Can't resolve " + fs); 1.984 + } 1.985 + else 1.986 + throw new IllegalArgumentException("Unsupported #= form"); 1.987 + } 1.988 +} 1.989 + 1.990 +//static class ArgVectorReader extends AFn{ 1.991 +// public Object invoke(Object reader, Object leftparen) throws Exception{ 1.992 +// PushbackReader r = (PushbackReader) reader; 1.993 +// return ArgVector.create(readDelimitedList('|', r, true)); 1.994 +// } 1.995 +// 1.996 +//} 1.997 + 1.998 +public static class VectorReader extends AFn{ 1.999 + public Object invoke(Object reader, Object leftparen) throws Exception{ 1.1000 + PushbackReader r = (PushbackReader) reader; 1.1001 + return LazilyPersistentVector.create(readDelimitedList(']', r, true)); 1.1002 + } 1.1003 + 1.1004 +} 1.1005 + 1.1006 +public static class MapReader extends AFn{ 1.1007 + public Object invoke(Object reader, Object leftparen) throws Exception{ 1.1008 + PushbackReader r = (PushbackReader) reader; 1.1009 + return RT.map(readDelimitedList('}', r, true).toArray()); 1.1010 + } 1.1011 + 1.1012 +} 1.1013 + 1.1014 +public static class SetReader extends AFn{ 1.1015 + public Object invoke(Object reader, Object leftbracket) throws Exception{ 1.1016 + PushbackReader r = (PushbackReader) reader; 1.1017 + return PersistentHashSet.createWithCheck(readDelimitedList('}', r, true)); 1.1018 + } 1.1019 + 1.1020 +} 1.1021 + 1.1022 +public static class UnmatchedDelimiterReader extends AFn{ 1.1023 + public Object invoke(Object reader, Object rightdelim) throws Exception{ 1.1024 + throw new Exception("Unmatched delimiter: " + rightdelim); 1.1025 + } 1.1026 + 1.1027 +} 1.1028 + 1.1029 +public static class UnreadableReader extends AFn{ 1.1030 + public Object invoke(Object reader, Object leftangle) throws Exception{ 1.1031 + throw new Exception("Unreadable form"); 1.1032 + } 1.1033 +} 1.1034 + 1.1035 +public static List readDelimitedList(char delim, PushbackReader r, boolean isRecursive) throws Exception{ 1.1036 + ArrayList a = new ArrayList(); 1.1037 + 1.1038 + for(; ;) 1.1039 + { 1.1040 + int ch = r.read(); 1.1041 + 1.1042 + while(isWhitespace(ch)) 1.1043 + ch = r.read(); 1.1044 + 1.1045 + if(ch == -1) 1.1046 + throw new Exception("EOF while reading"); 1.1047 + 1.1048 + if(ch == delim) 1.1049 + break; 1.1050 + 1.1051 + IFn macroFn = getMacro(ch); 1.1052 + if(macroFn != null) 1.1053 + { 1.1054 + Object mret = macroFn.invoke(r, (char) ch); 1.1055 + //no op macros return the reader 1.1056 + if(mret != r) 1.1057 + a.add(mret); 1.1058 + } 1.1059 + else 1.1060 + { 1.1061 + unread(r, ch); 1.1062 + 1.1063 + Object o = read(r, true, null, isRecursive); 1.1064 + if(o != r) 1.1065 + a.add(o); 1.1066 + } 1.1067 + } 1.1068 + 1.1069 + 1.1070 + return a; 1.1071 +} 1.1072 + 1.1073 +/* 1.1074 +public static void main(String[] args) throws Exception{ 1.1075 + //RT.init(); 1.1076 + PushbackReader rdr = new PushbackReader( new java.io.StringReader( "(+ 21 21)" ) ); 1.1077 + Object input = LispReader.read(rdr, false, new Object(), false ); 1.1078 + System.out.println(Compiler.eval(input)); 1.1079 +} 1.1080 + 1.1081 +public static void main(String[] args){ 1.1082 + LineNumberingPushbackReader r = new LineNumberingPushbackReader(new InputStreamReader(System.in)); 1.1083 + OutputStreamWriter w = new OutputStreamWriter(System.out); 1.1084 + Object ret = null; 1.1085 + try 1.1086 + { 1.1087 + for(; ;) 1.1088 + { 1.1089 + ret = LispReader.read(r, true, null, false); 1.1090 + RT.print(ret, w); 1.1091 + w.write('\n'); 1.1092 + if(ret != null) 1.1093 + w.write(ret.getClass().toString()); 1.1094 + w.write('\n'); 1.1095 + w.flush(); 1.1096 + } 1.1097 + } 1.1098 + catch(Exception e) 1.1099 + { 1.1100 + e.printStackTrace(); 1.1101 + } 1.1102 +} 1.1103 + */ 1.1104 + 1.1105 +} 1.1106 +