summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRich Hickey <richhickey@gmail.com>2010-01-14 19:27:54 -0500
committerRich Hickey <richhickey@gmail.com>2010-01-14 19:27:54 -0500
commit277f0235c1387ddd6247a72857597814a3e10bc3 (patch)
tree960501148292f57c32fc4fd33e6f9e35d3ae1d40
parente6a315bd3d514c6af10d2e7a853b693aa5f4520d (diff)
add &form and &env implicit args to macros
-rw-r--r--src/clj/clojure/core.clj63
-rw-r--r--src/jvm/clojure/lang/Compiler.java10
-rw-r--r--src/jvm/clojure/lang/RT.java13
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);