diff options
author | Rich Hickey <richhickey@gmail.com> | 2008-11-10 23:43:53 +0000 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2008-11-10 23:43:53 +0000 |
commit | 240969a3af34ff0661238d03c006cc5a74dc1698 (patch) | |
tree | eec677998e7aa5697ea87e8fb41fb8b3efa9a880 /src | |
parent | 22a2d9080da1ab1761306f0171d85c5464d82096 (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.clj | 315 | ||||
-rw-r--r-- | src/clj/clojure/inspector.clj | 4 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Compiler.java | 211 | ||||
-rw-r--r-- | src/jvm/clojure/lang/LispReader.java | 3 | ||||
-rw-r--r-- | src/jvm/clojure/lang/RT.java | 90 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Repl.java | 2 |
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, |