Mercurial > lasercutter
comparison 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 |
comparison
equal
deleted
inserted
replaced
9:35cf337adfcf | 10:ef7dbbd6452c |
---|---|
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 **/ | |
10 | |
11 /* rich Mar 25, 2006 4:28:27 PM */ | |
12 | |
13 package clojure.lang; | |
14 | |
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; | |
29 | |
30 public class RT{ | |
31 | |
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"; | |
35 | |
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 | |
148 | |
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 ); | |
166 | |
167 // single instance of UTF-8 Charset, so as to avoid catching UnsupportedCharsetExceptions everywhere | |
168 static public Charset UTF8 = Charset.forName("UTF-8"); | |
169 | |
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")); | |
192 | |
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); | |
201 | |
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); | |
208 | |
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 }; | |
222 | |
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 }; | |
231 | |
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 } | |
241 | |
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 } | |
251 | |
252 static public final Object[] EMPTY_ARRAY = new Object[]{}; | |
253 static public final Comparator DEFAULT_COMPARATOR = new DefaultComparator(); | |
254 | |
255 private static final class DefaultComparator implements Comparator, Serializable { | |
256 public int compare(Object o1, Object o2){ | |
257 return Util.compare(o1, o2); | |
258 } | |
259 | |
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 } | |
266 | |
267 static AtomicInteger id = new AtomicInteger(1); | |
268 | |
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 } | |
277 | |
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 } | |
308 | |
309 | |
310 static public Var var(String ns, String name){ | |
311 return Var.intern(Namespace.findOrCreate(Symbol.intern(null, ns)), Symbol.intern(null, name)); | |
312 } | |
313 | |
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 } | |
317 | |
318 public static void loadResourceScript(String name) throws Exception{ | |
319 loadResourceScript(name, true); | |
320 } | |
321 | |
322 public static void maybeLoadResourceScript(String name) throws Exception{ | |
323 loadResourceScript(name, false); | |
324 } | |
325 | |
326 public static void loadResourceScript(String name, boolean failIfNotFound) throws Exception{ | |
327 loadResourceScript(RT.class, name, failIfNotFound); | |
328 } | |
329 | |
330 public static void loadResourceScript(Class c, String name) throws Exception{ | |
331 loadResourceScript(c, name, true); | |
332 } | |
333 | |
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 } | |
350 | |
351 static public void init() throws Exception{ | |
352 RT.errPrintWriter().println("No need to call RT.init() anymore"); | |
353 } | |
354 | |
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 } | |
363 | |
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 } | |
374 | |
375 } | |
376 else | |
377 throw new FileNotFoundException("Could not locate Clojure resource on classpath: " + cljfile); | |
378 } | |
379 | |
380 static public void load(String scriptbase) throws Exception{ | |
381 load(scriptbase, true); | |
382 } | |
383 | |
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; | |
390 | |
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 } | |
414 | |
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); | |
420 | |
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"); | |
427 | |
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 } | |
438 | |
439 static public int nextID(){ | |
440 return id.getAndIncrement(); | |
441 } | |
442 | |
443 | |
444 ////////////// Collections support ///////////////////////////////// | |
445 | |
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 } | |
454 | |
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 } | |
474 | |
475 static public ISeq keys(Object coll){ | |
476 return APersistentMap.KeySeq.create(seq(coll)); | |
477 } | |
478 | |
479 static public ISeq vals(Object coll){ | |
480 return APersistentMap.ValSeq.create(seq(coll)); | |
481 } | |
482 | |
483 static public IPersistentMap meta(Object x){ | |
484 if(x instanceof IMeta) | |
485 return ((IMeta) x).meta(); | |
486 return null; | |
487 } | |
488 | |
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 } | |
494 | |
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); | |
517 | |
518 throw new UnsupportedOperationException("count not supported on this type: " + o.getClass().getSimpleName()); | |
519 } | |
520 | |
521 static public IPersistentCollection conj(IPersistentCollection coll, Object x){ | |
522 if(coll == null) | |
523 return new PersistentList(x); | |
524 return coll.cons(x); | |
525 } | |
526 | |
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 } | |
536 | |
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 } | |
545 | |
546 static public Object second(Object x){ | |
547 return first(next(x)); | |
548 } | |
549 | |
550 static public Object third(Object x){ | |
551 return first(next(next(x))); | |
552 } | |
553 | |
554 static public Object fourth(Object x){ | |
555 return first(next(next(next(x)))); | |
556 } | |
557 | |
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 } | |
566 | |
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 } | |
575 | |
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 //} | |
592 | |
593 static public Object peek(Object x){ | |
594 if(x == null) | |
595 return null; | |
596 return ((IPersistentStack) x).peek(); | |
597 } | |
598 | |
599 static public Object pop(Object x){ | |
600 if(x == null) | |
601 return null; | |
602 return ((IPersistentStack) x).pop(); | |
603 } | |
604 | |
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 } | |
610 | |
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 } | |
628 | |
629 return null; | |
630 } | |
631 | |
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 } | |
637 | |
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; | |
658 | |
659 } | |
660 | |
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 } | |
666 | |
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 } | |
684 | |
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 } | |
697 | |
698 //takes a seq of key,val,key,val | |
699 | |
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 } | |
712 | |
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 } | |
718 | |
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 } | |
724 | |
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); | |
736 | |
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 } | |
745 | |
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 } | |
759 | |
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 } | |
767 | |
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; | |
773 | |
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 } | |
818 | |
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 } | |
833 | |
834 static boolean hasTag(Object o, Object tag){ | |
835 return Util.equals(tag, RT.get(RT.meta(o), TAG_KEY)); | |
836 } | |
837 | |
838 /** | |
839 * ********************* Boxing/casts ****************************** | |
840 */ | |
841 static public Object box(Object x){ | |
842 return x; | |
843 } | |
844 | |
845 static public Character box(char x){ | |
846 return Character.valueOf(x); | |
847 } | |
848 | |
849 static public Object box(boolean x){ | |
850 return x ? T : F; | |
851 } | |
852 | |
853 static public Object box(Boolean x){ | |
854 return x;// ? T : null; | |
855 } | |
856 | |
857 static public Number box(byte x){ | |
858 return x;//Num.from(x); | |
859 } | |
860 | |
861 static public Number box(short x){ | |
862 return x;//Num.from(x); | |
863 } | |
864 | |
865 static public Number box(int x){ | |
866 return x;//Num.from(x); | |
867 } | |
868 | |
869 static public Number box(long x){ | |
870 return x;//Num.from(x); | |
871 } | |
872 | |
873 static public Number box(float x){ | |
874 return x;//Num.from(x); | |
875 } | |
876 | |
877 static public Number box(double x){ | |
878 return x;//Num.from(x); | |
879 } | |
880 | |
881 static public char charCast(Object x){ | |
882 if(x instanceof Character) | |
883 return ((Character) x).charValue(); | |
884 | |
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); | |
888 | |
889 return (char) n; | |
890 } | |
891 | |
892 static public boolean booleanCast(Object x){ | |
893 if(x instanceof Boolean) | |
894 return ((Boolean) x).booleanValue(); | |
895 return x != null; | |
896 } | |
897 | |
898 static public boolean booleanCast(boolean x){ | |
899 return x; | |
900 } | |
901 | |
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); | |
906 | |
907 return (byte) n; | |
908 } | |
909 | |
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); | |
914 | |
915 return (short) n; | |
916 } | |
917 | |
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 } | |
925 | |
926 static public int intCast(char x){ | |
927 return x; | |
928 } | |
929 | |
930 static public int intCast(byte x){ | |
931 return x; | |
932 } | |
933 | |
934 static public int intCast(short x){ | |
935 return x; | |
936 } | |
937 | |
938 static public int intCast(int x){ | |
939 return x; | |
940 } | |
941 | |
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 } | |
947 | |
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 } | |
953 | |
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 } | |
959 | |
960 static public long longCast(Object x){ | |
961 return ((Number) x).longValue(); | |
962 } | |
963 | |
964 static public long longCast(int x){ | |
965 return x; | |
966 } | |
967 | |
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 } | |
973 | |
974 static public long longCast(long x){ | |
975 return x; | |
976 } | |
977 | |
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 } | |
983 | |
984 static public float floatCast(Object x){ | |
985 if(x instanceof Float) | |
986 return ((Float) x).floatValue(); | |
987 | |
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); | |
991 | |
992 return (float) n; | |
993 | |
994 } | |
995 | |
996 static public float floatCast(int x){ | |
997 return x; | |
998 } | |
999 | |
1000 static public float floatCast(float x){ | |
1001 return x; | |
1002 } | |
1003 | |
1004 static public float floatCast(long x){ | |
1005 return x; | |
1006 } | |
1007 | |
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); | |
1011 | |
1012 return (float) x; | |
1013 } | |
1014 | |
1015 static public double doubleCast(Object x){ | |
1016 return ((Number) x).doubleValue(); | |
1017 } | |
1018 | |
1019 static public double doubleCast(int x){ | |
1020 return x; | |
1021 } | |
1022 | |
1023 static public double doubleCast(float x){ | |
1024 return x; | |
1025 } | |
1026 | |
1027 static public double doubleCast(long x){ | |
1028 return x; | |
1029 } | |
1030 | |
1031 static public double doubleCast(double x){ | |
1032 return x; | |
1033 } | |
1034 | |
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); | |
1041 } | |
1042 | |
1043 static public IPersistentSet set(Object... init){ | |
1044 return PersistentHashSet.createWithCheck(init); | |
1045 } | |
1046 | |
1047 static public IPersistentVector vector(Object... init){ | |
1048 return LazilyPersistentVector.createOwning(init); | |
1049 } | |
1050 | |
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); | |
1057 } | |
1058 | |
1059 /** | |
1060 * **************************************** list support ******************************* | |
1061 */ | |
1062 | |
1063 | |
1064 static public ISeq list(){ | |
1065 return null; | |
1066 } | |
1067 | |
1068 static public ISeq list(Object arg1){ | |
1069 return new PersistentList(arg1); | |
1070 } | |
1071 | |
1072 static public ISeq list(Object arg1, Object arg2){ | |
1073 return listStar(arg1, arg2, null); | |
1074 } | |
1075 | |
1076 static public ISeq list(Object arg1, Object arg2, Object arg3){ | |
1077 return listStar(arg1, arg2, arg3, null); | |
1078 } | |
1079 | |
1080 static public ISeq list(Object arg1, Object arg2, Object arg3, Object arg4){ | |
1081 return listStar(arg1, arg2, arg3, arg4, null); | |
1082 } | |
1083 | |
1084 static public ISeq list(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5){ | |
1085 return listStar(arg1, arg2, arg3, arg4, arg5, null); | |
1086 } | |
1087 | |
1088 static public ISeq listStar(Object arg1, ISeq rest){ | |
1089 return (ISeq) cons(arg1, rest); | |
1090 } | |
1091 | |
1092 static public ISeq listStar(Object arg1, Object arg2, ISeq rest){ | |
1093 return (ISeq) cons(arg1, cons(arg2, rest)); | |
1094 } | |
1095 | |
1096 static public ISeq listStar(Object arg1, Object arg2, Object arg3, ISeq rest){ | |
1097 return (ISeq) cons(arg1, cons(arg2, cons(arg3, rest))); | |
1098 } | |
1099 | |
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)))); | |
1102 } | |
1103 | |
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))))); | |
1106 } | |
1107 | |
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; | |
1113 } | |
1114 | |
1115 static public Object[] object_array(Object sizeOrSeq){ | |
1116 if(sizeOrSeq instanceof Number) | |
1117 return new Object[((Number) sizeOrSeq).intValue()]; | |
1118 else | |
1119 { | |
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; | |
1126 } | |
1127 } | |
1128 | |
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; | |
1144 } | |
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; | |
1151 } | |
1152 else | |
1153 throw new Exception("Unable to convert: " + coll.getClass() + " to Object[]"); | |
1154 } | |
1155 | |
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; | |
1162 } | |
1163 | |
1164 static public Object seqToTypedArray(ISeq seq) throws Exception{ | |
1165 Class type = (seq != null) ? seq.first().getClass() : Object.class; | |
1166 return seqToTypedArray(type, seq); | |
1167 } | |
1168 | |
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; | |
1174 } | |
1175 | |
1176 static public int length(ISeq list){ | |
1177 int i = 0; | |
1178 for(ISeq c = list; c != null; c = c.next()) { | |
1179 i++; | |
1180 } | |
1181 return i; | |
1182 } | |
1183 | |
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++; | |
1188 } | |
1189 return i; | |
1190 } | |
1191 | |
1192 ///////////////////////////////// reader support //////////////////////////////// | |
1193 | |
1194 static Character readRet(int ret){ | |
1195 if(ret == -1) | |
1196 return null; | |
1197 return box((char) ret); | |
1198 } | |
1199 | |
1200 static public Character readChar(Reader r) throws Exception{ | |
1201 int ret = r.read(); | |
1202 return readRet(ret); | |
1203 } | |
1204 | |
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); | |
1210 } | |
1211 else { | |
1212 r.mark(1); | |
1213 ret = r.read(); | |
1214 r.reset(); | |
1215 } | |
1216 | |
1217 return readRet(ret); | |
1218 } | |
1219 | |
1220 static public int getLineNumber(Reader r){ | |
1221 if(r instanceof LineNumberingPushbackReader) | |
1222 return ((LineNumberingPushbackReader) r).getLineNumber(); | |
1223 return 0; | |
1224 } | |
1225 | |
1226 static public LineNumberingPushbackReader getLineNumberingReader(Reader r){ | |
1227 if(isLineNumberingReader(r)) | |
1228 return (LineNumberingPushbackReader) r; | |
1229 return new LineNumberingPushbackReader(r); | |
1230 } | |
1231 | |
1232 static public boolean isLineNumberingReader(Reader r){ | |
1233 return r instanceof LineNumberingPushbackReader; | |
1234 } | |
1235 | |
1236 static public String resolveClassNameInContext(String className){ | |
1237 //todo - look up in context var | |
1238 return className; | |
1239 } | |
1240 | |
1241 static public boolean suppressRead(){ | |
1242 //todo - look up in suppress-read var | |
1243 return false; | |
1244 } | |
1245 | |
1246 static public String printString(Object x){ | |
1247 try { | |
1248 StringWriter sw = new StringWriter(); | |
1249 print(x, sw); | |
1250 return sw.toString(); | |
1251 } | |
1252 catch(Exception e) { | |
1253 throw new RuntimeException(e); | |
1254 } | |
1255 } | |
1256 | |
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); | |
1261 } | |
1262 catch(Exception e) { | |
1263 throw new RuntimeException(e); | |
1264 } | |
1265 } | |
1266 | |
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(' '); | |
1286 } | |
1287 } | |
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(')'); | |
1294 } | |
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); | |
1328 } | |
1329 } | |
1330 w.write('"'); | |
1331 } | |
1332 } | |
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(", "); | |
1342 } | |
1343 w.write('}'); | |
1344 } | |
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(' '); | |
1352 } | |
1353 w.write(']'); | |
1354 } | |
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(" "); | |
1361 } | |
1362 w.write('}'); | |
1363 } | |
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); | |
1391 } | |
1392 } | |
1393 } | |
1394 else if(x instanceof Class) { | |
1395 w.write("#="); | |
1396 w.write(((Class) x).getName()); | |
1397 } | |
1398 else if(x instanceof BigDecimal && readably) { | |
1399 w.write(x.toString()); | |
1400 w.write('M'); | |
1401 } | |
1402 else if(x instanceof Var) { | |
1403 Var v = (Var) x; | |
1404 w.write("#=(var " + v.ns.name + "/" + v.sym + ")"); | |
1405 } | |
1406 else if(x instanceof Pattern) { | |
1407 Pattern p = (Pattern) x; | |
1408 w.write("#\"" + p.pattern() + "\""); | |
1409 } | |
1410 else w.write(x.toString()); | |
1411 } | |
1412 //*/ | |
1413 } | |
1414 | |
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(' '); | |
1420 } | |
1421 } | |
1422 | |
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()); | |
1428 } | |
1429 | |
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('"'); | |
1437 } | |
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); | |
1459 } | |
1460 } | |
1461 else | |
1462 w.write(obj.toString()); | |
1463 } | |
1464 | |
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; | |
1477 } | |
1478 | |
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); | |
1523 } | |
1524 break; | |
1525 default: | |
1526 w.write(c); | |
1527 } | |
1528 } | |
1529 return args; | |
1530 } | |
1531 ///////////////////////////////// values ////////////////////////// | |
1532 | |
1533 static public Object[] setValues(Object... vals){ | |
1534 //ThreadLocalData.setValues(vals); | |
1535 if(vals.length > 0) | |
1536 return vals;//[0]; | |
1537 return null; | |
1538 } | |
1539 | |
1540 | |
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()); | |
1548 } | |
1549 finally{ | |
1550 Var.popThreadBindings(); | |
1551 } | |
1552 } | |
1553 }); | |
1554 } | |
1555 | |
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(); | |
1562 } | |
1563 | |
1564 static public Class classForName(String name) throws ClassNotFoundException{ | |
1565 | |
1566 return Class.forName(name, true, baseLoader()); | |
1567 } | |
1568 | |
1569 static public Class loadClassForName(String name) throws ClassNotFoundException{ | |
1570 try | |
1571 { | |
1572 Class.forName(name, false, baseLoader()); | |
1573 } | |
1574 catch(ClassNotFoundException e) | |
1575 { | |
1576 return null; | |
1577 } | |
1578 return Class.forName(name, true, baseLoader()); | |
1579 } | |
1580 | |
1581 static public float aget(float[] xs, int i){ | |
1582 return xs[i]; | |
1583 } | |
1584 | |
1585 static public float aset(float[] xs, int i, float v){ | |
1586 xs[i] = v; | |
1587 return v; | |
1588 } | |
1589 | |
1590 static public int alength(float[] xs){ | |
1591 return xs.length; | |
1592 } | |
1593 | |
1594 static public float[] aclone(float[] xs){ | |
1595 return xs.clone(); | |
1596 } | |
1597 | |
1598 static public double aget(double[] xs, int i){ | |
1599 return xs[i]; | |
1600 } | |
1601 | |
1602 static public double aset(double[] xs, int i, double v){ | |
1603 xs[i] = v; | |
1604 return v; | |
1605 } | |
1606 | |
1607 static public int alength(double[] xs){ | |
1608 return xs.length; | |
1609 } | |
1610 | |
1611 static public double[] aclone(double[] xs){ | |
1612 return xs.clone(); | |
1613 } | |
1614 | |
1615 static public int aget(int[] xs, int i){ | |
1616 return xs[i]; | |
1617 } | |
1618 | |
1619 static public int aset(int[] xs, int i, int v){ | |
1620 xs[i] = v; | |
1621 return v; | |
1622 } | |
1623 | |
1624 static public int alength(int[] xs){ | |
1625 return xs.length; | |
1626 } | |
1627 | |
1628 static public int[] aclone(int[] xs){ | |
1629 return xs.clone(); | |
1630 } | |
1631 | |
1632 static public long aget(long[] xs, int i){ | |
1633 return xs[i]; | |
1634 } | |
1635 | |
1636 static public long aset(long[] xs, int i, long v){ | |
1637 xs[i] = v; | |
1638 return v; | |
1639 } | |
1640 | |
1641 static public int alength(long[] xs){ | |
1642 return xs.length; | |
1643 } | |
1644 | |
1645 static public long[] aclone(long[] xs){ | |
1646 return xs.clone(); | |
1647 } | |
1648 | |
1649 static public char aget(char[] xs, int i){ | |
1650 return xs[i]; | |
1651 } | |
1652 | |
1653 static public char aset(char[] xs, int i, char v){ | |
1654 xs[i] = v; | |
1655 return v; | |
1656 } | |
1657 | |
1658 static public int alength(char[] xs){ | |
1659 return xs.length; | |
1660 } | |
1661 | |
1662 static public char[] aclone(char[] xs){ | |
1663 return xs.clone(); | |
1664 } | |
1665 | |
1666 static public byte aget(byte[] xs, int i){ | |
1667 return xs[i]; | |
1668 } | |
1669 | |
1670 static public byte aset(byte[] xs, int i, byte v){ | |
1671 xs[i] = v; | |
1672 return v; | |
1673 } | |
1674 | |
1675 static public int alength(byte[] xs){ | |
1676 return xs.length; | |
1677 } | |
1678 | |
1679 static public byte[] aclone(byte[] xs){ | |
1680 return xs.clone(); | |
1681 } | |
1682 | |
1683 static public short aget(short[] xs, int i){ | |
1684 return xs[i]; | |
1685 } | |
1686 | |
1687 static public short aset(short[] xs, int i, short v){ | |
1688 xs[i] = v; | |
1689 return v; | |
1690 } | |
1691 | |
1692 static public int alength(short[] xs){ | |
1693 return xs.length; | |
1694 } | |
1695 | |
1696 static public short[] aclone(short[] xs){ | |
1697 return xs.clone(); | |
1698 } | |
1699 | |
1700 static public boolean aget(boolean[] xs, int i){ | |
1701 return xs[i]; | |
1702 } | |
1703 | |
1704 static public boolean aset(boolean[] xs, int i, boolean v){ | |
1705 xs[i] = v; | |
1706 return v; | |
1707 } | |
1708 | |
1709 static public int alength(boolean[] xs){ | |
1710 return xs.length; | |
1711 } | |
1712 | |
1713 static public boolean[] aclone(boolean[] xs){ | |
1714 return xs.clone(); | |
1715 } | |
1716 | |
1717 static public Object aget(Object[] xs, int i){ | |
1718 return xs[i]; | |
1719 } | |
1720 | |
1721 static public Object aset(Object[] xs, int i, Object v){ | |
1722 xs[i] = v; | |
1723 return v; | |
1724 } | |
1725 | |
1726 static public int alength(Object[] xs){ | |
1727 return xs.length; | |
1728 } | |
1729 | |
1730 static public Object[] aclone(Object[] xs){ | |
1731 return xs.clone(); | |
1732 } | |
1733 | |
1734 | |
1735 } |