Skip to content

Commit

Permalink
add &form and &env implicit args to macros
Browse files Browse the repository at this point in the history
  • Loading branch information
richhickey committed Jan 15, 2010
1 parent e6a315b commit 277f023
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 27 deletions.
63 changes: 48 additions & 15 deletions src/clj/clojure/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down Expand Up @@ -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)}
{})
Expand Down Expand Up @@ -309,18 +309,56 @@


;;;;;;;;;;;;;;;;;;;;
(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
macro and will be used as a macro by the compiler when it is
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))

Expand All @@ -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}
Expand Down Expand Up @@ -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
Expand Down
10 changes: 1 addition & 9 deletions src/jvm/clojure/lang/Compiler.java
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
13 changes: 10 additions & 3 deletions src/jvm/clojure/lang/RT.java
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,6 @@ public class RT{
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");
Expand Down Expand Up @@ -219,6 +218,15 @@ public Object invoke(Object arg1) throws Exception{
}
};

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("--");
Expand Down Expand Up @@ -264,8 +272,7 @@ synchronized public Object invoke() throws Exception {
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);
Expand Down

0 comments on commit 277f023

Please sign in to comment.