summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2008-11-10 23:43:53 +0000
committerRich Hickey <richhickey@gmail.com>2008-11-10 23:43:53 +0000
commit240969a3af34ff0661238d03c006cc5a74dc1698 (patch)
treeeec677998e7aa5697ea87e8fb41fb8b3efa9a880 /src
parent22a2d9080da1ab1761306f0171d85c5464d82096 (diff)
Interim checkin - DO NOT USE!!
Unless you are interested in helping test: AOT compiler! build and start Clojure with: -cp ./classes:./src/clj:clojure.jar try: (do (compile 'clojure.core) (compile 'clojure.set) (compile 'clojure.xml) (compile 'clojure.zip)) restart Clojure - faster? rebuild Clojure w/o clean, should get faster start from jar alone deleted set/xml etc dirs Moved clojure ns to clojure.core, moved set/xml etc up out of dirs New binding syntax (breaking change) for: doseq dotimes with-open when-first if-let when-let plus: new print-dup functionality for replica generation of compilation constants new *print-dup* flag, prints duplicators back to simplified readably printing for repl readable fns, as long as they are not closures
Diffstat (limited to 'src')
-rw-r--r--src/clj/clojure/core.clj315
-rw-r--r--src/clj/clojure/inspector.clj4
-rw-r--r--src/jvm/clojure/lang/Compiler.java211
-rw-r--r--src/jvm/clojure/lang/LispReader.java3
-rw-r--r--src/jvm/clojure/lang/RT.java90
-rw-r--r--src/jvm/clojure/lang/Repl.java2
6 files changed, 471 insertions, 154 deletions
diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj
index 1d81d4f1..1c46d70c 100644
--- a/src/clj/clojure/core.clj
+++ b/src/clj/clojure/core.clj
@@ -3478,6 +3478,15 @@
#^{:doc "bound in a repl thread to the most recent exception caught by the repl"}
*e)
+(defmacro declare
+ "defs the supplied var names with no bindings, useful for making forward declarations."
+ [& names] `(do ~@(map #(list 'def %) names)))
+
+(defn compile [libsym]
+ (clojure.lang.RT/compileLib (str libsym)))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; printing ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
(import '(java.io Writer))
(def
@@ -3598,7 +3607,9 @@
(defmethod print-method clojure.lang.ISeq [o, #^Writer w]
(print-meta o w)
- (print-sequential "(" print-method " " ")" o w))
+ (print-sequential "(" pr-on " " ")" o w))
+
+(defmethod print-dup clojure.lang.ISeq [o w] (print-method o w))
(defmethod print-method clojure.lang.IPersistentList [o, #^Writer w]
(print-meta o w)
@@ -3783,7 +3794,303 @@
(def #^{:private true} print-initialized true)
-(defmacro declare
- "defs the supplied var names with no bindings, useful for making forward declarations."
- [& names] `(do ~@(map #(list 'def %) names)))
+;;;;;;;;;;;;;;;;;;;;;;;;;;;; proxy ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(import
+ '(clojure.asm ClassWriter ClassVisitor Opcodes Type)
+ '(java.lang.reflect Modifier Constructor)
+ '(clojure.asm.commons Method GeneratorAdapter)
+ '(clojure.lang IProxy Reflector DynamicClassLoader IPersistentMap PersistentHashMap RT))
+
+(def *proxy-classes* (ref {}))
+
+(defn method-sig [#^java.lang.reflect.Method meth]
+ [(. meth (getName)) (seq (. meth (getParameterTypes))) (. meth getReturnType)])
+
+(defn get-proxy-class
+ "Takes an optional single class followed by zero or more
+ interfaces. If not supplied class defaults to Object. Creates an
+ returns an instance of a proxy class derived from the supplied
+ classes. The resulting value is cached and used for any subsequent
+ requests for the same class set. Returns a Class object."
+ [& bases]
+ (let [bases (if (. (first bases) (isInterface))
+ (cons Object bases)
+ bases)
+ [super & interfaces] bases]
+ (or (get @*proxy-classes* bases)
+ (let [cv (new ClassWriter (. ClassWriter COMPUTE_MAXS))
+ cname (str "clojure/lang/" (gensym "Proxy__"))
+ ctype (. Type (getObjectType cname))
+ iname (fn [c] (.. Type (getType c) (getInternalName)))
+ fmap "__clojureFnMap"
+ totype (fn [c] (. Type (getType c)))
+ to-types (fn [cs] (if (pos? (count cs))
+ (into-array (map totype cs))
+ (make-array Type 0)))
+ super-type (totype super)
+ map-type (totype PersistentHashMap)
+ ifn-type (totype clojure.lang.IFn)
+ obj-type (totype Object)
+ sym-type (totype clojure.lang.Symbol)
+ rt-type (totype clojure.lang.RT)
+ ex-type (totype java.lang.UnsupportedOperationException)
+ gen-method
+ (fn [#^java.lang.reflect.Method meth else-gen]
+ (let [pclasses (. meth (getParameterTypes))
+ ptypes (to-types pclasses)
+ rtype (totype (. meth (getReturnType)))
+ m (new Method (. meth (getName)) rtype ptypes)
+ gen (new GeneratorAdapter (. Opcodes ACC_PUBLIC) m nil nil cv)
+ else-label (. gen (newLabel))
+ end-label (. gen (newLabel))
+ decl-type (. Type (getType (. meth (getDeclaringClass))))]
+ (. gen (visitCode))
+ (. gen (loadThis))
+ (. gen (getField ctype fmap map-type))
+ ;get symbol corresponding to name
+ (. gen (push (. meth (getName))))
+ (. gen (invokeStatic sym-type (. Method (getMethod "clojure.lang.Symbol create(String)"))))
+ ;lookup fn in map
+ (. gen (invokeStatic rt-type (. Method (getMethod "Object get(Object, Object)"))))
+ (. gen (dup))
+ (. gen (ifNull else-label))
+ ;if found
+ (. gen (loadThis))
+ ;box args
+ (dotimes [i (count ptypes)]
+ (. gen (loadArg i))
+ (. clojure.lang.Compiler$HostExpr (emitBoxReturn nil gen (nth pclasses i))))
+ ;call fn
+ (. gen (invokeInterface ifn-type (new Method "invoke" obj-type
+ (into-array (cons obj-type
+ (replicate (count ptypes) obj-type))))))
+ ;unbox return
+ (. gen (unbox rtype))
+ (when (= (. rtype (getSort)) (. Type VOID))
+ (. gen (pop)))
+ (. gen (goTo end-label))
+
+ ;else call supplied alternative generator
+ (. gen (mark else-label))
+ (. gen (pop))
+
+ (else-gen gen m)
+
+ (. gen (mark end-label))
+ (. gen (returnValue))
+ (. gen (endMethod))))]
+
+ ;start class definition
+ (. cv (visit (. Opcodes V1_5) (+ (. Opcodes ACC_PUBLIC) (. Opcodes ACC_SUPER))
+ cname nil (iname super)
+ (into-array (map iname (cons IProxy interfaces)))))
+ ;add field for fn mappings
+ (. cv (visitField (+ (. Opcodes ACC_PRIVATE) (. Opcodes ACC_VOLATILE))
+ fmap (. map-type (getDescriptor)) nil nil))
+ ;add ctors matching/calling super's
+ (doseq [#^Constructor ctor (. super (getDeclaredConstructors))]
+ (when-not (. Modifier (isPrivate (. ctor (getModifiers))))
+ (let [ptypes (to-types (. ctor (getParameterTypes)))
+ m (new Method "<init>" (. Type VOID_TYPE) ptypes)
+ gen (new GeneratorAdapter (. Opcodes ACC_PUBLIC) m nil nil cv)]
+ (. gen (visitCode))
+ ;call super ctor
+ (. gen (loadThis))
+ (. gen (dup))
+ (. gen (loadArgs))
+ (. gen (invokeConstructor super-type m))
+ ;init fmap
+ (. gen (getStatic map-type "EMPTY" map-type))
+ (. gen (putField ctype fmap map-type))
+
+ (. gen (returnValue))
+ (. gen (endMethod)))))
+ ;add IProxy methods
+ (let [m (. Method (getMethod "void __updateClojureFnMappings(clojure.lang.IPersistentMap)"))
+ gen (new GeneratorAdapter (. Opcodes ACC_PUBLIC) m nil nil cv)]
+ (. gen (visitCode))
+ (. gen (loadThis))
+ (. gen (dup))
+ (. gen (getField ctype fmap map-type))
+ (. gen (loadArgs))
+ (. gen (invokeInterface (totype clojure.lang.IPersistentCollection)
+ (. Method (getMethod "clojure.lang.IPersistentCollection cons(Object)"))))
+ (. gen (checkCast map-type))
+ (. gen (putField ctype fmap map-type))
+
+ (. gen (returnValue))
+ (. gen (endMethod)))
+ (let [m (. Method (getMethod "clojure.lang.IPersistentMap __getClojureFnMappings()"))
+ gen (new GeneratorAdapter (. Opcodes ACC_PUBLIC) m nil nil cv)]
+ (. gen (visitCode))
+ (. gen (loadThis))
+ (. gen (getField ctype fmap map-type))
+ (. gen (returnValue))
+ (. gen (endMethod)))
+
+ ;calc set of supers' non-private instance methods
+ (let [mm (loop [mm {} considered #{} c super]
+ (if c
+ (let [[mm considered]
+ (loop [mm mm
+ considered considered
+ meths (concat
+ (seq (. c (getDeclaredMethods)))
+ (seq (. c (getMethods))))]
+ (if meths
+ (let [#^java.lang.reflect.Method meth (first meths)
+ mods (. meth (getModifiers))
+ mk (method-sig meth)]
+ (if (or (considered mk)
+ (. Modifier (isPrivate mods))
+ (. Modifier (isStatic mods))
+ (. Modifier (isFinal mods))
+ (= "finalize" (.getName meth)))
+ (recur mm (conj considered mk) (rest meths))
+ (recur (assoc mm mk meth) (conj considered mk) (rest meths))))
+ [mm considered]))]
+ (recur mm considered (. c (getSuperclass))))
+ mm))]
+ ;add methods matching supers', if no mapping -> call super
+ (doseq [#^java.lang.reflect.Method meth (vals mm)]
+ (gen-method meth
+ (fn [gen m]
+ (. gen (loadThis))
+ ;push args
+ (. gen (loadArgs))
+ ;call super
+ (. gen (visitMethodInsn (. Opcodes INVOKESPECIAL)
+ (. super-type (getInternalName))
+ (. m (getName))
+ (. m (getDescriptor)))))))
+
+ ;add methods matching interfaces', if no mapping -> throw
+ (doseq [#^Class iface interfaces]
+ (doseq [#^java.lang.reflect.Method meth (. iface (getMethods))]
+ (when-not (contains? mm (method-sig meth))
+ (gen-method meth
+ (fn [gen m]
+ (. gen (throwException ex-type (. m (getName))))))))))
+
+ ;finish class def
+ (. cv (visitEnd))
+ ;generate, cache and return class object
+ (let [loader (. RT ROOT_CLASSLOADER)
+ c (. loader (defineClass (. cname (replace "/" "."))
+ (. cv (toByteArray))))]
+ (sync nil (commute *proxy-classes* assoc bases c))
+ c)))))
+
+(defn construct-proxy
+ "Takes a proxy class and any arguments for its superclass ctor and
+ creates and returns an instance of the proxy."
+ [c & ctor-args]
+ (. Reflector (invokeConstructor c (to-array ctor-args))))
+
+(defn update-proxy
+ "Takes a proxy instance and a map of symbols (whose names must
+ correspond to methods of the proxy superclass/superinterfaces) to
+ fns (which must take arguments matching the corresponding method,
+ plus an additional (explicit) first arg corresponding to this, and
+ updates (via assoc) the proxy's fn map. nil can be passed instead of
+ a fn, in which case the corresponding method will revert to the
+ default behavior. Note that this function can be used to update the
+ behavior of an existing instance without changing its identity."
+ [#^IProxy proxy mappings]
+ (. proxy (__updateClojureFnMappings mappings)))
+
+(defn proxy-mappings
+ "Takes a proxy instance and returns the proxy's fn map."
+ [#^IProxy proxy]
+ (. proxy (__getClojureFnMappings)))
+
+(defmacro proxy
+ "class-and-interfaces - a vector of class names
+
+ args - a (possibly empty) vector of arguments to the superclass
+ constructor.
+
+ f => (name [params*] body) or
+ (name ([params*] body) ([params+] body) ...)
+
+ Expands to code which creates a instance of a proxy class that
+ implements the named class/interface(s) by calling the supplied
+ fns. A single class, if provided, must be first. If not provided it
+ defaults to Object.
+
+ The interfaces names must be valid interface types. If a method fn
+ is not provided for a class method, the superclass methd will be
+ called. If a method fn is not provided for an interface method, an
+ UnsupportedOperationException will be thrown should it be
+ called. Method fns are closures and can capture the environment in
+ which proxy is called. Each method fn takes an additional implicit
+ first arg, which is bound to 'this. Note that while method fns can
+ be provided to override protected methods, they have no other access
+ to protected members, nor to super, as these capabilities cannot be
+ proxied."
+ [class-and-interfaces args & fs]
+ `(let [pc# (get-proxy-class ~@class-and-interfaces)
+ p# (construct-proxy pc# ~@args)]
+ (update-proxy p#
+ ~(loop [fmap {} fs fs]
+ (if fs
+ (let [[sym & meths] (first fs)
+ meths (if (vector? (first meths))
+ (list meths)
+ meths)
+ meths (map (fn [[params & body]]
+ (cons (apply vector 'this params) body))
+ meths)]
+ (recur (assoc fmap (list `quote (symbol (name sym))) (cons `fn meths)) (rest fs)))
+ fmap)))
+ p#))
+
+(defn proxy-call-with-super [call this meth]
+ (let [m (proxy-mappings this)]
+ (update-proxy this (assoc m meth nil))
+ (let [ret (call)]
+ (update-proxy this m)
+ ret)))
+
+(defmacro proxy-super
+ "Use to call a superclass method in the body of a proxy method.
+ Note, expansion captures 'this"
+ [meth & args]
+ `(proxy-call-with-super (fn [] (. ~'this ~meth ~@args)) ~'this '~(symbol (name meth))))
+
+(defn bean
+ "Takes a Java object and returns a read-only implementation of the
+ map abstraction based upon its JavaBean properties."
+ [#^Object x]
+ (let [c (. x (getClass))
+ pmap (reduce (fn [m #^java.beans.PropertyDescriptor pd]
+ (let [name (. pd (getName))
+ method (. pd (getReadMethod))]
+ (if (and method (zero? (alength (. method (getParameterTypes)))))
+ (assoc m (keyword name) (fn [] (. method (invoke x nil))))
+ m)))
+ {}
+ (seq (.. java.beans.Introspector
+ (getBeanInfo c)
+ (getPropertyDescriptors))))
+ v (fn [k] ((pmap k)))
+ snapshot (fn []
+ (reduce (fn [m e]
+ (assoc m (key e) ((val e))))
+ {} (seq pmap)))]
+ (proxy [clojure.lang.APersistentMap]
+ []
+ (containsKey [k] (contains? pmap k))
+ (entryAt [k] (when (contains? pmap k) (new clojure.lang.MapEntry k (v k))))
+ (valAt ([k] (v k))
+ ([k default] (if (contains? pmap k) (v k) default)))
+ (cons [m] (conj (snapshot) m))
+ (count [] (count pmap))
+ (assoc [k v] (assoc (snapshot) k v))
+ (without [k] (dissoc (snapshot) k))
+ (seq [] ((fn thisfn [pseq]
+ (when pseq
+ (lazy-cons (new clojure.lang.MapEntry (first pseq) (v (first pseq)))
+ (thisfn (rest pseq))))) (keys pmap))))))
diff --git a/src/clj/clojure/inspector.clj b/src/clj/clojure/inspector.clj
index f60f6561..820cd33e 100644
--- a/src/clj/clojure/inspector.clj
+++ b/src/clj/clojure/inspector.clj
@@ -140,8 +140,8 @@
(class x)
x))))
-(defn make-inspector [x]
- (agent {:frame frame :data x :parent nil :index 0}))
+;(defn make-inspector [x]
+; (agent {:frame frame :data x :parent nil :index 0}))
(defn inspect
diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java
index ace59409..de686e7a 100644
--- a/src/jvm/clojure/lang/Compiler.java
+++ b/src/jvm/clojure/lang/Compiler.java
@@ -180,6 +180,13 @@ static final public Var SOURCE = Var.create("NO_SOURCE_FILE");
static final public Var SOURCE_PATH = Var.intern(Namespace.findOrCreate(Symbol.create("clojure.core")),
Symbol.create("*file*"), null);
+//String
+static final public Var COMPILE_PATH = Var.intern(Namespace.findOrCreate(Symbol.create("clojure.core")),
+ Symbol.create("*compile-path*"), null);
+//boolean
+static final public Var COMPILE_FILES = Var.intern(Namespace.findOrCreate(Symbol.create("clojure.core")),
+ Symbol.create("*compile-files*"), RT.F);
+
//Integer
static final public Var LINE = Var.create(0);
@@ -2970,7 +2977,7 @@ static public class FnExpr implements Expr{
return ret;
}
- private void compile() throws IOException{
+ private void compile() throws Exception{
//create bytecode for a class
//with name current_ns.defname[$letname]+
//anonymous fns get names fn__id
@@ -3035,57 +3042,9 @@ static public class FnExpr implements Expr{
if(constants.count() > 0)
{
-
-// clinitgen.mark(begin);
-// clinitgen.visitLdcInsn(fntype);
-// clinitgen.invokeVirtual(CLASS_TYPE, getClassLoaderMethod);
-// clinitgen.checkCast(DYNAMIC_CLASSLOADER_TYPE);
-// clinitgen.push(constantsID);
-// clinitgen.invokeVirtual(DYNAMIC_CLASSLOADER_TYPE, getConstantsMethod);
- try{
- Var.pushThreadBindings(RT.map(RT.PRINT_DUP, RT.T));
-
- for(int i = 0; i < constants.count(); i++)
- {
- String cs = RT.printString(constants.nth(i));
- if(cs.length() == 0)
- throw new RuntimeException("Can't embed unreadable object in code: " + constants.nth(i));
-
- if(cs.startsWith("#<"))
- throw new RuntimeException("Can't embed unreadable object in code: " + cs);
- clinitgen.push(cs);
- clinitgen.invokeStatic(RT_TYPE, readStringMethod);
-// clinitgen.dup();
-// clinitgen.push(i);
-// clinitgen.arrayLoad(OBJECT_TYPE);
- clinitgen.checkCast(constantType(i));
- clinitgen.putStatic(fntype, constantName(i), constantType(i));
- }
+ emitConstants(clinitgen);
}
- finally{
- Var.popThreadBindings();
- }
- }
-// for(ISeq s = RT.keys(keywords); s != null; s = s.rest())
-// {
-// Keyword k = (Keyword) s.first();
-// clinitgen.push(k.sym.ns);
-// clinitgen.push(k.sym.name);
-// clinitgen.invokeStatic(KEYWORD_TYPE, kwintern);
-// clinitgen.putStatic(fntype, munge(k.sym.toString()), KEYWORD_TYPE);
-// }
-// for(ISeq s = RT.keys(vars); s != null; s = s.rest())
-// {
-// Var v = (Var) s.first();
-// clinitgen.push(v.ns.name.name);
-// clinitgen.invokeStatic(SYMBOL_TYPE, symcreate);
-// clinitgen.push(v.sym.name);
-// clinitgen.invokeStatic(SYMBOL_TYPE, symcreate);
-// clinitgen.invokeStatic(VAR_TYPE, varintern);
-// clinitgen.putStatic(fntype, munge(v.sym.toString()), VAR_TYPE);
-// }
-// clinitgen.mark(end);
-// clinitgen.visitLocalVariable("constants", "[Ljava/lang/Object;", null, begin, end, 0);
+
clinitgen.returnValue();
clinitgen.endMethod();
@@ -3170,29 +3129,47 @@ static public class FnExpr implements Expr{
//end of class
cv.visitEnd();
- loader = (DynamicClassLoader) LOADER.get();
bytecode = cw.toByteArray();
- String path = "gen" + File.separator + internalName + ".class";
- File cf = new File(path);
- cf.getParentFile().mkdirs();
- cf.createNewFile();
- OutputStream cfs = new FileOutputStream(cf);
- try
- {
- cfs.write(bytecode);
- }
- finally
+ if(RT.booleanCast(COMPILE_FILES.get()))
+ writeClassFile(internalName,bytecode);
+ else
+ getCompiledClass();
+ }
+
+
+ void emitConstants(GeneratorAdapter clinitgen){
+ try{
+ Var.pushThreadBindings(RT.map(RT.PRINT_DUP, RT.T));
+
+ for(int i = 0; i < constants.count(); i++)
{
- cfs.close();
+ String cs = RT.printString(constants.nth(i));
+ if(cs.length() == 0)
+ throw new RuntimeException("Can't embed unreadable object in code: " + constants.nth(i));
+
+ if(cs.startsWith("#<"))
+ throw new RuntimeException("Can't embed unreadable object in code: " + cs);
+ clinitgen.push(cs);
+ clinitgen.invokeStatic(RT_TYPE, readStringMethod);
+// clinitgen.dup();
+// clinitgen.push(i);
+// clinitgen.arrayLoad(OBJECT_TYPE);
+ clinitgen.checkCast(constantType(i));
+ clinitgen.putStatic(fntype, constantName(i), constantType(i));
}
+ }
+ finally{
+ Var.popThreadBindings();
+ }
}
synchronized Class getCompiledClass(){
if(compiledClass == null)
try
{
- compiledClass = RT.classForName(name);//loader.defineClass(name, bytecode);
- //compiledClass = loader.defineClass(name, bytecode);
+ //compiledClass = RT.classForName(name);//loader.defineClass(name, bytecode);
+ loader = (DynamicClassLoader) LOADER.get();
+ compiledClass = loader.defineClass(name, bytecode);
}
catch(Exception e)
{
@@ -3206,7 +3183,6 @@ static public class FnExpr implements Expr{
}
public void emit(C context, FnExpr fn, GeneratorAdapter gen){
- //getCompiledClass();
//emitting a Fn means constructing an instance, feeding closed-overs from enclosing scope, if any
//fn arg is enclosing fn, not this
gen.newInstance(fntype);
@@ -4459,7 +4435,29 @@ public static Object load(Reader rdr, String sourcePath, String sourceName) thro
return ret;
}
+static public void writeClassFile(String internalName, byte[] bytecode) throws Exception{
+ String genPath = (String) COMPILE_PATH.get();
+ if(genPath == null)
+ throw new Exception("*compile-path* not set");
+ String path = genPath + File.separator + internalName + ".class";
+ File cf = new File(path);
+ cf.getParentFile().mkdirs();
+ cf.createNewFile();
+ OutputStream cfs = new FileOutputStream(cf);
+ try
+ {
+ cfs.write(bytecode);
+ }
+ finally
+ {
+ cfs.close();
+ }
+}
+
public static Object compile(Reader rdr, String sourcePath, String sourceName) throws Exception{
+ if(COMPILE_PATH.get() == null)
+ throw new Exception("*compile-path* not set");
+
Object EOF = new Object();
Object ret = null;
LineNumberingPushbackReader pushbackReader =
@@ -4473,7 +4471,8 @@ public static Object compile(Reader rdr, String sourcePath, String sourceName) t
LINE_AFTER, pushbackReader.getLineNumber(),
CONSTANTS, PersistentVector.EMPTY,
KEYWORDS, PersistentHashMap.EMPTY,
- VARS, PersistentHashMap.EMPTY
+ VARS, PersistentHashMap.EMPTY,
+ COMPILE_FILES, RT.T
));
try
@@ -4484,7 +4483,7 @@ public static Object compile(Reader rdr, String sourcePath, String sourceName) t
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
ClassVisitor cv = cw;
cv.visit(V1_5, ACC_PUBLIC + ACC_SUPER, fn.internalName, null,
- "java.lang.Object", null);
+ "java/lang/Object", null);
//static load method
GeneratorAdapter gen = new GeneratorAdapter(ACC_PUBLIC + ACC_STATIC,
@@ -4526,13 +4525,7 @@ public static Object compile(Reader rdr, String sourcePath, String sourceName) t
clinitgen.visitCode();
if(fn.constants.count() > 0)
{
- for(int i = 0; i < fn.constants.count(); i++)
- {
- clinitgen.push(RT.printString(fn.constants.nth(i)));
- clinitgen.invokeStatic(RT_TYPE, FnExpr.readStringMethod);
- clinitgen.checkCast(fn.constantType(i));
- clinitgen.putStatic(fn.fntype, fn.constantName(i), fn.constantType(i));
- }
+ fn.emitConstants(clinitgen);
}
//end of static init
clinitgen.returnValue();
@@ -4540,6 +4533,8 @@ public static Object compile(Reader rdr, String sourcePath, String sourceName) t
//end of class
cv.visitEnd();
+
+ writeClassFile(fn.internalName,cw.toByteArray());
}
catch(LispReader.ReaderException e)
{
@@ -4552,70 +4547,4 @@ public static Object compile(Reader rdr, String sourcePath, String sourceName) t
return ret;
}
-/*
-public static void main(String[] args) throws Exception{
- RT.init();
- for(String file : args)
- try
- {
- loadFile(file);
- }
- catch(Exception e)
- {
- e.printStackTrace();
- }
-
- //repl
- LineNumberingPushbackReader rdr = (LineNumberingPushbackReader) RT.IN.get();
- OutputStreamWriter w = (OutputStreamWriter) RT.OUT.get();//new OutputStreamWriter(System.out);
-
- Object EOF = new Object();
- try
- {
- Var.pushThreadBindings(
- RT.map(
-// RT.NS_REFERS, RT.NS_REFERS.get(),
-// RT.NS_IMPORTS, RT.NS_IMPORTS.get(),
-RT.CURRENT_NS, RT.CURRENT_NS.get(),
-SOURCE, "REPL"
- ));
- w.write("Clojure\n");
- RT.inNamespace.invoke(Symbol.create("user"));
-
- for(; ;)
- {
- try
- {
- Var.pushThreadBindings(
- RT.map(LOADER, RT.makeClassLoader()));
- w.write(currentNS().name + "=> ");
- w.flush();
- Object r = LispReader.read(rdr, false, EOF, false);
- if(r == EOF)
- break;
- Object ret = eval(r);
- RT.print(ret, w);
- w.write('\n');
- //w.flush();
- }
- catch(Throwable e)
- {
- e.printStackTrace();
- }
- finally
- {
- Var.popThreadBindings();
- }
- }
- }
- catch(Exception e)
- {
- e.printStackTrace();
- }
- finally
- {
- Var.popThreadBindings();
- }
-}
-*/
}
diff --git a/src/jvm/clojure/lang/LispReader.java b/src/jvm/clojure/lang/LispReader.java
index 4847692d..c5a5c99c 100644
--- a/src/jvm/clojure/lang/LispReader.java
+++ b/src/jvm/clojure/lang/LispReader.java
@@ -888,7 +888,8 @@ static class EvalReader extends AFn{
Symbol fs = (Symbol) RT.first(o);
if(fs.equals(THE_VAR))
{
- return Compiler.resolve((Symbol) RT.second(o),true);
+ Symbol vs = (Symbol) RT.second(o);
+ return RT.var(vs.ns, vs.name); //Compiler.resolve((Symbol) RT.second(o),true);
}
if(fs.name.endsWith("."))
{
diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java
index 741dba22..048aaf43 100644
--- a/src/jvm/clojure/lang/RT.java
+++ b/src/jvm/clojure/lang/RT.java
@@ -15,6 +15,9 @@ package clojure.lang;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.Callable;
import java.util.*;
+import java.util.zip.ZipEntry;
+import java.util.jar.JarFile;
+import java.util.jar.JarEntry;
import java.util.regex.Matcher;
import java.io.*;
import java.lang.reflect.Array;
@@ -23,6 +26,8 @@ import java.math.BigInteger;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.net.URL;
+import java.net.URLConnection;
+import java.net.JarURLConnection;
import java.nio.charset.Charset;
public class RT{
@@ -376,13 +381,86 @@ static public void init() throws Exception{
((PrintWriter)RT.ERR.get()).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
+ {
+ File f = new File(url.toURI());
+ return f.lastModified();
+ }
+}
+static public void loadLib(String lib) throws Exception{
+ loadLib(lib, true);
+}
+
+static public void compileLib(String lib) throws Exception{
+ String libpath = lib.replace('.', '/');
+ String cljfile = libpath + ".clj";
+ InputStream ins = baseLoader().getResourceAsStream(cljfile);
+ if(ins != null)
+ {
+ Compiler.compile(new InputStreamReader(ins, UTF8), cljfile, cljfile.substring(cljfile.lastIndexOf("/")));
+ }
+ else
+ throw new FileNotFoundException("Could not locate Clojure resource on classpath: " + lib);
+}
+
+static public void loadLib(String lib, boolean failIfNotFound) throws Exception{
+ String libpath = lib.replace('.', '/');
+ String classfile = libpath + ".class";
+ String cljfile = libpath + ".clj";
+ URL classURL = baseLoader().getResource(classfile);
+ URL cljURL = baseLoader().getResource(cljfile);
+
+ if(classURL != null &&
+ (cljURL == null
+ || lastModified(classURL, classfile) > lastModified(cljURL, cljfile)))
+ {
+ try
+ {
+ Var.pushThreadBindings(
+ RT.map(CURRENT_NS, CURRENT_NS.get(),
+ WARN_ON_REFLECTION, WARN_ON_REFLECTION.get()));
+ Reflector.invokeStaticMethod(classForName(lib), "load", EMPTY_ARRAY);
+ }
+ finally
+ {
+ Var.popThreadBindings();
+ }
+ }
+ else if(cljURL != null)
+ {
+ loadResourceScript(RT.class, cljfile);
+ }
+ else if(failIfNotFound)
+ throw new FileNotFoundException("Could not locate Clojure resource on classpath: " + lib);
+
+}
static void doInit() throws Exception{
- loadResourceScript(RT.class, "clojure/core.clj");
- loadResourceScript(RT.class, "clojure/proxy.clj", false);
- loadResourceScript(RT.class, "clojure/genclass.clj", false);
- loadResourceScript(RT.class, "clojure/zip.clj", false);
- loadResourceScript(RT.class, "clojure/xml.clj", false);
- loadResourceScript(RT.class, "clojure/set.clj", false);
+ loadLib("clojure.core");
+ loadLib("clojure.zip",false);
+ loadLib("clojure.xml",false);
+ loadLib("clojure.set",false);
+// try
+// {
+// Reflector.invokeStaticMethod("clojure.core", "load", EMPTY_ARRAY);
+// Reflector.invokeStaticMethod("clojure.zip", "load", EMPTY_ARRAY);
+// Reflector.invokeStaticMethod("clojure.xml", "load", EMPTY_ARRAY);
+// Reflector.invokeStaticMethod("clojure.set", "load", EMPTY_ARRAY);
+// }
+// finally
+// {
+// Var.popThreadBindings();
+// }
+// loadResourceScript(RT.class, "clojure/core.clj");
+// loadResourceScript(RT.class, "clojure/proxy.clj", false);
+// loadResourceScript(RT.class, "clojure/genclass.clj", false);
+// loadResourceScript(RT.class, "clojure/zip.clj", false);
+// loadResourceScript(RT.class, "clojure/xml.clj", false);
+// loadResourceScript(RT.class, "clojure/set.clj", false);
Var.pushThreadBindings(
RT.map(CURRENT_NS, CURRENT_NS.get(),
diff --git a/src/jvm/clojure/lang/Repl.java b/src/jvm/clojure/lang/Repl.java
index 0c31d045..e5d16a40 100644
--- a/src/jvm/clojure/lang/Repl.java
+++ b/src/jvm/clojure/lang/Repl.java
@@ -23,6 +23,7 @@ static final Symbol CLOJURE = Symbol.create("clojure.core");
static final Var in_ns = RT.var("clojure.core", "in-ns");
static final Var refer = RT.var("clojure.core", "refer");
static final Var ns = RT.var("clojure.core", "*ns*");
+static final Var compile_path = RT.var("clojure.core", "*compile-path*");
static final Var warn_on_reflection = RT.var("clojure.core", "*warn-on-reflection*");
static final Var print_meta = RT.var("clojure.core", "*print-meta*");
static final Var print_length = RT.var("clojure.core", "*print-length*");
@@ -48,6 +49,7 @@ public static void main(String[] args) throws Exception{
print_meta, print_meta.get(),
print_length, print_length.get(),
print_level, print_level.get(),
+ compile_path, "classes",
star1, null,
star2, null,
star3, null,