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