   ([form env opts]
      (prewalk (analyze form env opts) cleanup)))
 
-;; TODO: handle env/*compiler*, cache analyzed code
 (defn analyze-ns [ns env]
-  (let [res (ns-resource ns)]
-    (assert res (str "Can't find " ns " in classpath"))
-    (let [filename (source-path res)]
-      (binding [*ns* *ns*]
-        (with-open [rdr (io/reader res)]
-          (let [pbr (readers/indexing-push-back-reader
-                     (java.io.PushbackReader. rdr) 1 filename)
-                eof (Object.)
-                env (empty-env)]
-            (loop []
-              (let [form (binding [c.c/*ns* (create-ns *ns*)
-                                   reader/*data-readers* tags/*cljs-data-readers*
-                                   reader/*alias-map* (apply merge {}
-                                                             (-> env :namespaces deref (get *ns*)
-                                                                (select-keys #{:aliases :macro-aliases})
-                                                                vals))]
-                           (reader/read pbr nil eof))]
-                (when-not (identical? form eof)
-                  (analyze form (assoc env :ns *ns*))
-                  (recur))))))))))
+  (env/ensure (global-env)
+    (let [res (ns-resource ns)]
+      (assert res (str "Can't find " ns " in classpath"))
+      (let [filename (source-path res)
+            path (res-path res)]
+        (when-not (get-in *env* [::analyzed-cljs path])
+          (binding [*ns* *ns*]
+            (with-open [rdr (io/reader res)]
+              (let [pbr (readers/indexing-push-back-reader
+                         (java.io.PushbackReader. rdr) 1 filename)
+                    eof (Object.)
+                    env (empty-env)]
+                (loop []
+                  (let [form (binding [c.c/*ns* (create-ns *ns*)
+                                       reader/*data-readers* tags/*cljs-data-readers*
+                                       reader/*alias-map* (apply merge {}
+                                                                 (-> (env/deref-env) :namespaces (get *ns*)
+                                                                    (select-keys #{:aliases :macro-aliases})
+                                                                    vals))]
+                               (reader/read pbr nil eof))]
+                    (when-not (identical? form eof)
+                      (swap! *env* update-in [::analyzed-cljs path]
+                             (fnil conj [])
+                             (analyze form (assoc env :ns *ns*)))
+                      (recur))))))))))))

       :else form))
    form))

(defn maybe-macro [sym {:keys [namespaces ns]}]
  (let [var (if-let [sym-ns (namespace sym)]
              (if-let [full-ns (get-in @namespaces [ns :macro-aliases] (symbol sym-ns))]
                (ns-resolve full-ns (symbol (name sym)))
                (ns-resolve (symbol sym-ns) (symbol (name sym))))
              (get-in @namespaces [ns :mcacro-mappings sym]))]
    (when (:macro (meta var))
      var)))

(defn macroexpand-1 [form env]
  (if (seq? form)
    (let [op (first form)]
      (if (specials op)
        form
        (let [clj-macro (maybe-macro op env)]
          (if (and clj-macro
                   (not (resolve-var op env))
                   (not (-> env :locals (get op))))
            (apply clj-macro form env (rest form)) ; (m &form &env & args)
            (desugar-host-expr form)))))
        form))

(defn create-var
  [sym {:keys [ns]}]

                          fields)
        protocols (-> name meta :protocols)]

    (swap! *env* assoc-in [:namespaces ns :mappings name]
           {:op        :type
            :name      name
            :ns        ns
