diff options
author | Rich Hickey <richhickey@gmail.com> | 2010-01-14 19:27:54 -0500 |
---|---|---|
committer | Rich Hickey <richhickey@gmail.com> | 2010-01-14 19:27:54 -0500 |
commit | 277f0235c1387ddd6247a72857597814a3e10bc3 (patch) | |
tree | 960501148292f57c32fc4fd33e6f9e35d3ae1d40 | |
parent | e6a315bd3d514c6af10d2e7a853b693aa5f4520d (diff) |
add &form and &env implicit args to macros
-rw-r--r-- | src/clj/clojure/core.clj | 63 | ||||
-rw-r--r-- | src/jvm/clojure/lang/Compiler.java | 10 | ||||
-rw-r--r-- | src/jvm/clojure/lang/RT.java | 13 |
3 files changed, 59 insertions, 27 deletions
diff --git a/src/clj/clojure/core.clj b/src/clj/clojure/core.clj index c253fc1b..ddc42e95 100644 --- a/src/clj/clojure/core.clj +++ b/src/clj/clojure/core.clj @@ -28,15 +28,15 @@ ;during bootstrap we don't have destructuring let, loop or fn, will redefine later (def #^{:macro true} - let (fn* let [& decl] (cons 'let* decl))) + let (fn* let [&form &env & decl] (cons 'let* decl))) (def #^{:macro true} - loop (fn* loop [& decl] (cons 'loop* decl))) + loop (fn* loop [&form &env & decl] (cons 'loop* decl))) (def #^{:macro true} - fn (fn* fn [& decl] (cons 'fn* decl))) + fn (fn* fn [&form &env & decl] (cons 'fn* decl))) (def #^{:arglists '([coll]) @@ -210,7 +210,7 @@ to the var metadata" :arglists '([name doc-string? attr-map? [params*] body] [name doc-string? attr-map? ([params*] body)+ attr-map?])} - defn (fn defn [name & fdecl] + defn (fn defn [&form &env name & fdecl] (let [m (if (string? (first fdecl)) {:doc (first fdecl)} {}) @@ -309,6 +309,11 @@ ;;;;;;;;;;;;;;;;;;;; +(defn nil? + "Returns true if x is nil, false otherwise." + {:tag Boolean} + [x] (identical? x nil)) + (def #^{:doc "Like defn, but the resulting function name is declared as a @@ -316,11 +321,44 @@ called." :arglists '([name doc-string? attr-map? [params*] body] [name doc-string? attr-map? ([params*] body)+ attr-map?])} - defmacro (fn [name & args] - (list 'do - (cons `defn (cons name args)) - (list '. (list 'var name) '(setMacro)) - (list 'var name)))) + defmacro (fn [&form &env + name & args] + (let [prefix (loop [p (list name) args args] + (let [f (first args)] + (if (string? f) + (recur (cons f p) (next args)) + (if (map? f) + (recur (cons f p) (next args)) + p)))) + fdecl (loop [fd args] + (if (string? (first fd)) + (recur (next fd)) + (if (map? (first fd)) + (recur (next fd)) + fd))) + fdecl (if (vector? (first fdecl)) + (list fdecl) + fdecl) + add-implicit-args (fn [fd] + (let [args (first fd)] + (cons (vec (cons '&form (cons '&env args))) (next fd)))) + add-args (fn [acc ds] + (if (nil? ds) + acc + (let [d (first ds)] + (if (map? d) + (conj acc d) + (recur (conj acc (add-implicit-args d)) (next ds)))))) + fdecl (seq (add-args [] fdecl)) + decl (loop [p prefix d fdecl] + (if p + (recur (next p) (cons (first p) d)) + d))] + (list 'do + (cons `defn decl) + (list '. (list 'var name) '(setMacro)) + (list 'var name))))) + (. (var defmacro) (setMacro)) @@ -334,11 +372,6 @@ [test & body] (list 'if test nil (cons 'do body))) -(defn nil? - "Returns true if x is nil, false otherwise." - {:tag Boolean} - [x] (identical? x nil)) - (defn false? "Returns true if x is the value false, false otherwise." {:tag Boolean} @@ -3041,7 +3074,7 @@ (if name (list* 'fn* name new-sigs) (cons 'fn* new-sigs)) - *macro-meta*))) + (meta &form)))) (defmacro loop "Evaluates the exprs in a lexical context in which the symbols in diff --git a/src/jvm/clojure/lang/Compiler.java b/src/jvm/clojure/lang/Compiler.java index 13bcf9de..9f58b794 100644 --- a/src/jvm/clojure/lang/Compiler.java +++ b/src/jvm/clojure/lang/Compiler.java @@ -5112,15 +5112,7 @@ public static Object macroexpand1(Object x) throws Exception{ Var v = isMacro(op); if(v != null) { - try - { - Var.pushThreadBindings(RT.map(RT.MACRO_META, RT.meta(form))); - return v.applyTo(form.next()); - } - finally - { - Var.popThreadBindings(); - } + return v.applyTo(RT.cons(form,RT.cons(LOCAL_ENV.get(),form.next()))); } else { diff --git a/src/jvm/clojure/lang/RT.java b/src/jvm/clojure/lang/RT.java index 277e62bc..2698c99f 100644 --- a/src/jvm/clojure/lang/RT.java +++ b/src/jvm/clojure/lang/RT.java @@ -180,7 +180,6 @@ 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"); @@ -219,6 +218,15 @@ final static IFn inNamespace = new AFn(){ } }; +final static IFn bootNamespace = new AFn(){ + public Object invoke(Object __form, Object __env,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("--"); @@ -264,8 +272,7 @@ static{ 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); + Var nv = Var.intern(CLOJURE_NS, NAMESPACE, bootNamespace); nv.setMacro(); Var v; v = Var.intern(CLOJURE_NS, IN_NAMESPACE, inNamespace); |