diff options
author | Rich Hickey <richhickey@gmail.com> | 2008-02-08 19:11:58 +0000 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2008-02-08 19:11:58 +0000 |
commit | 221023b4d27e75757e3c842176872d5300d35b23 (patch) | |
tree | ea3e1258301ad03d852fc267b6462dad8a6e3cee /src | |
parent | 81d57a3b85548d82668494a95368524087055665 (diff) |
var metadata
Diffstat (limited to 'src')
-rw-r--r-- | src/boot.clj | 42 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Compiler.java | 52 | ||||
-rw-r--r-- | src/jvm/clojure/lang/LispReader.java | 5 | ||||
-rw-r--r-- | src/jvm/clojure/lang/RT.java | 4 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Var.java | 57 |
5 files changed, 95 insertions, 65 deletions
diff --git a/src/boot.clj b/src/boot.clj index ad3d540e..302d22ef 100644 --- a/src/boot.clj +++ b/src/boot.clj @@ -16,7 +16,7 @@ (def defn (fn [name & fdecl] (list 'def name (cons 'fn (cons name fdecl))))) -(. (the-var defn) (setMacro)) +(. (var defn) (setMacro)) (defn instance? [#^Class c x] (. c (isInstance x))) @@ -52,9 +52,9 @@ (def defmacro (fn [name & args] (list 'do (cons 'defn (cons name args)) - (list '. (list 'the-var name) '(setMacro))))) + (list '. (list 'var name) '(setMacro))))) -(. (the-var defmacro) (setMacro)) +(. (var defmacro) (setMacro)) (defmacro when [test & body] (list 'if test (cons 'do body))) @@ -414,11 +414,11 @@ `(def ~name (new clojure.lang.MultiFn ~dispatch-fn ~default-val)))) (defmacro defmethod [multifn dispatch-val & fn-tail] - `(let [pvar# (the-var ~multifn)] + `(let [pvar# (var ~multifn)] (. pvar# (commuteRoot (fn [mf#] (. mf# (assoc ~dispatch-val (fn ~@fn-tail)))))))) (defmacro remove-method [multifn dispatch-val] - `(let [pvar# (the-var ~multifn)] + `(let [pvar# (var ~multifn)] (. pvar# (commuteRoot (fn [mf#] (. mf# (dissoc ~dispatch-val))))))) ;;;;;;;;; var stuff @@ -427,7 +427,7 @@ (let [var-ize (fn [var-vals] (loop [ret [] vvs (seq var-vals)] (if vvs - (recur (conj (conj ret `(the-var ~(first vvs))) (second vvs)) + (recur (conj (conj ret `(var ~(first vvs))) (second vvs)) (rest (rest vvs))) (seq ret))))] `(try @@ -994,13 +994,14 @@ (defn ns-unmap [#^clojure.lang.Namespace ns sym] (. ns (unmap sym))) -(defn export [syms] - (doseq sym syms - (.. *ns* (intern sym) (setExported true)))) +;(defn export [syms] +; (doseq sym syms +; (.. *ns* (intern sym) (setExported true)))) (defn ns-exports [#^clojure.lang.Namespace ns] (filter-key val (fn [v] (and (instance? clojure.lang.Var v) - (. v (isExported)))) + (= ns (. v ns)) + (. v (isPublic)))) (ns-map ns))) (defn ns-imports [#^clojure.lang.Namespace ns] @@ -1015,10 +1016,10 @@ to-do (or (:only fs) (keys nsexports))] (doseq sym to-do (when-not (exclude sym) - (let [var (nsexports sym)] - (when-not var + (let [v (nsexports sym)] + (when-not v (throw (new java.lang.IllegalAccessError (strcat sym " is not exported")))) - (. *ns* (refer (or (rename sym) sym) var))))))) + (. *ns* (refer (or (rename sym) sym) v))))))) (defn ns-refers [#^clojure.lang.Namespace ns] (filter-key val (fn [v] (and (instance? clojure.lang.Var v) @@ -1183,14 +1184,14 @@ (def defn* (fn [name & fdecl] (list 'def name (cons `fn* (cons name fdecl))))) -(. (the-var defn*) (setMacro)) +(. (var defn*) (setMacro)) (def defmacro* (fn [name & args] (list 'do (cons `defn* (cons name args)) - (list '. (list 'the-var name) '(setMacro))))) + (list '. (list 'var name) '(setMacro))))) -(. (the-var defmacro*) (setMacro)) +(. (var defmacro*) (setMacro)) (defn bean [#^Object x] (let [c (. x (getClass)) @@ -1216,6 +1217,9 @@ (lazy-cons (new clojure.lang.MapEntry (first pseq) (v (first pseq))) (this (rest pseq))))) (keys pmap)))))) +(defmacro comment [& body]) + +(comment (export '( load-file load list cons conj defn @@ -1269,7 +1273,8 @@ *warn-on-reflection* resultset-seq to-set distinct - export ns-exports ns-imports ns-map + export + ns-exports ns-imports ns-map identical? instance? load-file in-ns find-ns filter-key find-ns create-ns remove-ns @@ -1281,6 +1286,7 @@ nthrest string? symbol? map? seq? vector? let* fn* defn* defmacro* - bean + bean select )) + ) diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index eb651994..637c28b7 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -28,7 +28,6 @@ import org.objectweb.asm.util.CheckClassAdapter; //*/ import java.io.*; -import java.math.BigInteger; import java.util.List; import java.util.ArrayList; import java.util.LinkedList; @@ -45,7 +44,7 @@ static final Symbol LET = Symbol.create("let"); static final Symbol DO = Symbol.create("do"); static final Symbol FN = Symbol.create("fn"); static final Symbol QUOTE = Symbol.create("quote"); -static final Symbol THE_VAR = Symbol.create("the-var"); +static final Symbol THE_VAR = Symbol.create("var"); static final Symbol DOT = Symbol.create("."); static final Symbol ASSIGN = Symbol.create("set!"); //static final Symbol TRY_FINALLY = Symbol.create("try-finally"); @@ -117,6 +116,7 @@ final static Type CLASS_TYPE = Type.getType(Class.class); final static Type REFLECTOR_TYPE = Type.getType(Reflector.class); final static Type THROWABLE_TYPE = Type.getType(Throwable.class); final static Type BOOLEAN_OBJECT_TYPE = Type.getType(Boolean.class); +final static Type IPERSISTENTMAP_TYPE = Type.getType(IPersistentMap.class); private static final Type[][] ARG_TYPES; private static final Type[] EXCEPTION_TYPES = {Type.getType(Exception.class)}; @@ -238,23 +238,27 @@ static Symbol resolveSymbol(Symbol sym){ static class DefExpr implements Expr{ final Var var; final Expr init; - final Symbol tag; + final Expr meta; final boolean initProvided; final static Method bindRootMethod = Method.getMethod("void bindRoot(Object)"); final static Method setTagMethod = Method.getMethod("void setTag(clojure.lang.Symbol)"); + final static Method setMetaMethod = Method.getMethod("void setMeta(clojure.lang.IPersistentMap)"); final static Method symcreate = Method.getMethod("clojure.lang.Symbol create(String, String)"); - public DefExpr(Var var, Expr init, boolean initProvided, Symbol tag){ + public DefExpr(Var var, Expr init, Expr meta, boolean initProvided){ this.var = var; this.init = init; + this.meta = meta; this.initProvided = initProvided; - this.tag = tag; } public Object eval() throws Exception{ if(initProvided) var.bindRoot(init.eval()); - var.setTag(tag); + if(meta != null) + { + var.setMeta((IPersistentMap) meta.eval()); + } return var; } @@ -266,16 +270,14 @@ static class DefExpr implements Expr{ init.emit(C.EXPRESSION, fn, gen); gen.invokeVirtual(VAR_TYPE, bindRootMethod); } - gen.dup(); - if(tag != null) + if(meta != null) { - gen.push(tag.ns); - gen.push(tag.name); - gen.invokeStatic(SYMBOL_TYPE, symcreate); + gen.dup(); + meta.emit(C.EXPRESSION, fn, gen); + gen.checkCast(IPERSISTENTMAP_TYPE); + gen.invokeVirtual(VAR_TYPE, setMetaMethod); } - else - gen.visitInsn(Opcodes.ACONST_NULL); - gen.invokeVirtual(VAR_TYPE, setTagMethod); + if(context == C.STATEMENT) gen.pop(); } @@ -305,12 +307,15 @@ static class DefExpr implements Expr{ { if(sym.ns == null) throw new Exception("Name conflict, can't def " + sym + " because namespace: " + currentNS().name + - " refers to:" + v.sym); + " refers to:" + v); else throw new Exception("Can't create defs outside of current ns"); } + IPersistentMap mm = sym.meta(); + mm = (IPersistentMap) RT.assoc(mm, RT.LINE_KEY, LINE.get()).assoc(RT.FILE_KEY,SOURCE.get()); + Expr meta = analyze(context == C.EVAL ? context : C.EXPRESSION, mm); return new DefExpr(v, analyze(context == C.EVAL ? context : C.EXPRESSION, RT.third(form), v.sym.name), - RT.count(form) == 3, tagOf(sym)); + meta, RT.count(form) == 3); } } } @@ -356,7 +361,7 @@ static class AssignExpr implements Expr{ static class VarExpr implements Expr, AssignableExpr{ final Var var; - final Symbol tag; + final Object tag; final static Method getMethod = Method.getMethod("Object get()"); final static Method setMethod = Method.getMethod("Object set(Object)"); @@ -735,7 +740,7 @@ static abstract class HostExpr implements Expr{ return className; } */ - static Class tagToClass(Symbol tag) throws Exception{ + static Class tagToClass(Object tag) throws Exception{ Class c = maybeClass(tag, true); if(c != null) return c; @@ -1906,7 +1911,6 @@ static class NewExpr implements Expr{ static class MetaExpr implements Expr{ final Expr expr; final MapExpr meta; - final static Type IPERSISTENTMAP_TYPE = Type.getType(IPersistentMap.class); final static Type IOBJ_TYPE = Type.getType(IObj.class); final static Method withMetaMethod = Method.getMethod("clojure.lang.IObj withMeta(clojure.lang.IPersistentMap)"); @@ -2226,7 +2230,7 @@ static class VectorExpr implements Expr{ static class InvokeExpr implements Expr{ final Expr fexpr; - final Symbol tag; + final Object tag; final IPersistentVector args; final int line; @@ -3146,7 +3150,7 @@ static public Var isMacro(Object op) throws Exception{ Var v = (op instanceof Var) ? (Var) op : lookupVar((Symbol) op, false); if(v != null && v.isMacro()) { - if(v.ns != currentNS() && !v.isExported()) + if(v.ns != currentNS() && !v.isPublic()) throw new IllegalAccessError("var: " + v + " is not exported"); return v; } @@ -3158,8 +3162,8 @@ private static Expr analyzeSeq(C context, ISeq form, String name) throws Excepti Integer line = (Integer) LINE.get(); try { - if(RT.meta(form) != null && RT.meta(form).containsKey(LispReader.LINE_KEY)) - line = (Integer) RT.meta(form).valAt(LispReader.LINE_KEY); + if(RT.meta(form) != null && RT.meta(form).containsKey(RT.LINE_KEY)) + line = (Integer) RT.meta(form).valAt(RT.LINE_KEY); Var.pushThreadBindings( RT.map(LINE, line)); Object op = RT.first(form); @@ -3275,7 +3279,7 @@ static public Object resolveIn(Namespace n, Symbol sym) throws Exception{ Var v = ns.findInternedVar(Symbol.create(sym.name)); if(v == null) throw new Exception("No such var: " + sym); - else if(v.ns != currentNS() && !v.isExported()) + else if(v.ns != currentNS() && !v.isPublic()) throw new IllegalAccessError("var: " + sym + " is not exported"); return v; } diff --git a/src/jvm/clojure/lang/LispReader.java b/src/jvm/clojure/lang/LispReader.java index 52db79c6..e2c12ae1 100644 --- a/src/jvm/clojure/lang/LispReader.java +++ b/src/jvm/clojure/lang/LispReader.java @@ -32,7 +32,6 @@ static Symbol WITH_META = Symbol.create("clojure", "with-meta"); static Symbol META = Symbol.create("clojure", "meta");
static Symbol DEREF = Symbol.create("clojure", "deref");
//static Symbol DEREF_BANG = Symbol.create("clojure", "deref!");
-static Keyword LINE_KEY = Keyword.intern("clojure", "line");
static IFn[] macros = new IFn[256];
static IFn[] dispatchMacros = new IFn[256];
@@ -374,7 +373,7 @@ static class MetaReader extends AFn{ if(o instanceof IObj)
{
if(line != -1 && o instanceof ISeq)
- meta = ((IPersistentMap) meta).assoc(LINE_KEY, line);
+ meta = ((IPersistentMap) meta).assoc(RT.LINE_KEY, line);
return ((IObj) o).withMeta((IPersistentMap) meta);
}
else
@@ -557,7 +556,7 @@ static class ListReader extends AFn{ IObj s = (IObj) PersistentList.create(list);
// IObj s = (IObj) RT.seq(list);
if(line != -1)
- return s.withMeta(RT.map(LINE_KEY, line));
+ return s.withMeta(RT.map(RT.LINE_KEY, line));
else
return s;
}
diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java index 1ede12f4..90ec1602 100644 --- a/src/jvm/clojure/lang/RT.java +++ b/src/jvm/clojure/lang/RT.java @@ -108,8 +108,10 @@ final static public Var OUT = final static public Var IN = Var.intern(CLOJURE_NS, Symbol.create("*in*"), new LineNumberingPushbackReader(new InputStreamReader(System.in))); -final static Keyword TAG_KEY = Keyword.intern("clojure", "tag"); +final static Keyword TAG_KEY = Keyword.intern(null, "tag"); final static Keyword AGENT_KEY = Keyword.intern("clojure", "agent"); +static Keyword LINE_KEY = Keyword.intern(null, "line"); +static Keyword FILE_KEY = Keyword.intern(null, "file"); //final static public Var CURRENT_MODULE = Var.intern(Symbol.create("clojure", "current-module"), // Module.findOrCreateModule("clojure/user")); diff --git a/src/jvm/clojure/lang/Var.java b/src/jvm/clojure/lang/Var.java index 25c67e94..37f3bacd 100644 --- a/src/jvm/clojure/lang/Var.java +++ b/src/jvm/clojure/lang/Var.java @@ -12,11 +12,11 @@ package clojure.lang; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicInteger; -public final class Var implements IFn, IRef{ +public final class Var implements IFn, IRef, IObj{ + static class Frame{ //Var->Box @@ -44,13 +44,18 @@ static ThreadLocal<Frame> dvals = new ThreadLocal<Frame>(){ } }; +static Keyword privateKey = Keyword.intern(null, "private"); +static Keyword macroKey = Keyword.intern(null, "macro"); +static Keyword nameKey = Keyword.intern(null, "name"); +static Keyword nsKey = Keyword.intern(null, "ns"); +//static Keyword tagKey = Keyword.intern(null, "tag"); + volatile Object root; transient final AtomicInteger count; -final public Symbol sym; -final public Namespace ns; -boolean macroFlag = false; -boolean exported = false; -Symbol tag; +public final Symbol sym; +public final Namespace ns; + +IPersistentMap _meta; public static Var intern(Namespace ns, Symbol sym, Object root){ return intern(ns, sym, root, true); @@ -67,7 +72,7 @@ public static Var intern(Namespace ns, Symbol sym, Object root, boolean replaceR public String toString(){ return "#<Var: " + (ns != null ? (ns.name + "/") : "") + (sym != null ? sym.toString() : "--unnamed--") + - (exported?" (exported)":"") + ">"; + ">"; } public static Var find(Symbol nsQualifiedSym){ @@ -102,6 +107,7 @@ Var(Namespace ns, Symbol sym){ this.sym = sym; this.count = new AtomicInteger(); this.root = dvals; //use dvals as magic not-bound value + setMeta(PersistentHashMap.EMPTY); } Var(Namespace ns, Symbol sym, Object root){ @@ -140,32 +146,45 @@ public Object set(Object val){ throw new IllegalStateException(String.format("Can't change/establish root binding of: %s with set", sym)); } +public void setMeta(IPersistentMap m){ + //ensure these basis keys + _meta = m.assoc(nameKey, sym).assoc(nsKey, ns); +} + +public IPersistentMap meta(){ + return _meta; +} + +public IObj withMeta(IPersistentMap meta){ + throw new UnsupportedOperationException("Vars are not values"); +} + public void setMacro(){ - macroFlag = true; + _meta = _meta.assoc(macroKey, RT.T); } public boolean isMacro(){ - return macroFlag; + return RT.booleanCast(_meta.valAt(macroKey)); } -public void setExported(boolean state){ - exported = state; -} +//public void setExported(boolean state){ +// _meta = _meta.assoc(privateKey, state); +//} -public boolean isExported(){ - return exported; +public boolean isPublic(){ + return !RT.booleanCast(_meta.valAt(privateKey)); } public Object getRoot(){ return root; } -public Symbol getTag(){ - return tag; +public Object getTag(){ + return _meta.valAt(RT.TAG_KEY); } public void setTag(Symbol tag){ - this.tag = tag; + _meta = _meta.assoc(RT.TAG_KEY, tag); } final public boolean hasRoot(){ @@ -175,7 +194,7 @@ final public boolean hasRoot(){ //binding root always clears macro flag synchronized public void bindRoot(Object root){ this.root = root; - macroFlag = false; + _meta = _meta.assoc(macroKey, RT.F); } synchronized public void unbindRoot(){ |