rlm@10: /** rlm@10: * Copyright (c) Rich Hickey. All rights reserved. rlm@10: * The use and distribution terms for this software are covered by the rlm@10: * Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) rlm@10: * which can be found in the file epl-v10.html at the root of this distribution. rlm@10: * By using this software in any fashion, you are agreeing to be bound by rlm@10: * the terms of this license. rlm@10: * You must not remove this notice, or any other, from this software. rlm@10: **/ rlm@10: rlm@10: /* rich Mar 25, 2006 4:28:27 PM */ rlm@10: rlm@10: package clojure.lang; rlm@10: rlm@10: import java.util.concurrent.atomic.AtomicInteger; rlm@10: import java.util.concurrent.Callable; rlm@10: import java.util.*; rlm@10: import java.util.regex.Matcher; rlm@10: import java.util.regex.Pattern; rlm@10: import java.io.*; rlm@10: import java.lang.reflect.Array; rlm@10: import java.math.BigDecimal; rlm@10: import java.math.BigInteger; rlm@10: import java.security.AccessController; rlm@10: import java.security.PrivilegedAction; rlm@10: import java.net.URL; rlm@10: import java.net.JarURLConnection; rlm@10: import java.nio.charset.Charset; rlm@10: rlm@10: public class RT{ rlm@10: rlm@10: static final public Boolean T = Boolean.TRUE;//Keyword.intern(Symbol.create(null, "t")); rlm@10: static final public Boolean F = Boolean.FALSE;//Keyword.intern(Symbol.create(null, "t")); rlm@10: static final public String LOADER_SUFFIX = "__init"; rlm@10: rlm@10: //simple-symbol->class rlm@10: final static IPersistentMap DEFAULT_IMPORTS = map( rlm@10: // Symbol.create("RT"), "clojure.lang.RT", rlm@10: // Symbol.create("Num"), "clojure.lang.Num", rlm@10: // Symbol.create("Symbol"), "clojure.lang.Symbol", rlm@10: // Symbol.create("Keyword"), "clojure.lang.Keyword", rlm@10: // Symbol.create("Var"), "clojure.lang.Var", rlm@10: // Symbol.create("Ref"), "clojure.lang.Ref", rlm@10: // Symbol.create("IFn"), "clojure.lang.IFn", rlm@10: // Symbol.create("IObj"), "clojure.lang.IObj", rlm@10: // Symbol.create("ISeq"), "clojure.lang.ISeq", rlm@10: // Symbol.create("IPersistentCollection"), rlm@10: // "clojure.lang.IPersistentCollection", rlm@10: // Symbol.create("IPersistentMap"), "clojure.lang.IPersistentMap", rlm@10: // Symbol.create("IPersistentList"), "clojure.lang.IPersistentList", rlm@10: // Symbol.create("IPersistentVector"), "clojure.lang.IPersistentVector", rlm@10: Symbol.create("Boolean"), Boolean.class, rlm@10: Symbol.create("Byte"), Byte.class, rlm@10: Symbol.create("Character"), Character.class, rlm@10: Symbol.create("Class"), Class.class, rlm@10: Symbol.create("ClassLoader"), ClassLoader.class, rlm@10: Symbol.create("Compiler"), Compiler.class, rlm@10: Symbol.create("Double"), Double.class, rlm@10: Symbol.create("Enum"), Enum.class, rlm@10: Symbol.create("Float"), Float.class, rlm@10: Symbol.create("InheritableThreadLocal"), InheritableThreadLocal.class, rlm@10: Symbol.create("Integer"), Integer.class, rlm@10: Symbol.create("Long"), Long.class, rlm@10: Symbol.create("Math"), Math.class, rlm@10: Symbol.create("Number"), Number.class, rlm@10: Symbol.create("Object"), Object.class, rlm@10: Symbol.create("Package"), Package.class, rlm@10: Symbol.create("Process"), Process.class, rlm@10: Symbol.create("ProcessBuilder"), ProcessBuilder.class, rlm@10: Symbol.create("Runtime"), Runtime.class, rlm@10: Symbol.create("RuntimePermission"), RuntimePermission.class, rlm@10: Symbol.create("SecurityManager"), SecurityManager.class, rlm@10: Symbol.create("Short"), Short.class, rlm@10: Symbol.create("StackTraceElement"), StackTraceElement.class, rlm@10: Symbol.create("StrictMath"), StrictMath.class, rlm@10: Symbol.create("String"), String.class, rlm@10: Symbol.create("StringBuffer"), StringBuffer.class, rlm@10: Symbol.create("StringBuilder"), StringBuilder.class, rlm@10: Symbol.create("System"), System.class, rlm@10: Symbol.create("Thread"), Thread.class, rlm@10: Symbol.create("ThreadGroup"), ThreadGroup.class, rlm@10: Symbol.create("ThreadLocal"), ThreadLocal.class, rlm@10: Symbol.create("Throwable"), Throwable.class, rlm@10: Symbol.create("Void"), Void.class, rlm@10: Symbol.create("Appendable"), Appendable.class, rlm@10: Symbol.create("CharSequence"), CharSequence.class, rlm@10: Symbol.create("Cloneable"), Cloneable.class, rlm@10: Symbol.create("Comparable"), Comparable.class, rlm@10: Symbol.create("Iterable"), Iterable.class, rlm@10: Symbol.create("Readable"), Readable.class, rlm@10: Symbol.create("Runnable"), Runnable.class, rlm@10: Symbol.create("Callable"), Callable.class, rlm@10: Symbol.create("BigInteger"), BigInteger.class, rlm@10: Symbol.create("BigDecimal"), BigDecimal.class, rlm@10: Symbol.create("ArithmeticException"), ArithmeticException.class, rlm@10: Symbol.create("ArrayIndexOutOfBoundsException"), ArrayIndexOutOfBoundsException.class, rlm@10: Symbol.create("ArrayStoreException"), ArrayStoreException.class, rlm@10: Symbol.create("ClassCastException"), ClassCastException.class, rlm@10: Symbol.create("ClassNotFoundException"), ClassNotFoundException.class, rlm@10: Symbol.create("CloneNotSupportedException"), CloneNotSupportedException.class, rlm@10: Symbol.create("EnumConstantNotPresentException"), EnumConstantNotPresentException.class, rlm@10: Symbol.create("Exception"), Exception.class, rlm@10: Symbol.create("IllegalAccessException"), IllegalAccessException.class, rlm@10: Symbol.create("IllegalArgumentException"), IllegalArgumentException.class, rlm@10: Symbol.create("IllegalMonitorStateException"), IllegalMonitorStateException.class, rlm@10: Symbol.create("IllegalStateException"), IllegalStateException.class, rlm@10: Symbol.create("IllegalThreadStateException"), IllegalThreadStateException.class, rlm@10: Symbol.create("IndexOutOfBoundsException"), IndexOutOfBoundsException.class, rlm@10: Symbol.create("InstantiationException"), InstantiationException.class, rlm@10: Symbol.create("InterruptedException"), InterruptedException.class, rlm@10: Symbol.create("NegativeArraySizeException"), NegativeArraySizeException.class, rlm@10: Symbol.create("NoSuchFieldException"), NoSuchFieldException.class, rlm@10: Symbol.create("NoSuchMethodException"), NoSuchMethodException.class, rlm@10: Symbol.create("NullPointerException"), NullPointerException.class, rlm@10: Symbol.create("NumberFormatException"), NumberFormatException.class, rlm@10: Symbol.create("RuntimeException"), RuntimeException.class, rlm@10: Symbol.create("SecurityException"), SecurityException.class, rlm@10: Symbol.create("StringIndexOutOfBoundsException"), StringIndexOutOfBoundsException.class, rlm@10: Symbol.create("TypeNotPresentException"), TypeNotPresentException.class, rlm@10: Symbol.create("UnsupportedOperationException"), UnsupportedOperationException.class, rlm@10: Symbol.create("AbstractMethodError"), AbstractMethodError.class, rlm@10: Symbol.create("AssertionError"), AssertionError.class, rlm@10: Symbol.create("ClassCircularityError"), ClassCircularityError.class, rlm@10: Symbol.create("ClassFormatError"), ClassFormatError.class, rlm@10: Symbol.create("Error"), Error.class, rlm@10: Symbol.create("ExceptionInInitializerError"), ExceptionInInitializerError.class, rlm@10: Symbol.create("IllegalAccessError"), IllegalAccessError.class, rlm@10: Symbol.create("IncompatibleClassChangeError"), IncompatibleClassChangeError.class, rlm@10: Symbol.create("InstantiationError"), InstantiationError.class, rlm@10: Symbol.create("InternalError"), InternalError.class, rlm@10: Symbol.create("LinkageError"), LinkageError.class, rlm@10: Symbol.create("NoClassDefFoundError"), NoClassDefFoundError.class, rlm@10: Symbol.create("NoSuchFieldError"), NoSuchFieldError.class, rlm@10: Symbol.create("NoSuchMethodError"), NoSuchMethodError.class, rlm@10: Symbol.create("OutOfMemoryError"), OutOfMemoryError.class, rlm@10: Symbol.create("StackOverflowError"), StackOverflowError.class, rlm@10: Symbol.create("ThreadDeath"), ThreadDeath.class, rlm@10: Symbol.create("UnknownError"), UnknownError.class, rlm@10: Symbol.create("UnsatisfiedLinkError"), UnsatisfiedLinkError.class, rlm@10: Symbol.create("UnsupportedClassVersionError"), UnsupportedClassVersionError.class, rlm@10: Symbol.create("VerifyError"), VerifyError.class, rlm@10: Symbol.create("VirtualMachineError"), VirtualMachineError.class, rlm@10: Symbol.create("Thread$UncaughtExceptionHandler"), Thread.UncaughtExceptionHandler.class, rlm@10: Symbol.create("Thread$State"), Thread.State.class, rlm@10: Symbol.create("Deprecated"), Deprecated.class, rlm@10: Symbol.create("Override"), Override.class, rlm@10: Symbol.create("SuppressWarnings"), SuppressWarnings.class rlm@10: rlm@10: // Symbol.create("Collection"), "java.util.Collection", rlm@10: // Symbol.create("Comparator"), "java.util.Comparator", rlm@10: // Symbol.create("Enumeration"), "java.util.Enumeration", rlm@10: // Symbol.create("EventListener"), "java.util.EventListener", rlm@10: // Symbol.create("Formattable"), "java.util.Formattable", rlm@10: // Symbol.create("Iterator"), "java.util.Iterator", rlm@10: // Symbol.create("List"), "java.util.List", rlm@10: // Symbol.create("ListIterator"), "java.util.ListIterator", rlm@10: // Symbol.create("Map"), "java.util.Map", rlm@10: // Symbol.create("Map$Entry"), "java.util.Map$Entry", rlm@10: // Symbol.create("Observer"), "java.util.Observer", rlm@10: // Symbol.create("Queue"), "java.util.Queue", rlm@10: // Symbol.create("RandomAccess"), "java.util.RandomAccess", rlm@10: // Symbol.create("Set"), "java.util.Set", rlm@10: // Symbol.create("SortedMap"), "java.util.SortedMap", rlm@10: // Symbol.create("SortedSet"), "java.util.SortedSet" rlm@10: ); rlm@10: rlm@10: // single instance of UTF-8 Charset, so as to avoid catching UnsupportedCharsetExceptions everywhere rlm@10: static public Charset UTF8 = Charset.forName("UTF-8"); rlm@10: rlm@10: static public final Namespace CLOJURE_NS = Namespace.findOrCreate(Symbol.create("clojure.core")); rlm@10: //static final Namespace USER_NS = Namespace.findOrCreate(Symbol.create("user")); rlm@10: final static public Var OUT = rlm@10: Var.intern(CLOJURE_NS, Symbol.create("*out*"), new OutputStreamWriter(System.out)); rlm@10: final static public Var IN = rlm@10: Var.intern(CLOJURE_NS, Symbol.create("*in*"), rlm@10: new LineNumberingPushbackReader(new InputStreamReader(System.in))); rlm@10: final static public Var ERR = rlm@10: Var.intern(CLOJURE_NS, Symbol.create("*err*"), rlm@10: new PrintWriter(new OutputStreamWriter(System.err), true)); rlm@10: final static Keyword TAG_KEY = Keyword.intern(null, "tag"); rlm@10: final static public Var AGENT = Var.intern(CLOJURE_NS, Symbol.create("*agent*"), null); rlm@10: final static public Var READEVAL = Var.intern(CLOJURE_NS, Symbol.create("*read-eval*"), T); rlm@10: final static public Var ASSERT = Var.intern(CLOJURE_NS, Symbol.create("*assert*"), T); rlm@10: final static public Var MATH_CONTEXT = Var.intern(CLOJURE_NS, Symbol.create("*math-context*"), null); rlm@10: static Keyword LINE_KEY = Keyword.intern(null, "line"); rlm@10: static Keyword FILE_KEY = Keyword.intern(null, "file"); rlm@10: static Keyword DECLARED_KEY = Keyword.intern(null, "declared"); rlm@10: final static public Var USE_CONTEXT_CLASSLOADER = rlm@10: Var.intern(CLOJURE_NS, Symbol.create("*use-context-classloader*"), T); rlm@10: //final static public Var CURRENT_MODULE = Var.intern(Symbol.create("clojure.core", "current-module"), rlm@10: // Module.findOrCreateModule("clojure/user")); rlm@10: rlm@10: final static Symbol LOAD_FILE = Symbol.create("load-file"); rlm@10: final static Symbol IN_NAMESPACE = Symbol.create("in-ns"); rlm@10: final static Symbol NAMESPACE = Symbol.create("ns"); rlm@10: static final Symbol IDENTICAL = Symbol.create("identical?"); rlm@10: final static Var CMD_LINE_ARGS = Var.intern(CLOJURE_NS, Symbol.create("*command-line-args*"), null); rlm@10: //symbol rlm@10: final public static Var CURRENT_NS = Var.intern(CLOJURE_NS, Symbol.create("*ns*"), rlm@10: CLOJURE_NS); rlm@10: rlm@10: final static Var FLUSH_ON_NEWLINE = Var.intern(CLOJURE_NS, Symbol.create("*flush-on-newline*"), T); rlm@10: final static Var PRINT_META = Var.intern(CLOJURE_NS, Symbol.create("*print-meta*"), F); rlm@10: final static Var PRINT_READABLY = Var.intern(CLOJURE_NS, Symbol.create("*print-readably*"), T); rlm@10: final static Var PRINT_DUP = Var.intern(CLOJURE_NS, Symbol.create("*print-dup*"), F); rlm@10: final static Var WARN_ON_REFLECTION = Var.intern(CLOJURE_NS, Symbol.create("*warn-on-reflection*"), F); rlm@10: final static Var ALLOW_UNRESOLVED_VARS = Var.intern(CLOJURE_NS, Symbol.create("*allow-unresolved-vars*"), F); rlm@10: rlm@10: final static Var IN_NS_VAR = Var.intern(CLOJURE_NS, Symbol.create("in-ns"), F); rlm@10: final static Var NS_VAR = Var.intern(CLOJURE_NS, Symbol.create("ns"), F); rlm@10: static final Var PRINT_INITIALIZED = Var.intern(CLOJURE_NS, Symbol.create("print-initialized")); rlm@10: static final Var PR_ON = Var.intern(CLOJURE_NS, Symbol.create("pr-on")); rlm@10: //final static Var IMPORTS = Var.intern(CLOJURE_NS, Symbol.create("*imports*"), DEFAULT_IMPORTS); rlm@10: final static IFn inNamespace = new AFn(){ rlm@10: public Object invoke(Object arg1) throws Exception{ rlm@10: Symbol nsname = (Symbol) arg1; rlm@10: Namespace ns = Namespace.findOrCreate(nsname); rlm@10: CURRENT_NS.set(ns); rlm@10: return ns; rlm@10: } rlm@10: }; rlm@10: rlm@10: final static IFn bootNamespace = new AFn(){ rlm@10: public Object invoke(Object __form, Object __env,Object arg1) throws Exception{ rlm@10: Symbol nsname = (Symbol) arg1; rlm@10: Namespace ns = Namespace.findOrCreate(nsname); rlm@10: CURRENT_NS.set(ns); rlm@10: return ns; rlm@10: } rlm@10: }; rlm@10: rlm@10: public static List processCommandLine(String[] args){ rlm@10: List arglist = Arrays.asList(args); rlm@10: int split = arglist.indexOf("--"); rlm@10: if(split >= 0) { rlm@10: CMD_LINE_ARGS.bindRoot(RT.seq(arglist.subList(split + 1, args.length))); rlm@10: return arglist.subList(0, split); rlm@10: } rlm@10: return arglist; rlm@10: } rlm@10: rlm@10: // duck typing stderr plays nice with e.g. swank rlm@10: public static PrintWriter errPrintWriter(){ rlm@10: Writer w = (Writer) ERR.deref(); rlm@10: if (w instanceof PrintWriter) { rlm@10: return (PrintWriter) w; rlm@10: } else { rlm@10: return new PrintWriter(w); rlm@10: } rlm@10: } rlm@10: rlm@10: static public final Object[] EMPTY_ARRAY = new Object[]{}; rlm@10: static public final Comparator DEFAULT_COMPARATOR = new DefaultComparator(); rlm@10: rlm@10: private static final class DefaultComparator implements Comparator, Serializable { rlm@10: public int compare(Object o1, Object o2){ rlm@10: return Util.compare(o1, o2); rlm@10: } rlm@10: rlm@10: private Object readResolve() throws ObjectStreamException { rlm@10: // ensures that we aren't hanging onto a new default comparator for every rlm@10: // sorted set, etc., we deserialize rlm@10: return DEFAULT_COMPARATOR; rlm@10: } rlm@10: } rlm@10: rlm@10: static AtomicInteger id = new AtomicInteger(1); rlm@10: rlm@10: static public void addURL(Object url) throws Exception{ rlm@10: URL u = (url instanceof String) ? (new URL((String) url)) : (URL) url; rlm@10: ClassLoader ccl = Thread.currentThread().getContextClassLoader(); rlm@10: if(ccl instanceof DynamicClassLoader) rlm@10: ((DynamicClassLoader)ccl).addURL(u); rlm@10: else rlm@10: throw new IllegalAccessError("Context classloader is not a DynamicClassLoader"); rlm@10: } rlm@10: rlm@10: static{ rlm@10: Keyword dockw = Keyword.intern(null, "doc"); rlm@10: Keyword arglistskw = Keyword.intern(null, "arglists"); rlm@10: Symbol namesym = Symbol.create("name"); rlm@10: OUT.setTag(Symbol.create("java.io.Writer")); rlm@10: CURRENT_NS.setTag(Symbol.create("clojure.lang.Namespace")); rlm@10: AGENT.setMeta(map(dockw, "The agent currently running an action on this thread, else nil")); rlm@10: AGENT.setTag(Symbol.create("clojure.lang.Agent")); rlm@10: MATH_CONTEXT.setTag(Symbol.create("java.math.MathContext")); rlm@10: Var nv = Var.intern(CLOJURE_NS, NAMESPACE, bootNamespace); rlm@10: nv.setMacro(); rlm@10: Var v; rlm@10: v = Var.intern(CLOJURE_NS, IN_NAMESPACE, inNamespace); rlm@10: v.setMeta(map(dockw, "Sets *ns* to the namespace named by the symbol, creating it if needed.", rlm@10: arglistskw, list(vector(namesym)))); rlm@10: v = Var.intern(CLOJURE_NS, LOAD_FILE, rlm@10: new AFn(){ rlm@10: public Object invoke(Object arg1) throws Exception{ rlm@10: return Compiler.loadFile((String) arg1); rlm@10: } rlm@10: }); rlm@10: v.setMeta(map(dockw, "Sequentially read and evaluate the set of forms contained in the file.", rlm@10: arglistskw, list(vector(namesym)))); rlm@10: try { rlm@10: doInit(); rlm@10: } rlm@10: catch(Exception e) { rlm@10: throw new RuntimeException(e); rlm@10: } rlm@10: } rlm@10: rlm@10: rlm@10: static public Var var(String ns, String name){ rlm@10: return Var.intern(Namespace.findOrCreate(Symbol.intern(null, ns)), Symbol.intern(null, name)); rlm@10: } rlm@10: rlm@10: static public Var var(String ns, String name, Object init){ rlm@10: return Var.intern(Namespace.findOrCreate(Symbol.intern(null, ns)), Symbol.intern(null, name), init); rlm@10: } rlm@10: rlm@10: public static void loadResourceScript(String name) throws Exception{ rlm@10: loadResourceScript(name, true); rlm@10: } rlm@10: rlm@10: public static void maybeLoadResourceScript(String name) throws Exception{ rlm@10: loadResourceScript(name, false); rlm@10: } rlm@10: rlm@10: public static void loadResourceScript(String name, boolean failIfNotFound) throws Exception{ rlm@10: loadResourceScript(RT.class, name, failIfNotFound); rlm@10: } rlm@10: rlm@10: public static void loadResourceScript(Class c, String name) throws Exception{ rlm@10: loadResourceScript(c, name, true); rlm@10: } rlm@10: rlm@10: public static void loadResourceScript(Class c, String name, boolean failIfNotFound) throws Exception{ rlm@10: int slash = name.lastIndexOf('/'); rlm@10: String file = slash >= 0 ? name.substring(slash + 1) : name; rlm@10: InputStream ins = baseLoader().getResourceAsStream(name); rlm@10: if(ins != null) { rlm@10: try { rlm@10: Compiler.load(new InputStreamReader(ins, UTF8), name, file); rlm@10: } rlm@10: finally { rlm@10: ins.close(); rlm@10: } rlm@10: } rlm@10: else if(failIfNotFound) { rlm@10: throw new FileNotFoundException("Could not locate Clojure resource on classpath: " + name); rlm@10: } rlm@10: } rlm@10: rlm@10: static public void init() throws Exception{ rlm@10: RT.errPrintWriter().println("No need to call RT.init() anymore"); rlm@10: } rlm@10: rlm@10: static public long lastModified(URL url, String libfile) throws Exception{ rlm@10: if(url.getProtocol().equals("jar")) { rlm@10: return ((JarURLConnection) url.openConnection()).getJarFile().getEntry(libfile).getTime(); rlm@10: } rlm@10: else { rlm@10: return url.openConnection().getLastModified(); rlm@10: } rlm@10: } rlm@10: rlm@10: static void compile(String cljfile) throws Exception{ rlm@10: InputStream ins = baseLoader().getResourceAsStream(cljfile); rlm@10: if(ins != null) { rlm@10: try { rlm@10: Compiler.compile(new InputStreamReader(ins, UTF8), cljfile, rlm@10: cljfile.substring(1 + cljfile.lastIndexOf("/"))); rlm@10: } rlm@10: finally { rlm@10: ins.close(); rlm@10: } rlm@10: rlm@10: } rlm@10: else rlm@10: throw new FileNotFoundException("Could not locate Clojure resource on classpath: " + cljfile); rlm@10: } rlm@10: rlm@10: static public void load(String scriptbase) throws Exception{ rlm@10: load(scriptbase, true); rlm@10: } rlm@10: rlm@10: static public void load(String scriptbase, boolean failIfNotFound) throws Exception{ rlm@10: String classfile = scriptbase + LOADER_SUFFIX + ".class"; rlm@10: String cljfile = scriptbase + ".clj"; rlm@10: URL classURL = baseLoader().getResource(classfile); rlm@10: URL cljURL = baseLoader().getResource(cljfile); rlm@10: boolean loaded = false; rlm@10: rlm@10: if((classURL != null && rlm@10: (cljURL == null rlm@10: || lastModified(classURL, classfile) > lastModified(cljURL, cljfile))) rlm@10: || classURL == null) { rlm@10: try { rlm@10: Var.pushThreadBindings( rlm@10: RT.map(CURRENT_NS, CURRENT_NS.deref(), rlm@10: WARN_ON_REFLECTION, WARN_ON_REFLECTION.deref())); rlm@10: loaded = (loadClassForName(scriptbase.replace('/', '.') + LOADER_SUFFIX) != null); rlm@10: } rlm@10: finally { rlm@10: Var.popThreadBindings(); rlm@10: } rlm@10: } rlm@10: if(!loaded && cljURL != null) { rlm@10: if(booleanCast(Compiler.COMPILE_FILES.deref())) rlm@10: compile(cljfile); rlm@10: else rlm@10: loadResourceScript(RT.class, cljfile); rlm@10: } rlm@10: else if(!loaded && failIfNotFound) rlm@10: throw new FileNotFoundException(String.format("Could not locate %s or %s on classpath: ", classfile, cljfile)); rlm@10: } rlm@10: rlm@10: static void doInit() throws Exception{ rlm@10: load("clojure/core"); rlm@10: load("clojure/zip", false); rlm@10: load("clojure/xml", false); rlm@10: load("clojure/set", false); rlm@10: rlm@10: Var.pushThreadBindings( rlm@10: RT.map(CURRENT_NS, CURRENT_NS.deref(), rlm@10: WARN_ON_REFLECTION, WARN_ON_REFLECTION.deref())); rlm@10: try { rlm@10: Symbol USER = Symbol.create("user"); rlm@10: Symbol CLOJURE = Symbol.create("clojure.core"); rlm@10: rlm@10: Var in_ns = var("clojure.core", "in-ns"); rlm@10: Var refer = var("clojure.core", "refer"); rlm@10: in_ns.invoke(USER); rlm@10: refer.invoke(CLOJURE); rlm@10: maybeLoadResourceScript("user.clj"); rlm@10: } rlm@10: finally { rlm@10: Var.popThreadBindings(); rlm@10: } rlm@10: } rlm@10: rlm@10: static public int nextID(){ rlm@10: return id.getAndIncrement(); rlm@10: } rlm@10: rlm@10: rlm@10: ////////////// Collections support ///////////////////////////////// rlm@10: rlm@10: static public ISeq seq(Object coll){ rlm@10: if(coll instanceof ASeq) rlm@10: return (ASeq) coll; rlm@10: else if(coll instanceof LazySeq) rlm@10: return ((LazySeq) coll).seq(); rlm@10: else rlm@10: return seqFrom(coll); rlm@10: } rlm@10: rlm@10: static ISeq seqFrom(Object coll){ rlm@10: if(coll instanceof Seqable) rlm@10: return ((Seqable) coll).seq(); rlm@10: else if(coll == null) rlm@10: return null; rlm@10: else if(coll instanceof Iterable) rlm@10: return IteratorSeq.create(((Iterable) coll).iterator()); rlm@10: else if(coll.getClass().isArray()) rlm@10: return ArraySeq.createFromObject(coll); rlm@10: else if(coll instanceof CharSequence) rlm@10: return StringSeq.create((CharSequence) coll); rlm@10: else if(coll instanceof Map) rlm@10: return seq(((Map) coll).entrySet()); rlm@10: else { rlm@10: Class c = coll.getClass(); rlm@10: Class sc = c.getSuperclass(); rlm@10: throw new IllegalArgumentException("Don't know how to create ISeq from: " + c.getName()); rlm@10: } rlm@10: } rlm@10: rlm@10: static public ISeq keys(Object coll){ rlm@10: return APersistentMap.KeySeq.create(seq(coll)); rlm@10: } rlm@10: rlm@10: static public ISeq vals(Object coll){ rlm@10: return APersistentMap.ValSeq.create(seq(coll)); rlm@10: } rlm@10: rlm@10: static public IPersistentMap meta(Object x){ rlm@10: if(x instanceof IMeta) rlm@10: return ((IMeta) x).meta(); rlm@10: return null; rlm@10: } rlm@10: rlm@10: public static int count(Object o){ rlm@10: if(o instanceof Counted) rlm@10: return ((Counted) o).count(); rlm@10: return countFrom(Util.ret1(o, o = null)); rlm@10: } rlm@10: rlm@10: static int countFrom(Object o){ rlm@10: if(o == null) rlm@10: return 0; rlm@10: else if(o instanceof IPersistentCollection) { rlm@10: ISeq s = seq(o); rlm@10: o = null; rlm@10: int i = 0; rlm@10: for(; s != null; s = s.next()) { rlm@10: if(s instanceof Counted) rlm@10: return i + s.count(); rlm@10: i++; rlm@10: } rlm@10: return i; rlm@10: } rlm@10: else if(o instanceof CharSequence) rlm@10: return ((CharSequence) o).length(); rlm@10: else if(o instanceof Collection) rlm@10: return ((Collection) o).size(); rlm@10: else if(o instanceof Map) rlm@10: return ((Map) o).size(); rlm@10: else if(o.getClass().isArray()) rlm@10: return Array.getLength(o); rlm@10: rlm@10: throw new UnsupportedOperationException("count not supported on this type: " + o.getClass().getSimpleName()); rlm@10: } rlm@10: rlm@10: static public IPersistentCollection conj(IPersistentCollection coll, Object x){ rlm@10: if(coll == null) rlm@10: return new PersistentList(x); rlm@10: return coll.cons(x); rlm@10: } rlm@10: rlm@10: static public ISeq cons(Object x, Object coll){ rlm@10: //ISeq y = seq(coll); rlm@10: if(coll == null) rlm@10: return new PersistentList(x); rlm@10: else if(coll instanceof ISeq) rlm@10: return new Cons(x, (ISeq) coll); rlm@10: else rlm@10: return new Cons(x, seq(coll)); rlm@10: } rlm@10: rlm@10: static public Object first(Object x){ rlm@10: if(x instanceof ISeq) rlm@10: return ((ISeq) x).first(); rlm@10: ISeq seq = seq(x); rlm@10: if(seq == null) rlm@10: return null; rlm@10: return seq.first(); rlm@10: } rlm@10: rlm@10: static public Object second(Object x){ rlm@10: return first(next(x)); rlm@10: } rlm@10: rlm@10: static public Object third(Object x){ rlm@10: return first(next(next(x))); rlm@10: } rlm@10: rlm@10: static public Object fourth(Object x){ rlm@10: return first(next(next(next(x)))); rlm@10: } rlm@10: rlm@10: static public ISeq next(Object x){ rlm@10: if(x instanceof ISeq) rlm@10: return ((ISeq) x).next(); rlm@10: ISeq seq = seq(x); rlm@10: if(seq == null) rlm@10: return null; rlm@10: return seq.next(); rlm@10: } rlm@10: rlm@10: static public ISeq more(Object x){ rlm@10: if(x instanceof ISeq) rlm@10: return ((ISeq) x).more(); rlm@10: ISeq seq = seq(x); rlm@10: if(seq == null) rlm@10: return PersistentList.EMPTY; rlm@10: return seq.more(); rlm@10: } rlm@10: rlm@10: //static public Seqable more(Object x){ rlm@10: // Seqable ret = null; rlm@10: // if(x instanceof ISeq) rlm@10: // ret = ((ISeq) x).more(); rlm@10: // else rlm@10: // { rlm@10: // ISeq seq = seq(x); rlm@10: // if(seq == null) rlm@10: // ret = PersistentList.EMPTY; rlm@10: // else rlm@10: // ret = seq.more(); rlm@10: // } rlm@10: // if(ret == null) rlm@10: // ret = PersistentList.EMPTY; rlm@10: // return ret; rlm@10: //} rlm@10: rlm@10: static public Object peek(Object x){ rlm@10: if(x == null) rlm@10: return null; rlm@10: return ((IPersistentStack) x).peek(); rlm@10: } rlm@10: rlm@10: static public Object pop(Object x){ rlm@10: if(x == null) rlm@10: return null; rlm@10: return ((IPersistentStack) x).pop(); rlm@10: } rlm@10: rlm@10: static public Object get(Object coll, Object key){ rlm@10: if(coll instanceof ILookup) rlm@10: return ((ILookup) coll).valAt(key); rlm@10: return getFrom(coll, key); rlm@10: } rlm@10: rlm@10: static Object getFrom(Object coll, Object key){ rlm@10: if(coll == null) rlm@10: return null; rlm@10: else if(coll instanceof Map) { rlm@10: Map m = (Map) coll; rlm@10: return m.get(key); rlm@10: } rlm@10: else if(coll instanceof IPersistentSet) { rlm@10: IPersistentSet set = (IPersistentSet) coll; rlm@10: return set.get(key); rlm@10: } rlm@10: else if(key instanceof Number && (coll instanceof String || coll.getClass().isArray())) { rlm@10: int n = ((Number) key).intValue(); rlm@10: if(n >= 0 && n < count(coll)) rlm@10: return nth(coll, n); rlm@10: return null; rlm@10: } rlm@10: rlm@10: return null; rlm@10: } rlm@10: rlm@10: static public Object get(Object coll, Object key, Object notFound){ rlm@10: if(coll instanceof ILookup) rlm@10: return ((ILookup) coll).valAt(key, notFound); rlm@10: return getFrom(coll, key, notFound); rlm@10: } rlm@10: rlm@10: static Object getFrom(Object coll, Object key, Object notFound){ rlm@10: if(coll == null) rlm@10: return notFound; rlm@10: else if(coll instanceof Map) { rlm@10: Map m = (Map) coll; rlm@10: if(m.containsKey(key)) rlm@10: return m.get(key); rlm@10: return notFound; rlm@10: } rlm@10: else if(coll instanceof IPersistentSet) { rlm@10: IPersistentSet set = (IPersistentSet) coll; rlm@10: if(set.contains(key)) rlm@10: return set.get(key); rlm@10: return notFound; rlm@10: } rlm@10: else if(key instanceof Number && (coll instanceof String || coll.getClass().isArray())) { rlm@10: int n = ((Number) key).intValue(); rlm@10: return n >= 0 && n < count(coll) ? nth(coll, n) : notFound; rlm@10: } rlm@10: return notFound; rlm@10: rlm@10: } rlm@10: rlm@10: static public Associative assoc(Object coll, Object key, Object val){ rlm@10: if(coll == null) rlm@10: return new PersistentArrayMap(new Object[]{key, val}); rlm@10: return ((Associative) coll).assoc(key, val); rlm@10: } rlm@10: rlm@10: static public Object contains(Object coll, Object key){ rlm@10: if(coll == null) rlm@10: return F; rlm@10: else if(coll instanceof Associative) rlm@10: return ((Associative) coll).containsKey(key) ? T : F; rlm@10: else if(coll instanceof IPersistentSet) rlm@10: return ((IPersistentSet) coll).contains(key) ? T : F; rlm@10: else if(coll instanceof Map) { rlm@10: Map m = (Map) coll; rlm@10: return m.containsKey(key) ? T : F; rlm@10: } rlm@10: else if(key instanceof Number && (coll instanceof String || coll.getClass().isArray())) { rlm@10: int n = ((Number) key).intValue(); rlm@10: return n >= 0 && n < count(coll); rlm@10: } rlm@10: return F; rlm@10: } rlm@10: rlm@10: static public Object find(Object coll, Object key){ rlm@10: if(coll == null) rlm@10: return null; rlm@10: else if(coll instanceof Associative) rlm@10: return ((Associative) coll).entryAt(key); rlm@10: else { rlm@10: Map m = (Map) coll; rlm@10: if(m.containsKey(key)) rlm@10: return new MapEntry(key, m.get(key)); rlm@10: return null; rlm@10: } rlm@10: } rlm@10: rlm@10: //takes a seq of key,val,key,val rlm@10: rlm@10: //returns tail starting at val of matching key if found, else null rlm@10: static public ISeq findKey(Keyword key, ISeq keyvals) throws Exception{ rlm@10: while(keyvals != null) { rlm@10: ISeq r = keyvals.next(); rlm@10: if(r == null) rlm@10: throw new Exception("Malformed keyword argslist"); rlm@10: if(keyvals.first() == key) rlm@10: return r; rlm@10: keyvals = r.next(); rlm@10: } rlm@10: return null; rlm@10: } rlm@10: rlm@10: static public Object dissoc(Object coll, Object key) throws Exception{ rlm@10: if(coll == null) rlm@10: return null; rlm@10: return ((IPersistentMap) coll).without(key); rlm@10: } rlm@10: rlm@10: static public Object nth(Object coll, int n){ rlm@10: if(coll instanceof Indexed) rlm@10: return ((Indexed) coll).nth(n); rlm@10: return nthFrom(Util.ret1(coll, coll = null), n); rlm@10: } rlm@10: rlm@10: static Object nthFrom(Object coll, int n){ rlm@10: if(coll == null) rlm@10: return null; rlm@10: else if(coll instanceof CharSequence) rlm@10: return Character.valueOf(((CharSequence) coll).charAt(n)); rlm@10: else if(coll.getClass().isArray()) rlm@10: return Reflector.prepRet(Array.get(coll, n)); rlm@10: else if(coll instanceof RandomAccess) rlm@10: return ((List) coll).get(n); rlm@10: else if(coll instanceof Matcher) rlm@10: return ((Matcher) coll).group(n); rlm@10: rlm@10: else if(coll instanceof Map.Entry) { rlm@10: Map.Entry e = (Map.Entry) coll; rlm@10: if(n == 0) rlm@10: return e.getKey(); rlm@10: else if(n == 1) rlm@10: return e.getValue(); rlm@10: throw new IndexOutOfBoundsException(); rlm@10: } rlm@10: rlm@10: else if(coll instanceof Sequential) { rlm@10: ISeq seq = RT.seq(coll); rlm@10: coll = null; rlm@10: for(int i = 0; i <= n && seq != null; ++i, seq = seq.next()) { rlm@10: if(i == n) rlm@10: return seq.first(); rlm@10: } rlm@10: throw new IndexOutOfBoundsException(); rlm@10: } rlm@10: else rlm@10: throw new UnsupportedOperationException( rlm@10: "nth not supported on this type: " + coll.getClass().getSimpleName()); rlm@10: } rlm@10: rlm@10: static public Object nth(Object coll, int n, Object notFound){ rlm@10: if(coll instanceof Indexed) { rlm@10: Indexed v = (Indexed) coll; rlm@10: return v.nth(n, notFound); rlm@10: } rlm@10: return nthFrom(coll, n, notFound); rlm@10: } rlm@10: rlm@10: static Object nthFrom(Object coll, int n, Object notFound){ rlm@10: if(coll == null) rlm@10: return notFound; rlm@10: else if(n < 0) rlm@10: return notFound; rlm@10: rlm@10: else if(coll instanceof CharSequence) { rlm@10: CharSequence s = (CharSequence) coll; rlm@10: if(n < s.length()) rlm@10: return Character.valueOf(s.charAt(n)); rlm@10: return notFound; rlm@10: } rlm@10: else if(coll.getClass().isArray()) { rlm@10: if(n < Array.getLength(coll)) rlm@10: return Reflector.prepRet(Array.get(coll, n)); rlm@10: return notFound; rlm@10: } rlm@10: else if(coll instanceof RandomAccess) { rlm@10: List list = (List) coll; rlm@10: if(n < list.size()) rlm@10: return list.get(n); rlm@10: return notFound; rlm@10: } rlm@10: else if(coll instanceof Matcher) { rlm@10: Matcher m = (Matcher) coll; rlm@10: if(n < m.groupCount()) rlm@10: return m.group(n); rlm@10: return notFound; rlm@10: } rlm@10: else if(coll instanceof Map.Entry) { rlm@10: Map.Entry e = (Map.Entry) coll; rlm@10: if(n == 0) rlm@10: return e.getKey(); rlm@10: else if(n == 1) rlm@10: return e.getValue(); rlm@10: return notFound; rlm@10: } rlm@10: else if(coll instanceof Sequential) { rlm@10: ISeq seq = RT.seq(coll); rlm@10: coll = null; rlm@10: for(int i = 0; i <= n && seq != null; ++i, seq = seq.next()) { rlm@10: if(i == n) rlm@10: return seq.first(); rlm@10: } rlm@10: return notFound; rlm@10: } rlm@10: else rlm@10: throw new UnsupportedOperationException( rlm@10: "nth not supported on this type: " + coll.getClass().getSimpleName()); rlm@10: } rlm@10: rlm@10: static public Object assocN(int n, Object val, Object coll){ rlm@10: if(coll == null) rlm@10: return null; rlm@10: else if(coll instanceof IPersistentVector) rlm@10: return ((IPersistentVector) coll).assocN(n, val); rlm@10: else if(coll instanceof Object[]) { rlm@10: //hmm... this is not persistent rlm@10: Object[] array = ((Object[]) coll); rlm@10: array[n] = val; rlm@10: return array; rlm@10: } rlm@10: else rlm@10: return null; rlm@10: } rlm@10: rlm@10: static boolean hasTag(Object o, Object tag){ rlm@10: return Util.equals(tag, RT.get(RT.meta(o), TAG_KEY)); rlm@10: } rlm@10: rlm@10: /** rlm@10: * ********************* Boxing/casts ****************************** rlm@10: */ rlm@10: static public Object box(Object x){ rlm@10: return x; rlm@10: } rlm@10: rlm@10: static public Character box(char x){ rlm@10: return Character.valueOf(x); rlm@10: } rlm@10: rlm@10: static public Object box(boolean x){ rlm@10: return x ? T : F; rlm@10: } rlm@10: rlm@10: static public Object box(Boolean x){ rlm@10: return x;// ? T : null; rlm@10: } rlm@10: rlm@10: static public Number box(byte x){ rlm@10: return x;//Num.from(x); rlm@10: } rlm@10: rlm@10: static public Number box(short x){ rlm@10: return x;//Num.from(x); rlm@10: } rlm@10: rlm@10: static public Number box(int x){ rlm@10: return x;//Num.from(x); rlm@10: } rlm@10: rlm@10: static public Number box(long x){ rlm@10: return x;//Num.from(x); rlm@10: } rlm@10: rlm@10: static public Number box(float x){ rlm@10: return x;//Num.from(x); rlm@10: } rlm@10: rlm@10: static public Number box(double x){ rlm@10: return x;//Num.from(x); rlm@10: } rlm@10: rlm@10: static public char charCast(Object x){ rlm@10: if(x instanceof Character) rlm@10: return ((Character) x).charValue(); rlm@10: rlm@10: long n = ((Number) x).longValue(); rlm@10: if(n < Character.MIN_VALUE || n > Character.MAX_VALUE) rlm@10: throw new IllegalArgumentException("Value out of range for char: " + x); rlm@10: rlm@10: return (char) n; rlm@10: } rlm@10: rlm@10: static public boolean booleanCast(Object x){ rlm@10: if(x instanceof Boolean) rlm@10: return ((Boolean) x).booleanValue(); rlm@10: return x != null; rlm@10: } rlm@10: rlm@10: static public boolean booleanCast(boolean x){ rlm@10: return x; rlm@10: } rlm@10: rlm@10: static public byte byteCast(Object x){ rlm@10: long n = ((Number) x).longValue(); rlm@10: if(n < Byte.MIN_VALUE || n > Byte.MAX_VALUE) rlm@10: throw new IllegalArgumentException("Value out of range for byte: " + x); rlm@10: rlm@10: return (byte) n; rlm@10: } rlm@10: rlm@10: static public short shortCast(Object x){ rlm@10: long n = ((Number) x).longValue(); rlm@10: if(n < Short.MIN_VALUE || n > Short.MAX_VALUE) rlm@10: throw new IllegalArgumentException("Value out of range for short: " + x); rlm@10: rlm@10: return (short) n; rlm@10: } rlm@10: rlm@10: static public int intCast(Object x){ rlm@10: if(x instanceof Integer) rlm@10: return ((Integer)x).intValue(); rlm@10: if(x instanceof Number) rlm@10: return intCast(((Number) x).longValue()); rlm@10: return ((Character) x).charValue(); rlm@10: } rlm@10: rlm@10: static public int intCast(char x){ rlm@10: return x; rlm@10: } rlm@10: rlm@10: static public int intCast(byte x){ rlm@10: return x; rlm@10: } rlm@10: rlm@10: static public int intCast(short x){ rlm@10: return x; rlm@10: } rlm@10: rlm@10: static public int intCast(int x){ rlm@10: return x; rlm@10: } rlm@10: rlm@10: static public int intCast(float x){ rlm@10: if(x < Integer.MIN_VALUE || x > Integer.MAX_VALUE) rlm@10: throw new IllegalArgumentException("Value out of range for int: " + x); rlm@10: return (int) x; rlm@10: } rlm@10: rlm@10: static public int intCast(long x){ rlm@10: if(x < Integer.MIN_VALUE || x > Integer.MAX_VALUE) rlm@10: throw new IllegalArgumentException("Value out of range for int: " + x); rlm@10: return (int) x; rlm@10: } rlm@10: rlm@10: static public int intCast(double x){ rlm@10: if(x < Integer.MIN_VALUE || x > Integer.MAX_VALUE) rlm@10: throw new IllegalArgumentException("Value out of range for int: " + x); rlm@10: return (int) x; rlm@10: } rlm@10: rlm@10: static public long longCast(Object x){ rlm@10: return ((Number) x).longValue(); rlm@10: } rlm@10: rlm@10: static public long longCast(int x){ rlm@10: return x; rlm@10: } rlm@10: rlm@10: static public long longCast(float x){ rlm@10: if(x < Long.MIN_VALUE || x > Long.MAX_VALUE) rlm@10: throw new IllegalArgumentException("Value out of range for long: " + x); rlm@10: return (long) x; rlm@10: } rlm@10: rlm@10: static public long longCast(long x){ rlm@10: return x; rlm@10: } rlm@10: rlm@10: static public long longCast(double x){ rlm@10: if(x < Long.MIN_VALUE || x > Long.MAX_VALUE) rlm@10: throw new IllegalArgumentException("Value out of range for long: " + x); rlm@10: return (long) x; rlm@10: } rlm@10: rlm@10: static public float floatCast(Object x){ rlm@10: if(x instanceof Float) rlm@10: return ((Float) x).floatValue(); rlm@10: rlm@10: double n = ((Number) x).doubleValue(); rlm@10: if(n < -Float.MAX_VALUE || n > Float.MAX_VALUE) rlm@10: throw new IllegalArgumentException("Value out of range for float: " + x); rlm@10: rlm@10: return (float) n; rlm@10: rlm@10: } rlm@10: rlm@10: static public float floatCast(int x){ rlm@10: return x; rlm@10: } rlm@10: rlm@10: static public float floatCast(float x){ rlm@10: return x; rlm@10: } rlm@10: rlm@10: static public float floatCast(long x){ rlm@10: return x; rlm@10: } rlm@10: rlm@10: static public float floatCast(double x){ rlm@10: if(x < -Float.MAX_VALUE || x > Float.MAX_VALUE) rlm@10: throw new IllegalArgumentException("Value out of range for float: " + x); rlm@10: rlm@10: return (float) x; rlm@10: } rlm@10: rlm@10: static public double doubleCast(Object x){ rlm@10: return ((Number) x).doubleValue(); rlm@10: } rlm@10: rlm@10: static public double doubleCast(int x){ rlm@10: return x; rlm@10: } rlm@10: rlm@10: static public double doubleCast(float x){ rlm@10: return x; rlm@10: } rlm@10: rlm@10: static public double doubleCast(long x){ rlm@10: return x; rlm@10: } rlm@10: rlm@10: static public double doubleCast(double x){ rlm@10: return x; rlm@10: } rlm@10: rlm@10: static public IPersistentMap map(Object... init){ rlm@10: if(init == null) rlm@10: return PersistentArrayMap.EMPTY; rlm@10: else if(init.length <= PersistentArrayMap.HASHTABLE_THRESHOLD) rlm@10: return PersistentArrayMap.createWithCheck(init); rlm@10: return PersistentHashMap.createWithCheck(init); rlm@10: } rlm@10: rlm@10: static public IPersistentSet set(Object... init){ rlm@10: return PersistentHashSet.createWithCheck(init); rlm@10: } rlm@10: rlm@10: static public IPersistentVector vector(Object... init){ rlm@10: return LazilyPersistentVector.createOwning(init); rlm@10: } rlm@10: rlm@10: static public IPersistentVector subvec(IPersistentVector v, int start, int end){ rlm@10: if(end < start || start < 0 || end > v.count()) rlm@10: throw new IndexOutOfBoundsException(); rlm@10: if(start == end) rlm@10: return PersistentVector.EMPTY; rlm@10: return new APersistentVector.SubVector(null, v, start, end); rlm@10: } rlm@10: rlm@10: /** rlm@10: * **************************************** list support ******************************* rlm@10: */ rlm@10: rlm@10: rlm@10: static public ISeq list(){ rlm@10: return null; rlm@10: } rlm@10: rlm@10: static public ISeq list(Object arg1){ rlm@10: return new PersistentList(arg1); rlm@10: } rlm@10: rlm@10: static public ISeq list(Object arg1, Object arg2){ rlm@10: return listStar(arg1, arg2, null); rlm@10: } rlm@10: rlm@10: static public ISeq list(Object arg1, Object arg2, Object arg3){ rlm@10: return listStar(arg1, arg2, arg3, null); rlm@10: } rlm@10: rlm@10: static public ISeq list(Object arg1, Object arg2, Object arg3, Object arg4){ rlm@10: return listStar(arg1, arg2, arg3, arg4, null); rlm@10: } rlm@10: rlm@10: static public ISeq list(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5){ rlm@10: return listStar(arg1, arg2, arg3, arg4, arg5, null); rlm@10: } rlm@10: rlm@10: static public ISeq listStar(Object arg1, ISeq rest){ rlm@10: return (ISeq) cons(arg1, rest); rlm@10: } rlm@10: rlm@10: static public ISeq listStar(Object arg1, Object arg2, ISeq rest){ rlm@10: return (ISeq) cons(arg1, cons(arg2, rest)); rlm@10: } rlm@10: rlm@10: static public ISeq listStar(Object arg1, Object arg2, Object arg3, ISeq rest){ rlm@10: return (ISeq) cons(arg1, cons(arg2, cons(arg3, rest))); rlm@10: } rlm@10: rlm@10: static public ISeq listStar(Object arg1, Object arg2, Object arg3, Object arg4, ISeq rest){ rlm@10: return (ISeq) cons(arg1, cons(arg2, cons(arg3, cons(arg4, rest)))); rlm@10: } rlm@10: rlm@10: static public ISeq listStar(Object arg1, Object arg2, Object arg3, Object arg4, Object arg5, ISeq rest){ rlm@10: return (ISeq) cons(arg1, cons(arg2, cons(arg3, cons(arg4, cons(arg5, rest))))); rlm@10: } rlm@10: rlm@10: static public ISeq arrayToList(Object[] a) throws Exception{ rlm@10: ISeq ret = null; rlm@10: for(int i = a.length - 1; i >= 0; --i) rlm@10: ret = (ISeq) cons(a[i], ret); rlm@10: return ret; rlm@10: } rlm@10: rlm@10: static public Object[] object_array(Object sizeOrSeq){ rlm@10: if(sizeOrSeq instanceof Number) rlm@10: return new Object[((Number) sizeOrSeq).intValue()]; rlm@10: else rlm@10: { rlm@10: ISeq s = RT.seq(sizeOrSeq); rlm@10: int size = RT.count(s); rlm@10: Object[] ret = new Object[size]; rlm@10: for(int i = 0; i < size && s != null; i++, s = s.next()) rlm@10: ret[i] = s.first(); rlm@10: return ret; rlm@10: } rlm@10: } rlm@10: rlm@10: static public Object[] toArray(Object coll) throws Exception{ rlm@10: if(coll == null) rlm@10: return EMPTY_ARRAY; rlm@10: else if(coll instanceof Object[]) rlm@10: return (Object[]) coll; rlm@10: else if(coll instanceof Collection) rlm@10: return ((Collection) coll).toArray(); rlm@10: else if(coll instanceof Map) rlm@10: return ((Map) coll).entrySet().toArray(); rlm@10: else if(coll instanceof String) { rlm@10: char[] chars = ((String) coll).toCharArray(); rlm@10: Object[] ret = new Object[chars.length]; rlm@10: for(int i = 0; i < chars.length; i++) rlm@10: ret[i] = chars[i]; rlm@10: return ret; rlm@10: } rlm@10: else if(coll.getClass().isArray()) { rlm@10: ISeq s = (seq(coll)); rlm@10: Object[] ret = new Object[count(s)]; rlm@10: for(int i = 0; i < ret.length; i++, s = s.next()) rlm@10: ret[i] = s.first(); rlm@10: return ret; rlm@10: } rlm@10: else rlm@10: throw new Exception("Unable to convert: " + coll.getClass() + " to Object[]"); rlm@10: } rlm@10: rlm@10: static public Object[] seqToArray(ISeq seq){ rlm@10: int len = length(seq); rlm@10: Object[] ret = new Object[len]; rlm@10: for(int i = 0; seq != null; ++i, seq = seq.next()) rlm@10: ret[i] = seq.first(); rlm@10: return ret; rlm@10: } rlm@10: rlm@10: static public Object seqToTypedArray(ISeq seq) throws Exception{ rlm@10: Class type = (seq != null) ? seq.first().getClass() : Object.class; rlm@10: return seqToTypedArray(type, seq); rlm@10: } rlm@10: rlm@10: static public Object seqToTypedArray(Class type, ISeq seq) throws Exception{ rlm@10: Object ret = Array.newInstance(type, length(seq)); rlm@10: for(int i = 0; seq != null; ++i, seq = seq.next()) rlm@10: Array.set(ret, i, seq.first()); rlm@10: return ret; rlm@10: } rlm@10: rlm@10: static public int length(ISeq list){ rlm@10: int i = 0; rlm@10: for(ISeq c = list; c != null; c = c.next()) { rlm@10: i++; rlm@10: } rlm@10: return i; rlm@10: } rlm@10: rlm@10: static public int boundedLength(ISeq list, int limit) throws Exception{ rlm@10: int i = 0; rlm@10: for(ISeq c = list; c != null && i <= limit; c = c.next()) { rlm@10: i++; rlm@10: } rlm@10: return i; rlm@10: } rlm@10: rlm@10: ///////////////////////////////// reader support //////////////////////////////// rlm@10: rlm@10: static Character readRet(int ret){ rlm@10: if(ret == -1) rlm@10: return null; rlm@10: return box((char) ret); rlm@10: } rlm@10: rlm@10: static public Character readChar(Reader r) throws Exception{ rlm@10: int ret = r.read(); rlm@10: return readRet(ret); rlm@10: } rlm@10: rlm@10: static public Character peekChar(Reader r) throws Exception{ rlm@10: int ret; rlm@10: if(r instanceof PushbackReader) { rlm@10: ret = r.read(); rlm@10: ((PushbackReader) r).unread(ret); rlm@10: } rlm@10: else { rlm@10: r.mark(1); rlm@10: ret = r.read(); rlm@10: r.reset(); rlm@10: } rlm@10: rlm@10: return readRet(ret); rlm@10: } rlm@10: rlm@10: static public int getLineNumber(Reader r){ rlm@10: if(r instanceof LineNumberingPushbackReader) rlm@10: return ((LineNumberingPushbackReader) r).getLineNumber(); rlm@10: return 0; rlm@10: } rlm@10: rlm@10: static public LineNumberingPushbackReader getLineNumberingReader(Reader r){ rlm@10: if(isLineNumberingReader(r)) rlm@10: return (LineNumberingPushbackReader) r; rlm@10: return new LineNumberingPushbackReader(r); rlm@10: } rlm@10: rlm@10: static public boolean isLineNumberingReader(Reader r){ rlm@10: return r instanceof LineNumberingPushbackReader; rlm@10: } rlm@10: rlm@10: static public String resolveClassNameInContext(String className){ rlm@10: //todo - look up in context var rlm@10: return className; rlm@10: } rlm@10: rlm@10: static public boolean suppressRead(){ rlm@10: //todo - look up in suppress-read var rlm@10: return false; rlm@10: } rlm@10: rlm@10: static public String printString(Object x){ rlm@10: try { rlm@10: StringWriter sw = new StringWriter(); rlm@10: print(x, sw); rlm@10: return sw.toString(); rlm@10: } rlm@10: catch(Exception e) { rlm@10: throw new RuntimeException(e); rlm@10: } rlm@10: } rlm@10: rlm@10: static public Object readString(String s){ rlm@10: PushbackReader r = new PushbackReader(new StringReader(s)); rlm@10: try { rlm@10: return LispReader.read(r, true, null, false); rlm@10: } rlm@10: catch(Exception e) { rlm@10: throw new RuntimeException(e); rlm@10: } rlm@10: } rlm@10: rlm@10: static public void print(Object x, Writer w) throws Exception{ rlm@10: //call multimethod rlm@10: if(PRINT_INITIALIZED.isBound() && RT.booleanCast(PRINT_INITIALIZED.deref())) rlm@10: PR_ON.invoke(x, w); rlm@10: //* rlm@10: else { rlm@10: boolean readably = booleanCast(PRINT_READABLY.deref()); rlm@10: if(x instanceof Obj) { rlm@10: Obj o = (Obj) x; rlm@10: if(RT.count(o.meta()) > 0 && rlm@10: ((readably && booleanCast(PRINT_META.deref())) rlm@10: || booleanCast(PRINT_DUP.deref()))) { rlm@10: IPersistentMap meta = o.meta(); rlm@10: w.write("#^"); rlm@10: if(meta.count() == 1 && meta.containsKey(TAG_KEY)) rlm@10: print(meta.valAt(TAG_KEY), w); rlm@10: else rlm@10: print(meta, w); rlm@10: w.write(' '); rlm@10: } rlm@10: } rlm@10: if(x == null) rlm@10: w.write("nil"); rlm@10: else if(x instanceof ISeq || x instanceof IPersistentList) { rlm@10: w.write('('); rlm@10: printInnerSeq(seq(x), w); rlm@10: w.write(')'); rlm@10: } rlm@10: else if(x instanceof String) { rlm@10: String s = (String) x; rlm@10: if(!readably) rlm@10: w.write(s); rlm@10: else { rlm@10: w.write('"'); rlm@10: //w.write(x.toString()); rlm@10: for(int i = 0; i < s.length(); i++) { rlm@10: char c = s.charAt(i); rlm@10: switch(c) { rlm@10: case '\n': rlm@10: w.write("\\n"); rlm@10: break; rlm@10: case '\t': rlm@10: w.write("\\t"); rlm@10: break; rlm@10: case '\r': rlm@10: w.write("\\r"); rlm@10: break; rlm@10: case '"': rlm@10: w.write("\\\""); rlm@10: break; rlm@10: case '\\': rlm@10: w.write("\\\\"); rlm@10: break; rlm@10: case '\f': rlm@10: w.write("\\f"); rlm@10: break; rlm@10: case '\b': rlm@10: w.write("\\b"); rlm@10: break; rlm@10: default: rlm@10: w.write(c); rlm@10: } rlm@10: } rlm@10: w.write('"'); rlm@10: } rlm@10: } rlm@10: else if(x instanceof IPersistentMap) { rlm@10: w.write('{'); rlm@10: for(ISeq s = seq(x); s != null; s = s.next()) { rlm@10: IMapEntry e = (IMapEntry) s.first(); rlm@10: print(e.key(), w); rlm@10: w.write(' '); rlm@10: print(e.val(), w); rlm@10: if(s.next() != null) rlm@10: w.write(", "); rlm@10: } rlm@10: w.write('}'); rlm@10: } rlm@10: else if(x instanceof IPersistentVector) { rlm@10: IPersistentVector a = (IPersistentVector) x; rlm@10: w.write('['); rlm@10: for(int i = 0; i < a.count(); i++) { rlm@10: print(a.nth(i), w); rlm@10: if(i < a.count() - 1) rlm@10: w.write(' '); rlm@10: } rlm@10: w.write(']'); rlm@10: } rlm@10: else if(x instanceof IPersistentSet) { rlm@10: w.write("#{"); rlm@10: for(ISeq s = seq(x); s != null; s = s.next()) { rlm@10: print(s.first(), w); rlm@10: if(s.next() != null) rlm@10: w.write(" "); rlm@10: } rlm@10: w.write('}'); rlm@10: } rlm@10: else if(x instanceof Character) { rlm@10: char c = ((Character) x).charValue(); rlm@10: if(!readably) rlm@10: w.write(c); rlm@10: else { rlm@10: w.write('\\'); rlm@10: switch(c) { rlm@10: case '\n': rlm@10: w.write("newline"); rlm@10: break; rlm@10: case '\t': rlm@10: w.write("tab"); rlm@10: break; rlm@10: case ' ': rlm@10: w.write("space"); rlm@10: break; rlm@10: case '\b': rlm@10: w.write("backspace"); rlm@10: break; rlm@10: case '\f': rlm@10: w.write("formfeed"); rlm@10: break; rlm@10: case '\r': rlm@10: w.write("return"); rlm@10: break; rlm@10: default: rlm@10: w.write(c); rlm@10: } rlm@10: } rlm@10: } rlm@10: else if(x instanceof Class) { rlm@10: w.write("#="); rlm@10: w.write(((Class) x).getName()); rlm@10: } rlm@10: else if(x instanceof BigDecimal && readably) { rlm@10: w.write(x.toString()); rlm@10: w.write('M'); rlm@10: } rlm@10: else if(x instanceof Var) { rlm@10: Var v = (Var) x; rlm@10: w.write("#=(var " + v.ns.name + "/" + v.sym + ")"); rlm@10: } rlm@10: else if(x instanceof Pattern) { rlm@10: Pattern p = (Pattern) x; rlm@10: w.write("#\"" + p.pattern() + "\""); rlm@10: } rlm@10: else w.write(x.toString()); rlm@10: } rlm@10: //*/ rlm@10: } rlm@10: rlm@10: private static void printInnerSeq(ISeq x, Writer w) throws Exception{ rlm@10: for(ISeq s = x; s != null; s = s.next()) { rlm@10: print(s.first(), w); rlm@10: if(s.next() != null) rlm@10: w.write(' '); rlm@10: } rlm@10: } rlm@10: rlm@10: static public void formatAesthetic(Writer w, Object obj) throws IOException{ rlm@10: if(obj == null) rlm@10: w.write("null"); rlm@10: else rlm@10: w.write(obj.toString()); rlm@10: } rlm@10: rlm@10: static public void formatStandard(Writer w, Object obj) throws IOException{ rlm@10: if(obj == null) rlm@10: w.write("null"); rlm@10: else if(obj instanceof String) { rlm@10: w.write('"'); rlm@10: w.write((String) obj); rlm@10: w.write('"'); rlm@10: } rlm@10: else if(obj instanceof Character) { rlm@10: w.write('\\'); rlm@10: char c = ((Character) obj).charValue(); rlm@10: switch(c) { rlm@10: case '\n': rlm@10: w.write("newline"); rlm@10: break; rlm@10: case '\t': rlm@10: w.write("tab"); rlm@10: break; rlm@10: case ' ': rlm@10: w.write("space"); rlm@10: break; rlm@10: case '\b': rlm@10: w.write("backspace"); rlm@10: break; rlm@10: case '\f': rlm@10: w.write("formfeed"); rlm@10: break; rlm@10: default: rlm@10: w.write(c); rlm@10: } rlm@10: } rlm@10: else rlm@10: w.write(obj.toString()); rlm@10: } rlm@10: rlm@10: static public Object format(Object o, String s, Object... args) throws Exception{ rlm@10: Writer w; rlm@10: if(o == null) rlm@10: w = new StringWriter(); rlm@10: else if(Util.equals(o, T)) rlm@10: w = (Writer) OUT.deref(); rlm@10: else rlm@10: w = (Writer) o; rlm@10: doFormat(w, s, ArraySeq.create(args)); rlm@10: if(o == null) rlm@10: return w.toString(); rlm@10: return null; rlm@10: } rlm@10: rlm@10: static public ISeq doFormat(Writer w, String s, ISeq args) throws Exception{ rlm@10: for(int i = 0; i < s.length();) { rlm@10: char c = s.charAt(i++); rlm@10: switch(Character.toLowerCase(c)) { rlm@10: case '~': rlm@10: char d = s.charAt(i++); rlm@10: switch(Character.toLowerCase(d)) { rlm@10: case '%': rlm@10: w.write('\n'); rlm@10: break; rlm@10: case 't': rlm@10: w.write('\t'); rlm@10: break; rlm@10: case 'a': rlm@10: if(args == null) rlm@10: throw new IllegalArgumentException("Missing argument"); rlm@10: RT.formatAesthetic(w, RT.first(args)); rlm@10: args = RT.next(args); rlm@10: break; rlm@10: case 's': rlm@10: if(args == null) rlm@10: throw new IllegalArgumentException("Missing argument"); rlm@10: RT.formatStandard(w, RT.first(args)); rlm@10: args = RT.next(args); rlm@10: break; rlm@10: case '{': rlm@10: int j = s.indexOf("~}", i); //note - does not nest rlm@10: if(j == -1) rlm@10: throw new IllegalArgumentException("Missing ~}"); rlm@10: String subs = s.substring(i, j); rlm@10: for(ISeq sargs = RT.seq(RT.first(args)); sargs != null;) rlm@10: sargs = doFormat(w, subs, sargs); rlm@10: args = RT.next(args); rlm@10: i = j + 2; //skip ~} rlm@10: break; rlm@10: case '^': rlm@10: if(args == null) rlm@10: return null; rlm@10: break; rlm@10: case '~': rlm@10: w.write('~'); rlm@10: break; rlm@10: default: rlm@10: throw new IllegalArgumentException("Unsupported ~ directive: " + d); rlm@10: } rlm@10: break; rlm@10: default: rlm@10: w.write(c); rlm@10: } rlm@10: } rlm@10: return args; rlm@10: } rlm@10: ///////////////////////////////// values ////////////////////////// rlm@10: rlm@10: static public Object[] setValues(Object... vals){ rlm@10: //ThreadLocalData.setValues(vals); rlm@10: if(vals.length > 0) rlm@10: return vals;//[0]; rlm@10: return null; rlm@10: } rlm@10: rlm@10: rlm@10: static public ClassLoader makeClassLoader(){ rlm@10: return (ClassLoader) AccessController.doPrivileged(new PrivilegedAction(){ rlm@10: public Object run(){ rlm@10: try{ rlm@10: Var.pushThreadBindings(RT.map(USE_CONTEXT_CLASSLOADER, RT.T)); rlm@10: // getRootClassLoader(); rlm@10: return new DynamicClassLoader(baseLoader()); rlm@10: } rlm@10: finally{ rlm@10: Var.popThreadBindings(); rlm@10: } rlm@10: } rlm@10: }); rlm@10: } rlm@10: rlm@10: static public ClassLoader baseLoader(){ rlm@10: if(Compiler.LOADER.isBound()) rlm@10: return (ClassLoader) Compiler.LOADER.deref(); rlm@10: else if(booleanCast(USE_CONTEXT_CLASSLOADER.deref())) rlm@10: return Thread.currentThread().getContextClassLoader(); rlm@10: return Compiler.class.getClassLoader(); rlm@10: } rlm@10: rlm@10: static public Class classForName(String name) throws ClassNotFoundException{ rlm@10: rlm@10: return Class.forName(name, true, baseLoader()); rlm@10: } rlm@10: rlm@10: static public Class loadClassForName(String name) throws ClassNotFoundException{ rlm@10: try rlm@10: { rlm@10: Class.forName(name, false, baseLoader()); rlm@10: } rlm@10: catch(ClassNotFoundException e) rlm@10: { rlm@10: return null; rlm@10: } rlm@10: return Class.forName(name, true, baseLoader()); rlm@10: } rlm@10: rlm@10: static public float aget(float[] xs, int i){ rlm@10: return xs[i]; rlm@10: } rlm@10: rlm@10: static public float aset(float[] xs, int i, float v){ rlm@10: xs[i] = v; rlm@10: return v; rlm@10: } rlm@10: rlm@10: static public int alength(float[] xs){ rlm@10: return xs.length; rlm@10: } rlm@10: rlm@10: static public float[] aclone(float[] xs){ rlm@10: return xs.clone(); rlm@10: } rlm@10: rlm@10: static public double aget(double[] xs, int i){ rlm@10: return xs[i]; rlm@10: } rlm@10: rlm@10: static public double aset(double[] xs, int i, double v){ rlm@10: xs[i] = v; rlm@10: return v; rlm@10: } rlm@10: rlm@10: static public int alength(double[] xs){ rlm@10: return xs.length; rlm@10: } rlm@10: rlm@10: static public double[] aclone(double[] xs){ rlm@10: return xs.clone(); rlm@10: } rlm@10: rlm@10: static public int aget(int[] xs, int i){ rlm@10: return xs[i]; rlm@10: } rlm@10: rlm@10: static public int aset(int[] xs, int i, int v){ rlm@10: xs[i] = v; rlm@10: return v; rlm@10: } rlm@10: rlm@10: static public int alength(int[] xs){ rlm@10: return xs.length; rlm@10: } rlm@10: rlm@10: static public int[] aclone(int[] xs){ rlm@10: return xs.clone(); rlm@10: } rlm@10: rlm@10: static public long aget(long[] xs, int i){ rlm@10: return xs[i]; rlm@10: } rlm@10: rlm@10: static public long aset(long[] xs, int i, long v){ rlm@10: xs[i] = v; rlm@10: return v; rlm@10: } rlm@10: rlm@10: static public int alength(long[] xs){ rlm@10: return xs.length; rlm@10: } rlm@10: rlm@10: static public long[] aclone(long[] xs){ rlm@10: return xs.clone(); rlm@10: } rlm@10: rlm@10: static public char aget(char[] xs, int i){ rlm@10: return xs[i]; rlm@10: } rlm@10: rlm@10: static public char aset(char[] xs, int i, char v){ rlm@10: xs[i] = v; rlm@10: return v; rlm@10: } rlm@10: rlm@10: static public int alength(char[] xs){ rlm@10: return xs.length; rlm@10: } rlm@10: rlm@10: static public char[] aclone(char[] xs){ rlm@10: return xs.clone(); rlm@10: } rlm@10: rlm@10: static public byte aget(byte[] xs, int i){ rlm@10: return xs[i]; rlm@10: } rlm@10: rlm@10: static public byte aset(byte[] xs, int i, byte v){ rlm@10: xs[i] = v; rlm@10: return v; rlm@10: } rlm@10: rlm@10: static public int alength(byte[] xs){ rlm@10: return xs.length; rlm@10: } rlm@10: rlm@10: static public byte[] aclone(byte[] xs){ rlm@10: return xs.clone(); rlm@10: } rlm@10: rlm@10: static public short aget(short[] xs, int i){ rlm@10: return xs[i]; rlm@10: } rlm@10: rlm@10: static public short aset(short[] xs, int i, short v){ rlm@10: xs[i] = v; rlm@10: return v; rlm@10: } rlm@10: rlm@10: static public int alength(short[] xs){ rlm@10: return xs.length; rlm@10: } rlm@10: rlm@10: static public short[] aclone(short[] xs){ rlm@10: return xs.clone(); rlm@10: } rlm@10: rlm@10: static public boolean aget(boolean[] xs, int i){ rlm@10: return xs[i]; rlm@10: } rlm@10: rlm@10: static public boolean aset(boolean[] xs, int i, boolean v){ rlm@10: xs[i] = v; rlm@10: return v; rlm@10: } rlm@10: rlm@10: static public int alength(boolean[] xs){ rlm@10: return xs.length; rlm@10: } rlm@10: rlm@10: static public boolean[] aclone(boolean[] xs){ rlm@10: return xs.clone(); rlm@10: } rlm@10: rlm@10: static public Object aget(Object[] xs, int i){ rlm@10: return xs[i]; rlm@10: } rlm@10: rlm@10: static public Object aset(Object[] xs, int i, Object v){ rlm@10: xs[i] = v; rlm@10: return v; rlm@10: } rlm@10: rlm@10: static public int alength(Object[] xs){ rlm@10: return xs.length; rlm@10: } rlm@10: rlm@10: static public Object[] aclone(Object[] xs){ rlm@10: return xs.clone(); rlm@10: } rlm@10: rlm@10: rlm@10: }