   <closed-overs>"
 
   first)
+
+(defn gen-methods
+  [^ClassWriter cw {:keys [thistype] :as env} methods]
+  (let [before-rest (complement #{rest-token})
+        arglists (map first methods)]
+    (doseq [[params & body] methods]
+      (let [env (assoc env
+                  :params (take-while before-rest params)
+                  :restarg (second (drop-while before-rest params)))]
+        (gen-body cw env body)))
+    (gen-applier cw thistype arglists)
+    (gen-handle cw thistype arglists)))
+
+(defn compile-lambda
+  [[_ & methods :as form]]
+  (let [fv (vec (free-vars form))
+        cw (ClassWriter. ClassWriter/COMPUTE_FRAMES)
+        lname (str (dotmunge (str (or *top-level* *lambda-name* 'lambda))) "_" (next-id))
+        fqname (str "wombat/" lname)
+        _ (debug "fqname:" fqname)
+        dotname (.replace fqname "/" ".")
+        ifaces (into-array String ["wombat/ILambda"])
+        env {:closed-overs fv
+             :locals {}
+             :recur-sym *lambda-name*
+             :thistype (Type/getObjectType fqname)}]
+    (. cw visit Opcodes/V1_7 Opcodes/ACC_PUBLIC fqname nil "java/lang/Object" ifaces)
+    (gen-closure-fields cw fv)
+    (gen-ctor cw fqname fv)
+    (binding [*lambda-name* (if *top-level* *lambda-name* nil)]
+      (gen-methods cw env methods))
+    (. cw visitEnd)))
 
 (defmethod compile 'lambda
   [[_ params & body :as lambda]]
   (when-not (get @*compiled-lambdas* lambda)
     (validate-params! params)
     (debug "Compiling:" lambda)
-    (let [fv (vec (free-vars lambda))
-          cw (ClassWriter. ClassWriter/COMPUTE_FRAMES)
-          lname (str (dotmunge (str (or *lambda-name* 'lambda))) "_" (next-id))
-          fqname (str "wombat/" lname)
-          _ (debug "fqname:" fqname)
-          dotname (.replace fqname "/" ".")
-          ifaces (into-array String ["wombat/ILambda"])
+    (let [
           before-rest (complement #{rest-token})
           restarg (second (drop-while before-rest params))
-          env {:params (take-while before-rest params)
-               :closed-overs fv
-               :locals {}
-               :recur-sym *lambda-name* ;; TODO: Enable named lambdas
-               :thistype (Type/getObjectType fqname)
-               :restarg restarg}]
+]
       (binding [*lambda-name* (if *top-level* *lambda-name* nil)]
         (. cw visit Opcodes/V1_7 Opcodes/ACC_PUBLIC fqname nil "java/lang/Object" ifaces)
         (gen-closure-fields cw fv)

      (. gen returnValue)
      (. gen endMethod))))

(defn validate-params!
  [params]
  (when (and (some #{rest-token} params)
             (not= (count (drop-while (complement #{rest-token}) params)) 2))
    (throw (IllegalArgumentException. "#!rest may only be followed by one symbol!"))))

(def ^:dynamic *compiled-lambdas*)

(defmulti compile


     (['lambda params & body] :seq)
     (apply disj (free-vars body) (cons *lambda-name* (remove special-token? params)))

     (['case-lambda & methods] :seq)
     (reduce into (sorted-set)
             (map #(apply disj (free-vars (second %))
                          (cons *lambda-name* (remove special-token? (first %))))
                  methods))

     ([(:or 'let 'letrec) bindings & body] :seq)
     (let [[name bindings & body] (if (symbol? bindings)
