view src/clojure/lang/RT.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 source
1 /**
2 * Copyright (c) Rich Hickey. All rights reserved.
3 * The use and distribution terms for this software are covered by the
4 * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
5 * which can be found in the file epl-v10.html at the root of this distribution.
6 * By using this software in any fashion, you are agreeing to be bound by
7 * the terms of this license.
8 * You must not remove this notice, or any other, from this software.
9 **/
11 /* rich Mar 25, 2006 4:28:27 PM */
13 package clojure.lang;
15 import java.util.concurrent.atomic.AtomicInteger;
16 import java.util.concurrent.Callable;
17 import java.util.*;
18 import java.util.regex.Matcher;
19 import java.util.regex.Pattern;
20 import java.io.*;
21 import java.lang.reflect.Array;
22 import java.math.BigDecimal;
23 import java.math.BigInteger;
24 import java.security.AccessController;
25 import java.security.PrivilegedAction;
26 import java.net.URL;
27 import java.net.JarURLConnection;
28 import java.nio.charset.Charset;
30 public class RT{
32 static final public Boolean T = Boolean.TRUE;//Keyword.intern(Symbol.create(null, "t"));
33 static final public Boolean F = Boolean.FALSE;//Keyword.intern(Symbol.create(null, "t"));
34 static final public String LOADER_SUFFIX = "__init";
36 //simple-symbol->class
37 final static IPersistentMap DEFAULT_IMPORTS = map(
38 // Symbol.create("RT"), "clojure.lang.RT",
39 // Symbol.create("Num"), "clojure.lang.Num",
40 // Symbol.create("Symbol"), "clojure.lang.Symbol",
41 // Symbol.create("Keyword"), "clojure.lang.Keyword",
42 // Symbol.create("Var"), "clojure.lang.Var",
43 // Symbol.create("Ref"), "clojure.lang.Ref",
44 // Symbol.create("IFn"), "clojure.lang.IFn",
45 // Symbol.create("IObj"), "clojure.lang.IObj",
46 // Symbol.create("ISeq"), "clojure.lang.ISeq",
47 // Symbol.create("IPersistentCollection"),
48 // "clojure.lang.IPersistentCollection",
49 // Symbol.create("IPersistentMap"), "clojure.lang.IPersistentMap",
50 // Symbol.create("IPersistentList"), "clojure.lang.IPersistentList",
51 // Symbol.create("IPersistentVector"), "clojure.lang.IPersistentVector",
52 Symbol.create("Boolean"), Boolean.class,
53 Symbol.create("Byte"), Byte.class,
54 Symbol.create("Character"), Character.class,
55 Symbol.create("Class"), Class.class,
56 Symbol.create("ClassLoader"), ClassLoader.class,
57 Symbol.create("Compiler"), Compiler.class,
58 Symbol.create("Double"), Double.class,
59 Symbol.create("Enum"), Enum.class,
60 Symbol.create("Float"), Float.class,
61 Symbol.create("InheritableThreadLocal"), InheritableThreadLocal.class,
62 Symbol.create("Integer"), Integer.class,
63 Symbol.create("Long"), Long.class,
64 Symbol.create("Math"), Math.class,
65 Symbol.create("Number"), Number.class,
66 Symbol.create("Object"), Object.class,
67 Symbol.create("Package"), Package.class,
68 Symbol.create("Process"), Process.class,
69 Symbol.create("ProcessBuilder"), ProcessBuilder.class,
70 Symbol.create("Runtime"), Runtime.class,
71 Symbol.create("RuntimePermission"), RuntimePermission.class,
72 Symbol.create("SecurityManager"), SecurityManager.class,
73 Symbol.create("Short"), Short.class,
74 Symbol.create("StackTraceElement"), StackTraceElement.class,
75 Symbol.create("StrictMath"), StrictMath.class,
76 Symbol.create("String"), String.class,
77 Symbol.create("StringBuffer"), StringBuffer.class,
78 Symbol.create("StringBuilder"), StringBuilder.class,
79 Symbol.create("System"), System.class,
80 Symbol.create("Thread"), Thread.class,
81 Symbol.create("ThreadGroup"), ThreadGroup.class,
82 Symbol.create("ThreadLocal"), ThreadLocal.class,
83 Symbol.create("Throwable"), Throwable.class,
84 Symbol.create("Void"), Void.class,
85 Symbol.create("Appendable"), Appendable.class,
86 Symbol.create("CharSequence"), CharSequence.class,
87 Symbol.create("Cloneable"), Cloneable.class,
88 Symbol.create("Comparable"), Comparable.class,
89 Symbol.create("Iterable"), Iterable.class,
90 Symbol.create("Readable"), Readable.class,
91 Symbol.create("Runnable"), Runnable.class,
92 Symbol.create("Callable"), Callable.class,
93 Symbol.create("BigInteger"), BigInteger.class,
94 Symbol.create("BigDecimal"), BigDecimal.class,
95 Symbol.create("ArithmeticException"), ArithmeticException.class,
96 Symbol.create("ArrayIndexOutOfBoundsException"), ArrayIndexOutOfBoundsException.class,
97 Symbol.create("ArrayStoreException"), ArrayStoreException.class,
98 Symbol.create("ClassCastException"), ClassCastException.class,
99 Symbol.create("ClassNotFoundException"), ClassNotFoundException.class,
100 Symbol.create("CloneNotSupportedException"), CloneNotSupportedException.class,
101 Symbol.create("EnumConstantNotPresentException"), EnumConstantNotPresentException.class,
102 Symbol.create("Exception"), Exception.class,
103 Symbol.create("IllegalAccessException"), IllegalAccessException.class,
104 Symbol.create("IllegalArgumentException"), IllegalArgumentException.class,
105 Symbol.create("IllegalMonitorStateException"), IllegalMonitorStateException.class,
106 Symbol.create("IllegalStateException"), IllegalStateException.class,
107 Symbol.create("IllegalThreadStateException"), IllegalThreadStateException.class,
108 Symbol.create("IndexOutOfBoundsException"), IndexOutOfBoundsException.class,
109 Symbol.create("InstantiationException"), InstantiationException.class,
110 Symbol.create("InterruptedException"), InterruptedException.class,
111 Symbol.create("NegativeArraySizeException"), NegativeArraySizeException.class,
112 Symbol.create("NoSuchFieldException"), NoSuchFieldException.class,
113 Symbol.create("NoSuchMethodException"), NoSuchMethodException.class,
114 Symbol.create("NullPointerException"), NullPointerException.class,
115 Symbol.create("NumberFormatException"), NumberFormatException.class,
116 Symbol.create("RuntimeException"), RuntimeException.class,
117 Symbol.create("SecurityException"), SecurityException.class,
118 Symbol.create("StringIndexOutOfBoundsException"), StringIndexOutOfBoundsException.class,
119 Symbol.create("TypeNotPresentException"), TypeNotPresentException.class,
120 Symbol.create("UnsupportedOperationException"), UnsupportedOperationException.class,
121 Symbol.create("AbstractMethodError"), AbstractMethodError.class,
122 Symbol.create("AssertionError"), AssertionError.class,
123 Symbol.create("ClassCircularityError"), ClassCircularityError.class,
124 Symbol.create("ClassFormatError"), ClassFormatError.class,
125 Symbol.create("Error"), Error.class,
126 Symbol.create("ExceptionInInitializerError"), ExceptionInInitializerError.class,
127 Symbol.create("IllegalAccessError"), IllegalAccessError.class,
128 Symbol.create("IncompatibleClassChangeError"), IncompatibleClassChangeError.class,
129 Symbol.create("InstantiationError"), InstantiationError.class,
130 Symbol.create("InternalError"), InternalError.class,
131 Symbol.create("LinkageError"), LinkageError.class,
132 Symbol.create("NoClassDefFoundError"), NoClassDefFoundError.class,
133 Symbol.create("NoSuchFieldError"), NoSuchFieldError.class,
134 Symbol.create("NoSuchMethodError"), NoSuchMethodError.class,
135 Symbol.create("OutOfMemoryError"), OutOfMemoryError.class,
136 Symbol.create("StackOverflowError"), StackOverflowError.class,
137 Symbol.create("ThreadDeath"), ThreadDeath.class,
138 Symbol.create("UnknownError"), UnknownError.class,
139 Symbol.create("UnsatisfiedLinkError"), UnsatisfiedLinkError.class,
140 Symbol.create("UnsupportedClassVersionError"), UnsupportedClassVersionError.class,
141 Symbol.create("VerifyError"), VerifyError.class,
142 Symbol.create("VirtualMachineError"), VirtualMachineError.class,
143 Symbol.create("Thread$UncaughtExceptionHandler"), Thread.UncaughtExceptionHandler.class,
144 Symbol.create("Thread$State"), Thread.State.class,
145 Symbol.create("Deprecated"), Deprecated.class,
146 Symbol.create("Override"), Override.class,
147 Symbol.create("SuppressWarnings"), SuppressWarnings.class
149 // Symbol.create("Collection"), "java.util.Collection",
150 // Symbol.create("Comparator"), "java.util.Comparator",
151 // Symbol.create("Enumeration"), "java.util.Enumeration",
152 // Symbol.create("EventListener"), "java.util.EventListener",
153 // Symbol.create("Formattable"), "java.util.Formattable",
154 // Symbol.create("Iterator"), "java.util.Iterator",
155 // Symbol.create("List"), "java.util.List",
156 // Symbol.create("ListIterator"), "java.util.ListIterator",
157 // Symbol.create("Map"), "java.util.Map",
158 // Symbol.create("Map$Entry"), "java.util.Map$Entry",
159 // Symbol.create("Observer"), "java.util.Observer",
160 // Symbol.create("Queue"), "java.util.Queue",
161 // Symbol.create("RandomAccess"), "java.util.RandomAccess",
162 // Symbol.create("Set"), "java.util.Set",
163 // Symbol.create("SortedMap"), "java.util.SortedMap",
164 // Symbol.create("SortedSet"), "java.util.SortedSet"
165 );
167 // single instance of UTF-8 Charset, so as to avoid catching UnsupportedCharsetExceptions everywhere
168 static public Charset UTF8 = Charset.forName("UTF-8");
170 static public final Namespace CLOJURE_NS = Namespace.findOrCreate(Symbol.create("clojure.core"));
171 //static final Namespace USER_NS = Namespace.findOrCreate(Symbol.create("user"));
172 final static public Var OUT =
173 Var.intern(CLOJURE_NS, Symbol.create("*out*"), new OutputStreamWriter(System.out));
174 final static public Var IN =
175 Var.intern(CLOJURE_NS, Symbol.create("*in*"),
176 new LineNumberingPushbackReader(new InputStreamReader(System.in)));
177 final static public Var ERR =
178 Var.intern(CLOJURE_NS, Symbol.create("*err*"),
179 new PrintWriter(new OutputStreamWriter(System.err), true));
180 final static Keyword TAG_KEY = Keyword.intern(null, "tag");
181 final static public Var AGENT = Var.intern(CLOJURE_NS, Symbol.create("*agent*"), null);
182 final static public Var READEVAL = Var.intern(CLOJURE_NS, Symbol.create("*read-eval*"), T);
183 final static public Var ASSERT = Var.intern(CLOJURE_NS, Symbol.create("*assert*"), T);
184 final static public Var MATH_CONTEXT = Var.intern(CLOJURE_NS, Symbol.create("*math-context*"), null);
185 static Keyword LINE_KEY = Keyword.intern(null, "line");
186 static Keyword FILE_KEY = Keyword.intern(null, "file");
187 static Keyword DECLARED_KEY = Keyword.intern(null, "declared");
188 final static public Var USE_CONTEXT_CLASSLOADER =
189 Var.intern(CLOJURE_NS, Symbol.create("*use-context-classloader*"), T);
190 //final static public Var CURRENT_MODULE = Var.intern(Symbol.create("clojure.core", "current-module"),
191 // Module.findOrCreateModule("clojure/user"));
193 final static Symbol LOAD_FILE = Symbol.create("load-file");
194 final static Symbol IN_NAMESPACE = Symbol.create("in-ns");
195 final static Symbol NAMESPACE = Symbol.create("ns");
196 static final Symbol IDENTICAL = Symbol.create("identical?");
197 final static Var CMD_LINE_ARGS = Var.intern(CLOJURE_NS, Symbol.create("*command-line-args*"), null);
198 //symbol
199 final public static Var CURRENT_NS = Var.intern(CLOJURE_NS, Symbol.create("*ns*"),
200 CLOJURE_NS);
202 final static Var FLUSH_ON_NEWLINE = Var.intern(CLOJURE_NS, Symbol.create("*flush-on-newline*"), T);
203 final static Var PRINT_META = Var.intern(CLOJURE_NS, Symbol.create("*print-meta*"), F);
204 final static Var PRINT_READABLY = Var.intern(CLOJURE_NS, Symbol.create("*print-readably*"), T);
205 final static Var PRINT_DUP = Var.intern(CLOJURE_NS, Symbol.create("*print-dup*"), F);
206 final static Var WARN_ON_REFLECTION = Var.intern(CLOJURE_NS, Symbol.create("*warn-on-reflection*"), F);
207 final static Var ALLOW_UNRESOLVED_VARS = Var.intern(CLOJURE_NS, Symbol.create("*allow-unresolved-vars*"), F);
209 final static Var IN_NS_VAR = Var.intern(CLOJURE_NS, Symbol.create("in-ns"), F);
210 final static Var NS_VAR = Var.intern(CLOJURE_NS, Symbol.create("ns"), F);
211 static final Var PRINT_INITIALIZED = Var.intern(CLOJURE_NS, Symbol.create("print-initialized"));
212 static final Var PR_ON = Var.intern(CLOJURE_NS, Symbol.create("pr-on"));
213 //final static Var IMPORTS = Var.intern(CLOJURE_NS, Symbol.create("*imports*"), DEFAULT_IMPORTS);
214 final static IFn inNamespace = new AFn(){
215 public Object invoke(Object arg1) throws Exception{
216 Symbol nsname = (Symbol) arg1;
217 Namespace ns = Namespace.findOrCreate(nsname);
218 CURRENT_NS.set(ns);
219 return ns;
220 }
221 };
223 final static IFn bootNamespace = new AFn(){
224 public Object invoke(Object __form, Object __env,Object arg1) throws Exception{
225 Symbol nsname = (Symbol) arg1;
226 Namespace ns = Namespace.findOrCreate(nsname);
227 CURRENT_NS.set(ns);
228 return ns;
229 }
230 };
232 public static List<String> processCommandLine(String[] args){
233 List<String> arglist = Arrays.asList(args);
234 int split = arglist.indexOf("--");
235 if(split >= 0) {
236 CMD_LINE_ARGS.bindRoot(RT.seq(arglist.subList(split + 1, args.length)));
237 return arglist.subList(0, split);
238 }
239 return arglist;
240 }
242 // duck typing stderr plays nice with e.g. swank
243 public static PrintWriter errPrintWriter(){
244 Writer w = (Writer) ERR.deref();
245 if (w instanceof PrintWriter) {
246 return (PrintWriter) w;
247 } else {
248 return new PrintWriter(w);
249 }
250 }
252 static public final Object[] EMPTY_ARRAY = new Object[]{};
253 static public final Comparator DEFAULT_COMPARATOR = new DefaultComparator();
255 private static final class DefaultComparator implements Comparator, Serializable {
256 public int compare(Object o1, Object o2){
257 return Util.compare(o1, o2);
258 }
260 private Object readResolve() throws ObjectStreamException {
261 // ensures that we aren't hanging onto a new default comparator for every
262 // sorted set, etc., we deserialize
263 return DEFAULT_COMPARATOR;
264 }
265 }
267 static AtomicInteger id = new AtomicInteger(1);
269 static public void addURL(Object url) throws Exception{
270 URL u = (url instanceof String) ? (new URL((String) url)) : (URL) url;
271 ClassLoader ccl = Thread.currentThread().getContextClassLoader();
272 if(ccl instanceof DynamicClassLoader)
273 ((DynamicClassLoader)ccl).addURL(u);
274 else
275 throw new IllegalAccessError("Context classloader is not a DynamicClassLoader");
276 }
278 static{
279 Keyword dockw = Keyword.intern(null, "doc");
280 Keyword arglistskw = Keyword.intern(null, "arglists");
281 Symbol namesym = Symbol.create("name");
282 OUT.setTag(Symbol.create("java.io.Writer"));
283 CURRENT_NS.setTag(Symbol.create("clojure.lang.Namespace"));
284 AGENT.setMeta(map(dockw, "The agent currently running an action on this thread, else nil"));
285 AGENT.setTag(Symbol.create("clojure.lang.Agent"));
286 MATH_CONTEXT.setTag(Symbol.create("java.math.MathContext"));
287 Var nv = Var.intern(CLOJURE_NS, NAMESPACE, bootNamespace);
288 nv.setMacro();
289 Var v;
290 v = Var.intern(CLOJURE_NS, IN_NAMESPACE, inNamespace);
291 v.setMeta(map(dockw, "Sets *ns* to the namespace named by the symbol, creating it if needed.",
292 arglistskw, list(vector(namesym))));
293 v = Var.intern(CLOJURE_NS, LOAD_FILE,
294 new AFn(){
295 public Object invoke(Object arg1) throws Exception{
296 return Compiler.loadFile((String) arg1);
297 }
298 });
299 v.setMeta(map(dockw, "Sequentially read and evaluate the set of forms contained in the file.",
300 arglistskw, list(vector(namesym))));
301 try {
302 doInit();
303 }
304 catch(Exception e) {
305 throw new RuntimeException(e);
306 }
307 }
310 static public Var var(String ns, String name){
311 return Var.intern(Namespace.findOrCreate(Symbol.intern(null, ns)), Symbol.intern(null, name));
312 }
314 static public Var var(String ns, String name, Object init){
315 return Var.intern(Namespace.findOrCreate(Symbol.intern(null, ns)), Symbol.intern(null, name), init);
316 }
318 public static void loadResourceScript(String name) throws Exception{
319 loadResourceScript(name, true);
320 }
322 public static void maybeLoadResourceScript(String name) throws Exception{
323 loadResourceScript(name, false);
324 }
326 public static void loadResourceScript(String name, boolean failIfNotFound) throws Exception{
327 loadResourceScript(RT.class, name, failIfNotFound);
328 }
330 public static void loadResourceScript(Class c, String name) throws Exception{
331 loadResourceScript(c, name, true);
332 }
334 public static void loadResourceScript(Class c, String name, boolean failIfNotFound) throws Exception{
335 int slash = name.lastIndexOf('/');
336 String file = slash >= 0 ? name.substring(slash + 1) : name;
337 InputStream ins = baseLoader().getResourceAsStream(name);
338 if(ins != null) {
339 try {
340 Compiler.load(new InputStreamReader(ins, UTF8), name, file);
341 }
342 finally {
343 ins.close();
344 }
345 }
346 else if(failIfNotFound) {
347 throw new FileNotFoundException("Could not locate Clojure resource on classpath: " + name);
348 }
349 }
351 static public void init() throws Exception{
352 RT.errPrintWriter().println("No need to call RT.init() anymore");
353 }
355 static public long lastModified(URL url, String libfile) throws Exception{
356 if(url.getProtocol().equals("jar")) {
357 return ((JarURLConnection) url.openConnection()).getJarFile().getEntry(libfile).getTime();
358 }
359 else {
360 return url.openConnection().getLastModified();
361 }
362 }
364 static void compile(String cljfile) throws Exception{
365 InputStream ins = baseLoader().getResourceAsStream(cljfile);
366 if(ins != null) {
367 try {
368 Compiler.compile(new InputStreamReader(ins, UTF8), cljfile,
369 cljfile.substring(1 + cljfile.lastIndexOf("/")));
370 }
371 finally {
372 ins.close();
373 }
375 }
376 else
377 throw new FileNotFoundException("Could not locate Clojure resource on classpath: " + cljfile);
378 }
380 static public void load(String scriptbase) throws Exception{
381 load(scriptbase, true);
382 }
384 static public void load(String scriptbase, boolean failIfNotFound) throws Exception{
385 String classfile = scriptbase + LOADER_SUFFIX + ".class";
386 String cljfile = scriptbase + ".clj";
387 URL classURL = baseLoader().getResource(classfile);
388 URL cljURL = baseLoader().getResource(cljfile);
389 boolean loaded = false;
391 if((classURL != null &&
392 (cljURL == null
393 || lastModified(classURL, classfile) > lastModified(cljURL, cljfile)))
394 || classURL == null) {
395 try {
396 Var.pushThreadBindings(
397 RT.map(CURRENT_NS, CURRENT_NS.deref(),
398 WARN_ON_REFLECTION, WARN_ON_REFLECTION.deref()));
399 loaded = (loadClassForName(scriptbase.replace('/', '.') + LOADER_SUFFIX) != null);
400 }
401 finally {
402 Var.popThreadBindings();
403 }
404 }
405 if(!loaded && cljURL != null) {
406 if(booleanCast(Compiler.COMPILE_FILES.deref()))
407 compile(cljfile);
408 else
409 loadResourceScript(RT.class, cljfile);
410 }
411 else if(!loaded && failIfNotFound)
412 throw new FileNotFoundException(String.format("Could not locate %s or %s on classpath: ", classfile, cljfile));
413 }
415 static void doInit() throws Exception{
416 load("clojure/core");
417 load("clojure/zip", false);
418 load("clojure/xml", false);
419 load("clojure/set", false);
421 Var.pushThreadBindings(
422 RT.map(CURRENT_NS, CURRENT_NS.deref(),
423 WARN_ON_REFLECTION, WARN_ON_REFLECTION.deref()));
424 try {
425 Symbol USER = Symbol.create("user");
426 Symbol CLOJURE = Symbol.create("clojure.core");
428 Var in_ns = var("clojure.core", "in-ns");
429 Var refer = var("clojure.core", "refer");
430 in_ns.invoke(USER);
431 refer.invoke(CLOJURE);
432 maybeLoadResourceScript("user.clj");
433 }
434 finally {
435 Var.popThreadBindings();
436 }
437 }
439 static public int nextID(){
440 return id.getAndIncrement();
441 }
444 ////////////// Collections support /////////////////////////////////
446 static public ISeq seq(Object coll){
447 if(coll instanceof ASeq)
448 return (ASeq) coll;
449 else if(coll instanceof LazySeq)
450 return ((LazySeq) coll).seq();
451 else
452 return seqFrom(coll);
453 }
455 static ISeq seqFrom(Object coll){
456 if(coll instanceof Seqable)
457 return ((Seqable) coll).seq();
458 else if(coll == null)
459 return null;
460 else if(coll instanceof Iterable)
461 return IteratorSeq.create(((Iterable) coll).iterator());
462 else if(coll.getClass().isArray())
463 return ArraySeq.createFromObject(coll);
464 else if(coll instanceof CharSequence)
465 return StringSeq.create((CharSequence) coll);
466 else if(coll instanceof Map)
467 return seq(((Map) coll).entrySet());
468 else {
469 Class c = coll.getClass();
470 Class sc = c.getSuperclass();
471 throw new IllegalArgumentException("Don't know how to create ISeq from: " + c.getName());
472 }
473 }
475 static public ISeq keys(Object coll){
476 return APersistentMap.KeySeq.create(seq(coll));
477 }
479 static public ISeq vals(Object coll){
480 return APersistentMap.ValSeq.create(seq(coll));
481 }
483 static public IPersistentMap meta(Object x){
484 if(x instanceof IMeta)
485 return ((IMeta) x).meta();
486 return null;
487 }
489 public static int count(Object o){
490 if(o instanceof Counted)
491 return ((Counted) o).count();
492 return countFrom(Util.ret1(o, o = null));
493 }
495 static int countFrom(Object o){
496 if(o == null)
497 return 0;
498 else if(o instanceof IPersistentCollection) {
499 ISeq s = seq(o);
500 o = null;
501 int i = 0;
502 for(; s != null; s = s.next()) {
503 if(s instanceof Counted)
504 return i + s.count();
505 i++;
506 }
507 return i;
508 }
509 else if(o instanceof CharSequence)
510 return ((CharSequence) o).length();
511 else if(o instanceof Collection)
512 return ((Collection) o).size();
513 else if(o instanceof Map)
514 return ((Map) o).size();
515 else if(o.getClass().isArray())
516 return Array.getLength(o);
518 throw new UnsupportedOperationException("count not supported on this type: " + o.getClass().getSimpleName());
519 }
521 static public IPersistentCollection conj(IPersistentCollection coll, Object x){
522 if(coll == null)
523 return new PersistentList(x);
524 return coll.cons(x);
525 }
527 static public ISeq cons(Object x, Object coll){
528 //ISeq y = seq(coll);
529 if(coll == null)
530 return new PersistentList(x);
531 else if(coll instanceof ISeq)
532 return new Cons(x, (ISeq) coll);
533 else
534 return new Cons(x, seq(coll));
535 }
537 static public Object first(Object x){
538 if(x instanceof ISeq)
539 return ((ISeq) x).first();
540 ISeq seq = seq(x);
541 if(seq == null)
542 return null;
543 return seq.first();
544 }
546 static public Object second(Object x){
547 return first(next(x));
548 }
550 static public Object third(Object x){
551 return first(next(next(x)));
552 }
554 static public Object fourth(Object x){
555 return first(next(next(next(x))));
556 }
558 static public ISeq next(Object x){
559 if(x instanceof ISeq)
560 return ((ISeq) x).next();
561 ISeq seq = seq(x);
562 if(seq == null)
563 return null;
564 return seq.next();
565 }
567 static public ISeq more(Object x){
568 if(x instanceof ISeq)
569 return ((ISeq) x).more();
570 ISeq seq = seq(x);
571 if(seq == null)
572 return PersistentList.EMPTY;
573 return seq.more();
574 }
576 //static public Seqable more(Object x){
577 // Seqable ret = null;
578 // if(x instanceof ISeq)
579 // ret = ((ISeq) x).more();
580 // else
581 // {
582 // ISeq seq = seq(x);
583 // if(seq == null)
584 // ret = PersistentList.EMPTY;
585 // else
586 // ret = seq.more();
587 // }
588 // if(ret == null)
589 // ret = PersistentList.EMPTY;
590 // return ret;
591 //}
593 static public Object peek(Object x){
594 if(x == null)
595 return null;
596 return ((IPersistentStack) x).peek();
597 }
599 static public Object pop(Object x){
600 if(x == null)
601 return null;
602 return ((IPersistentStack) x).pop();
603 }
605 static public Object get(Object coll, Object key){
606 if(coll instanceof ILookup)
607 return ((ILookup) coll).valAt(key);
608 return getFrom(coll, key);
609 }
611 static Object getFrom(Object coll, Object key){
612 if(coll == null)
613 return null;
614 else if(coll instanceof Map) {
615 Map m = (Map) coll;
616 return m.get(key);
617 }
618 else if(coll instanceof IPersistentSet) {
619 IPersistentSet set = (IPersistentSet) coll;
620 return set.get(key);
621 }
622 else if(key instanceof Number && (coll instanceof String || coll.getClass().isArray())) {
623 int n = ((Number) key).intValue();
624 if(n >= 0 && n < count(coll))
625 return nth(coll, n);
626 return null;
627 }
629 return null;
630 }
632 static public Object get(Object coll, Object key, Object notFound){
633 if(coll instanceof ILookup)
634 return ((ILookup) coll).valAt(key, notFound);
635 return getFrom(coll, key, notFound);
636 }
638 static Object getFrom(Object coll, Object key, Object notFound){
639 if(coll == null)
640 return notFound;
641 else if(coll instanceof Map) {
642 Map m = (Map) coll;
643 if(m.containsKey(key))
644 return m.get(key);
645 return notFound;
646 }
647 else if(coll instanceof IPersistentSet) {
648 IPersistentSet set = (IPersistentSet) coll;
649 if(set.contains(key))
650 return set.get(key);
651 return notFound;
652 }
653 else if(key instanceof Number && (coll instanceof String || coll.getClass().isArray())) {
654 int n = ((Number) key).intValue();
655 return n >= 0 && n < count(coll) ? nth(coll, n) : notFound;
656 }
657 return notFound;
659 }
661 static public Associative assoc(Object coll, Object key, Object val){
662 if(coll == null)
663 return new PersistentArrayMap(new Object[]{key, val});
664 return ((Associative) coll).assoc(key, val);
665 }
667 static public Object contains(Object coll, Object key){
668 if(coll == null)
669 return F;
670 else if(coll instanceof Associative)
671 return ((Associative) coll).containsKey(key) ? T : F;
672 else if(coll instanceof IPersistentSet)
673 return ((IPersistentSet) coll).contains(key) ? T : F;
674 else if(coll instanceof Map) {
675 Map m = (Map) coll;
676 return m.containsKey(key) ? T : F;
677 }
678 else if(key instanceof Number && (coll instanceof String || coll.getClass().isArray())) {
679 int n = ((Number) key).intValue();
680 return n >= 0 && n < count(coll);
681 }
682 return F;
683 }
685 static public Object find(Object coll, Object key){
686 if(coll == null)
687 return null;
688 else if(coll instanceof Associative)
689 return ((Associative) coll).entryAt(key);
690 else {
691 Map m = (Map) coll;
692 if(m.containsKey(key))
693 return new MapEntry(key, m.get(key));
694 return null;
695 }
696 }
698 //takes a seq of key,val,key,val
700 //returns tail starting at val of matching key if found, else null
701 static public ISeq findKey(Keyword key, ISeq keyvals) throws Exception{
702 while(keyvals != null) {
703 ISeq r = keyvals.next();
704 if(r == null)
705 throw new Exception("Malformed keyword argslist");
706 if(keyvals.first() == key)
707 return r;
708 keyvals = r.next();
709 }
710 return null;
711 }
713 static public Object dissoc(Object coll, Object key) throws Exception{
714 if(coll == null)
715 return null;
716 return ((IPersistentMap) coll).without(key);
717 }
719 static public Object nth(Object coll, int n){
720 if(coll instanceof Indexed)
721 return ((Indexed) coll).nth(n);
722 return nthFrom(Util.ret1(coll, coll = null), n);
723 }
725 static Object nthFrom(Object coll, int n){
726 if(coll == null)
727 return null;
728 else if(coll instanceof CharSequence)
729 return Character.valueOf(((CharSequence) coll).charAt(n));
730 else if(coll.getClass().isArray())
731 return Reflector.prepRet(Array.get(coll, n));
732 else if(coll instanceof RandomAccess)
733 return ((List) coll).get(n);
734 else if(coll instanceof Matcher)
735 return ((Matcher) coll).group(n);
737 else if(coll instanceof Map.Entry) {
738 Map.Entry e = (Map.Entry) coll;
739 if(n == 0)
740 return e.getKey();
741 else if(n == 1)
742 return e.getValue();
743 throw new IndexOutOfBoundsException();
744 }
746 else if(coll instanceof Sequential) {
747 ISeq seq = RT.seq(coll);
748 coll = null;
749 for(int i = 0; i <= n && seq != null; ++i, seq = seq.next()) {
750 if(i == n)
751 return seq.first();
752 }
753 throw new IndexOutOfBoundsException();
754 }
755 else
756 throw new UnsupportedOperationException(
757 "nth not supported on this type: " + coll.getClass().getSimpleName());
758 }
760 static public Object nth(Object coll, int n, Object notFound){
761 if(coll instanceof Indexed) {
762 Indexed v = (Indexed) coll;
763 return v.nth(n, notFound);
764 }
765 return nthFrom(coll, n, notFound);
766 }
768 static Object nthFrom(Object coll, int n, Object notFound){
769 if(coll == null)
770 return notFound;
771 else if(n < 0)
772 return notFound;
774 else if(coll instanceof CharSequence) {
775 CharSequence s = (CharSequence) coll;
776 if(n < s.length())
777 return Character.valueOf(s.charAt(n));
778 return notFound;
779 }
780 else if(coll.getClass().isArray()) {
781 if(n < Array.getLength(coll))
782 return Reflector.prepRet(Array.get(coll, n));
783 return notFound;
784 }
785 else if(coll instanceof RandomAccess) {
786 List list = (List) coll;
787 if(n < list.size())
788 return list.get(n);
789 return notFound;
790 }
791 else if(coll instanceof Matcher) {
792 Matcher m = (Matcher) coll;
793 if(n < m.groupCount())
794 return m.group(n);
795 return notFound;
796 }
797 else if(coll instanceof Map.Entry) {
798 Map.Entry e = (Map.Entry) coll;
799 if(n == 0)
800 return e.getKey();
801 else if(n == 1)
802 return e.getValue();
803 return notFound;
804 }
805 else if(coll instanceof Sequential) {
806 ISeq seq = RT.seq(coll);
807 coll = null;
808 for(int i = 0; i <= n && seq != null; ++i, seq = seq.next()) {
809 if(i == n)
810 return seq.first();
811 }
812 return notFound;
813 }
814 else
815 throw new UnsupportedOperationException(
816 "nth not supported on this type: " + coll.getClass().getSimpleName());
817 }
819 static public Object assocN(int n, Object val, Object coll){
820 if(coll == null)
821 return null;
822 else if(coll instanceof IPersistentVector)
823 return ((IPersistentVector) coll).assocN(n, val);
824 else if(coll instanceof Object[]) {
825 //hmm... this is not persistent
826 Object[] array = ((Object[]) coll);
827 array[n] = val;
828 return array;
829 }
830 else
831 return null;
832 }
834 static boolean hasTag(Object o, Object tag){
835 return Util.equals(tag, RT.get(RT.meta(o), TAG_KEY));
836 }
838 /**
839 * ********************* Boxing/casts ******************************
840 */
841 static public Object box(Object x){
842 return x;
843 }
845 static public Character box(char x){
846 return Character.valueOf(x);
847 }
849 static public Object box(boolean x){
850 return x ? T : F;
851 }
853 static public Object box(Boolean x){
854 return x;// ? T : null;
855 }
857 static public Number box(byte x){
858 return x;//Num.from(x);
859 }
861 static public Number box(short x){
862 return x;//Num.from(x);
863 }
865 static public Number box(int x){
866 return x;//Num.from(x);
867 }
869 static public Number box(long x){
870 return x;//Num.from(x);
871 }
873 static public Number box(float x){
874 return x;//Num.from(x);
875 }
877 static public Number box(double x){
878 return x;//Num.from(x);
879 }
881 static public char charCast(Object x){
882 if(x instanceof Character)
883 return ((Character) x).charValue();
885 long n = ((Number) x).longValue();
886 if(n < Character.MIN_VALUE || n > Character.MAX_VALUE)
887 throw new IllegalArgumentException("Value out of range for char: " + x);
889 return (char) n;
890 }
892 static public boolean booleanCast(Object x){
893 if(x instanceof Boolean)
894 return ((Boolean) x).booleanValue();
895 return x != null;
896 }
898 static public boolean booleanCast(boolean x){
899 return x;
900 }
902 static public byte byteCast(Object x){
903 long n = ((Number) x).longValue();
904 if(n < Byte.MIN_VALUE || n > Byte.MAX_VALUE)
905 throw new IllegalArgumentException("Value out of range for byte: " + x);
907 return (byte) n;
908 }
910 static public short shortCast(Object x){
911 long n = ((Number) x).longValue();
912 if(n < Short.MIN_VALUE || n > Short.MAX_VALUE)
913 throw new IllegalArgumentException("Value out of range for short: " + x);
915 return (short) n;
916 }
918 static public int intCast(Object x){
919 if(x instanceof Integer)
920 return ((Integer)x).intValue();
921 if(x instanceof Number)
922 return intCast(((Number) x).longValue());
923 return ((Character) x).charValue();
924 }
926 static public int intCast(char x){
927 return x;
928 }
930 static public int intCast(byte x){
931 return x;
932 }
934 static public int intCast(short x){
935 return x;
936 }
938 static public int intCast(int x){
939 return x;
940 }
942 static public int intCast(float x){
943 if(x < Integer.MIN_VALUE || x > Integer.MAX_VALUE)
944 throw new IllegalArgumentException("Value out of range for int: " + x);
945 return (int) x;
946 }
948 static public int intCast(long x){
949 if(x < Integer.MIN_VALUE || x > Integer.MAX_VALUE)
950 throw new IllegalArgumentException("Value out of range for int: " + x);
951 return (int) x;
952 }
954 static public int intCast(double x){
955 if(x < Integer.MIN_VALUE || x > Integer.MAX_VALUE)
956 throw new IllegalArgumentException("Value out of range for int: " + x);
957 return (int) x;
958 }
960 static public long longCast(Object x){
961 return ((Number) x).longValue();
962 }
964 static public long longCast(int x){
965 return x;
966 }
968 static public long longCast(float x){
969 if(x < Long.MIN_VALUE || x > Long.MAX_VALUE)
970 throw new IllegalArgumentException("Value out of range for long: " + x);
971 return (long) x;
972 }
974 static public long longCast(long x){
975 return x;
976 }
978 static public long longCast(double x){
979 if(x < Long.MIN_VALUE || x > Long.MAX_VALUE)
980 throw new IllegalArgumentException("Value out of range for long: " + x);
981 return (long) x;
982 }
984 static public float floatCast(Object x){
985 if(x instanceof Float)
986 return ((Float) x).floatValue();
988 double n = ((Number) x).doubleValue();
989 if(n < -Float.MAX_VALUE || n > Float.MAX_VALUE)
990 throw new IllegalArgumentException("Value out of range for float: " + x);
992 return (float) n;
994 }
996 static public float floatCast(int x){
997 return x;
998 }
1000 static public float floatCast(float x){
1001 return x;
1004 static public float floatCast(long x){
1005 return x;
1008 static public float floatCast(double x){
1009 if(x < -Float.MAX_VALUE || x > Float.MAX_VALUE)
1010 throw new IllegalArgumentException("Value out of range for float: " + x);
1012 return (float) x;
1015 static public double doubleCast(Object x){
1016 return ((Number) x).doubleValue();
1019 static public double doubleCast(int x){
1020 return x;
1023 static public double doubleCast(float x){
1024 return x;
1027 static public double doubleCast(long x){
1028 return x;
1031 static public double doubleCast(double x){
1032 return x;
1035 static public IPersistentMap map(Object... init){
1036 if(init == null)
1037 return PersistentArrayMap.EMPTY;
1038 else if(init.length <= PersistentArrayMap.HASHTABLE_THRESHOLD)
1039 return PersistentArrayMap.createWithCheck(init);
1040 return PersistentHashMap.createWithCheck(init);
1043 static public IPersistentSet set(Object... init){
1044 return PersistentHashSet.createWithCheck(init);
1047 static public IPersistentVector vector(Object... init){
1048 return LazilyPersistentVector.createOwning(init);
1051 static public IPersistentVector subvec(IPersistentVector v, int start, int end){
1052 if(end < start || start < 0 || end > v.count())
1053 throw new IndexOutOfBoundsException();
1054 if(start == end)
1055 return PersistentVector.EMPTY;
1056 return new APersistentVector.SubVector(null, v, start, end);
1059 /**
1060 * **************************************** list support *******************************
1061 */
1064 static public ISeq list(){
1065 return null;
1068 static public ISeq list(Object arg1){
1069 return new PersistentList(arg1);
1072 static public ISeq list(Object arg1, Object arg2){
1073 return listStar(arg1, arg2, null);
1076 static public ISeq list(Object arg1, Object arg2, Object arg3){
1077 return listStar(arg1, arg2, arg3, null);
1080 static public ISeq list(Object arg1, Object arg2, Object arg3, Object arg4){
1081 return listStar(arg1, arg2, arg3, arg4, null);
1084 static public ISeq list(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5){
1085 return listStar(arg1, arg2, arg3, arg4, arg5, null);
1088 static public ISeq listStar(Object arg1, ISeq rest){
1089 return (ISeq) cons(arg1, rest);
1092 static public ISeq listStar(Object arg1, Object arg2, ISeq rest){
1093 return (ISeq) cons(arg1, cons(arg2, rest));
1096 static public ISeq listStar(Object arg1, Object arg2, Object arg3, ISeq rest){
1097 return (ISeq) cons(arg1, cons(arg2, cons(arg3, rest)));
1100 static public ISeq listStar(Object arg1, Object arg2, Object arg3, Object arg4, ISeq rest){
1101 return (ISeq) cons(arg1, cons(arg2, cons(arg3, cons(arg4, rest))));
1104 static public ISeq listStar(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, ISeq rest){
1105 return (ISeq) cons(arg1, cons(arg2, cons(arg3, cons(arg4, cons(arg5, rest)))));
1108 static public ISeq arrayToList(Object[] a) throws Exception{
1109 ISeq ret = null;
1110 for(int i = a.length - 1; i >= 0; --i)
1111 ret = (ISeq) cons(a[i], ret);
1112 return ret;
1115 static public Object[] object_array(Object sizeOrSeq){
1116 if(sizeOrSeq instanceof Number)
1117 return new Object[((Number) sizeOrSeq).intValue()];
1118 else
1120 ISeq s = RT.seq(sizeOrSeq);
1121 int size = RT.count(s);
1122 Object[] ret = new Object[size];
1123 for(int i = 0; i < size && s != null; i++, s = s.next())
1124 ret[i] = s.first();
1125 return ret;
1129 static public Object[] toArray(Object coll) throws Exception{
1130 if(coll == null)
1131 return EMPTY_ARRAY;
1132 else if(coll instanceof Object[])
1133 return (Object[]) coll;
1134 else if(coll instanceof Collection)
1135 return ((Collection) coll).toArray();
1136 else if(coll instanceof Map)
1137 return ((Map) coll).entrySet().toArray();
1138 else if(coll instanceof String) {
1139 char[] chars = ((String) coll).toCharArray();
1140 Object[] ret = new Object[chars.length];
1141 for(int i = 0; i < chars.length; i++)
1142 ret[i] = chars[i];
1143 return ret;
1145 else if(coll.getClass().isArray()) {
1146 ISeq s = (seq(coll));
1147 Object[] ret = new Object[count(s)];
1148 for(int i = 0; i < ret.length; i++, s = s.next())
1149 ret[i] = s.first();
1150 return ret;
1152 else
1153 throw new Exception("Unable to convert: " + coll.getClass() + " to Object[]");
1156 static public Object[] seqToArray(ISeq seq){
1157 int len = length(seq);
1158 Object[] ret = new Object[len];
1159 for(int i = 0; seq != null; ++i, seq = seq.next())
1160 ret[i] = seq.first();
1161 return ret;
1164 static public Object seqToTypedArray(ISeq seq) throws Exception{
1165 Class type = (seq != null) ? seq.first().getClass() : Object.class;
1166 return seqToTypedArray(type, seq);
1169 static public Object seqToTypedArray(Class type, ISeq seq) throws Exception{
1170 Object ret = Array.newInstance(type, length(seq));
1171 for(int i = 0; seq != null; ++i, seq = seq.next())
1172 Array.set(ret, i, seq.first());
1173 return ret;
1176 static public int length(ISeq list){
1177 int i = 0;
1178 for(ISeq c = list; c != null; c = c.next()) {
1179 i++;
1181 return i;
1184 static public int boundedLength(ISeq list, int limit) throws Exception{
1185 int i = 0;
1186 for(ISeq c = list; c != null && i <= limit; c = c.next()) {
1187 i++;
1189 return i;
1192 ///////////////////////////////// reader support ////////////////////////////////
1194 static Character readRet(int ret){
1195 if(ret == -1)
1196 return null;
1197 return box((char) ret);
1200 static public Character readChar(Reader r) throws Exception{
1201 int ret = r.read();
1202 return readRet(ret);
1205 static public Character peekChar(Reader r) throws Exception{
1206 int ret;
1207 if(r instanceof PushbackReader) {
1208 ret = r.read();
1209 ((PushbackReader) r).unread(ret);
1211 else {
1212 r.mark(1);
1213 ret = r.read();
1214 r.reset();
1217 return readRet(ret);
1220 static public int getLineNumber(Reader r){
1221 if(r instanceof LineNumberingPushbackReader)
1222 return ((LineNumberingPushbackReader) r).getLineNumber();
1223 return 0;
1226 static public LineNumberingPushbackReader getLineNumberingReader(Reader r){
1227 if(isLineNumberingReader(r))
1228 return (LineNumberingPushbackReader) r;
1229 return new LineNumberingPushbackReader(r);
1232 static public boolean isLineNumberingReader(Reader r){
1233 return r instanceof LineNumberingPushbackReader;
1236 static public String resolveClassNameInContext(String className){
1237 //todo - look up in context var
1238 return className;
1241 static public boolean suppressRead(){
1242 //todo - look up in suppress-read var
1243 return false;
1246 static public String printString(Object x){
1247 try {
1248 StringWriter sw = new StringWriter();
1249 print(x, sw);
1250 return sw.toString();
1252 catch(Exception e) {
1253 throw new RuntimeException(e);
1257 static public Object readString(String s){
1258 PushbackReader r = new PushbackReader(new StringReader(s));
1259 try {
1260 return LispReader.read(r, true, null, false);
1262 catch(Exception e) {
1263 throw new RuntimeException(e);
1267 static public void print(Object x, Writer w) throws Exception{
1268 //call multimethod
1269 if(PRINT_INITIALIZED.isBound() && RT.booleanCast(PRINT_INITIALIZED.deref()))
1270 PR_ON.invoke(x, w);
1271 //*
1272 else {
1273 boolean readably = booleanCast(PRINT_READABLY.deref());
1274 if(x instanceof Obj) {
1275 Obj o = (Obj) x;
1276 if(RT.count(o.meta()) > 0 &&
1277 ((readably && booleanCast(PRINT_META.deref()))
1278 || booleanCast(PRINT_DUP.deref()))) {
1279 IPersistentMap meta = o.meta();
1280 w.write("#^");
1281 if(meta.count() == 1 && meta.containsKey(TAG_KEY))
1282 print(meta.valAt(TAG_KEY), w);
1283 else
1284 print(meta, w);
1285 w.write(' ');
1288 if(x == null)
1289 w.write("nil");
1290 else if(x instanceof ISeq || x instanceof IPersistentList) {
1291 w.write('(');
1292 printInnerSeq(seq(x), w);
1293 w.write(')');
1295 else if(x instanceof String) {
1296 String s = (String) x;
1297 if(!readably)
1298 w.write(s);
1299 else {
1300 w.write('"');
1301 //w.write(x.toString());
1302 for(int i = 0; i < s.length(); i++) {
1303 char c = s.charAt(i);
1304 switch(c) {
1305 case '\n':
1306 w.write("\\n");
1307 break;
1308 case '\t':
1309 w.write("\\t");
1310 break;
1311 case '\r':
1312 w.write("\\r");
1313 break;
1314 case '"':
1315 w.write("\\\"");
1316 break;
1317 case '\\':
1318 w.write("\\\\");
1319 break;
1320 case '\f':
1321 w.write("\\f");
1322 break;
1323 case '\b':
1324 w.write("\\b");
1325 break;
1326 default:
1327 w.write(c);
1330 w.write('"');
1333 else if(x instanceof IPersistentMap) {
1334 w.write('{');
1335 for(ISeq s = seq(x); s != null; s = s.next()) {
1336 IMapEntry e = (IMapEntry) s.first();
1337 print(e.key(), w);
1338 w.write(' ');
1339 print(e.val(), w);
1340 if(s.next() != null)
1341 w.write(", ");
1343 w.write('}');
1345 else if(x instanceof IPersistentVector) {
1346 IPersistentVector a = (IPersistentVector) x;
1347 w.write('[');
1348 for(int i = 0; i < a.count(); i++) {
1349 print(a.nth(i), w);
1350 if(i < a.count() - 1)
1351 w.write(' ');
1353 w.write(']');
1355 else if(x instanceof IPersistentSet) {
1356 w.write("#{");
1357 for(ISeq s = seq(x); s != null; s = s.next()) {
1358 print(s.first(), w);
1359 if(s.next() != null)
1360 w.write(" ");
1362 w.write('}');
1364 else if(x instanceof Character) {
1365 char c = ((Character) x).charValue();
1366 if(!readably)
1367 w.write(c);
1368 else {
1369 w.write('\\');
1370 switch(c) {
1371 case '\n':
1372 w.write("newline");
1373 break;
1374 case '\t':
1375 w.write("tab");
1376 break;
1377 case ' ':
1378 w.write("space");
1379 break;
1380 case '\b':
1381 w.write("backspace");
1382 break;
1383 case '\f':
1384 w.write("formfeed");
1385 break;
1386 case '\r':
1387 w.write("return");
1388 break;
1389 default:
1390 w.write(c);
1394 else if(x instanceof Class) {
1395 w.write("#=");
1396 w.write(((Class) x).getName());
1398 else if(x instanceof BigDecimal && readably) {
1399 w.write(x.toString());
1400 w.write('M');
1402 else if(x instanceof Var) {
1403 Var v = (Var) x;
1404 w.write("#=(var " + v.ns.name + "/" + v.sym + ")");
1406 else if(x instanceof Pattern) {
1407 Pattern p = (Pattern) x;
1408 w.write("#\"" + p.pattern() + "\"");
1410 else w.write(x.toString());
1412 //*/
1415 private static void printInnerSeq(ISeq x, Writer w) throws Exception{
1416 for(ISeq s = x; s != null; s = s.next()) {
1417 print(s.first(), w);
1418 if(s.next() != null)
1419 w.write(' ');
1423 static public void formatAesthetic(Writer w, Object obj) throws IOException{
1424 if(obj == null)
1425 w.write("null");
1426 else
1427 w.write(obj.toString());
1430 static public void formatStandard(Writer w, Object obj) throws IOException{
1431 if(obj == null)
1432 w.write("null");
1433 else if(obj instanceof String) {
1434 w.write('"');
1435 w.write((String) obj);
1436 w.write('"');
1438 else if(obj instanceof Character) {
1439 w.write('\\');
1440 char c = ((Character) obj).charValue();
1441 switch(c) {
1442 case '\n':
1443 w.write("newline");
1444 break;
1445 case '\t':
1446 w.write("tab");
1447 break;
1448 case ' ':
1449 w.write("space");
1450 break;
1451 case '\b':
1452 w.write("backspace");
1453 break;
1454 case '\f':
1455 w.write("formfeed");
1456 break;
1457 default:
1458 w.write(c);
1461 else
1462 w.write(obj.toString());
1465 static public Object format(Object o, String s, Object... args) throws Exception{
1466 Writer w;
1467 if(o == null)
1468 w = new StringWriter();
1469 else if(Util.equals(o, T))
1470 w = (Writer) OUT.deref();
1471 else
1472 w = (Writer) o;
1473 doFormat(w, s, ArraySeq.create(args));
1474 if(o == null)
1475 return w.toString();
1476 return null;
1479 static public ISeq doFormat(Writer w, String s, ISeq args) throws Exception{
1480 for(int i = 0; i < s.length();) {
1481 char c = s.charAt(i++);
1482 switch(Character.toLowerCase(c)) {
1483 case '~':
1484 char d = s.charAt(i++);
1485 switch(Character.toLowerCase(d)) {
1486 case '%':
1487 w.write('\n');
1488 break;
1489 case 't':
1490 w.write('\t');
1491 break;
1492 case 'a':
1493 if(args == null)
1494 throw new IllegalArgumentException("Missing argument");
1495 RT.formatAesthetic(w, RT.first(args));
1496 args = RT.next(args);
1497 break;
1498 case 's':
1499 if(args == null)
1500 throw new IllegalArgumentException("Missing argument");
1501 RT.formatStandard(w, RT.first(args));
1502 args = RT.next(args);
1503 break;
1504 case '{':
1505 int j = s.indexOf("~}", i); //note - does not nest
1506 if(j == -1)
1507 throw new IllegalArgumentException("Missing ~}");
1508 String subs = s.substring(i, j);
1509 for(ISeq sargs = RT.seq(RT.first(args)); sargs != null;)
1510 sargs = doFormat(w, subs, sargs);
1511 args = RT.next(args);
1512 i = j + 2; //skip ~}
1513 break;
1514 case '^':
1515 if(args == null)
1516 return null;
1517 break;
1518 case '~':
1519 w.write('~');
1520 break;
1521 default:
1522 throw new IllegalArgumentException("Unsupported ~ directive: " + d);
1524 break;
1525 default:
1526 w.write(c);
1529 return args;
1531 ///////////////////////////////// values //////////////////////////
1533 static public Object[] setValues(Object... vals){
1534 //ThreadLocalData.setValues(vals);
1535 if(vals.length > 0)
1536 return vals;//[0];
1537 return null;
1541 static public ClassLoader makeClassLoader(){
1542 return (ClassLoader) AccessController.doPrivileged(new PrivilegedAction(){
1543 public Object run(){
1544 try{
1545 Var.pushThreadBindings(RT.map(USE_CONTEXT_CLASSLOADER, RT.T));
1546 // getRootClassLoader();
1547 return new DynamicClassLoader(baseLoader());
1549 finally{
1550 Var.popThreadBindings();
1553 });
1556 static public ClassLoader baseLoader(){
1557 if(Compiler.LOADER.isBound())
1558 return (ClassLoader) Compiler.LOADER.deref();
1559 else if(booleanCast(USE_CONTEXT_CLASSLOADER.deref()))
1560 return Thread.currentThread().getContextClassLoader();
1561 return Compiler.class.getClassLoader();
1564 static public Class classForName(String name) throws ClassNotFoundException{
1566 return Class.forName(name, true, baseLoader());
1569 static public Class loadClassForName(String name) throws ClassNotFoundException{
1570 try
1572 Class.forName(name, false, baseLoader());
1574 catch(ClassNotFoundException e)
1576 return null;
1578 return Class.forName(name, true, baseLoader());
1581 static public float aget(float[] xs, int i){
1582 return xs[i];
1585 static public float aset(float[] xs, int i, float v){
1586 xs[i] = v;
1587 return v;
1590 static public int alength(float[] xs){
1591 return xs.length;
1594 static public float[] aclone(float[] xs){
1595 return xs.clone();
1598 static public double aget(double[] xs, int i){
1599 return xs[i];
1602 static public double aset(double[] xs, int i, double v){
1603 xs[i] = v;
1604 return v;
1607 static public int alength(double[] xs){
1608 return xs.length;
1611 static public double[] aclone(double[] xs){
1612 return xs.clone();
1615 static public int aget(int[] xs, int i){
1616 return xs[i];
1619 static public int aset(int[] xs, int i, int v){
1620 xs[i] = v;
1621 return v;
1624 static public int alength(int[] xs){
1625 return xs.length;
1628 static public int[] aclone(int[] xs){
1629 return xs.clone();
1632 static public long aget(long[] xs, int i){
1633 return xs[i];
1636 static public long aset(long[] xs, int i, long v){
1637 xs[i] = v;
1638 return v;
1641 static public int alength(long[] xs){
1642 return xs.length;
1645 static public long[] aclone(long[] xs){
1646 return xs.clone();
1649 static public char aget(char[] xs, int i){
1650 return xs[i];
1653 static public char aset(char[] xs, int i, char v){
1654 xs[i] = v;
1655 return v;
1658 static public int alength(char[] xs){
1659 return xs.length;
1662 static public char[] aclone(char[] xs){
1663 return xs.clone();
1666 static public byte aget(byte[] xs, int i){
1667 return xs[i];
1670 static public byte aset(byte[] xs, int i, byte v){
1671 xs[i] = v;
1672 return v;
1675 static public int alength(byte[] xs){
1676 return xs.length;
1679 static public byte[] aclone(byte[] xs){
1680 return xs.clone();
1683 static public short aget(short[] xs, int i){
1684 return xs[i];
1687 static public short aset(short[] xs, int i, short v){
1688 xs[i] = v;
1689 return v;
1692 static public int alength(short[] xs){
1693 return xs.length;
1696 static public short[] aclone(short[] xs){
1697 return xs.clone();
1700 static public boolean aget(boolean[] xs, int i){
1701 return xs[i];
1704 static public boolean aset(boolean[] xs, int i, boolean v){
1705 xs[i] = v;
1706 return v;
1709 static public int alength(boolean[] xs){
1710 return xs.length;
1713 static public boolean[] aclone(boolean[] xs){
1714 return xs.clone();
1717 static public Object aget(Object[] xs, int i){
1718 return xs[i];
1721 static public Object aset(Object[] xs, int i, Object v){
1722 xs[i] = v;
1723 return v;
1726 static public int alength(Object[] xs){
1727 return xs.length;
1730 static public Object[] aclone(Object[] xs){
1731 return xs.clone();