 ;; -----------------------------------------------------------------------------
 ;; Analyze
 
+(declare compile*)
+
 (def *loaded* (atom #{}))
 
 (defn require
-  ([name cb]
+  ([bound-vars name opts cb]
    (when-not (contains? @*loaded* name)
      (*load-fn* name
        (fn [source]
-         (*eval-fn* source)
-         (cb true)))))
-  ([name reload cb]
+         (compile* bound-vars source opts (fn [ret] (cb true)))))))
+  ([bound-vars name reload opts cb]
    (when (= :reload reload)
      (swap! *loaded* disj name))
    (when (= :reload-all reload)

   (when-not (contains? @*loaded* name)
     (*load-fn* name
       (fn [source]
         (*eval-fn* source)
         (cb true))))))

(declare ns-side-effects)

(defn analyze* [env bound-vars source opts cb]
  (let [rdr  (rt/string-push-back-reader source)
        eof  (js-obj)
        aenv (ana/empty-env)]
    (binding [ana/*cljs-ns*    (:*cljs-ns* bound-vars)
              *ns*             (:*ns* bound-vars)
              r/*data-readers* (:*data-readers* bound-vars)
              env/*compiler*   env]
      (loop []
        (let [form (r/read {:eof eof} rdr)]
          (if-not (identical? eof form)
            (let [aenv (assoc aenv :ns (ana/get-namespace ana/*cljs-ns*))
                  ast  (ana/analyze aenv form)]
              (if (= (:op ast) :ns)
                (ns-side-effects env ast opts bound-vars
                  (fn [_] (cb)))
                (recur)))
            (cb)))))))


  ([env source cb]
   (analyze env source nil cb))
  ([env source opts cb]
   (analyze*
     {:*compiler*     env
      :*cljs-ns*      (or (:ns env) 'cljs.user)
      :*ns*           (create-ns ana/*cljs-ns*)
      :*data-readers* tags/*cljs-data-readers*}
     source opts cb)))
