               (let [pcnt (count (:params meth))]
                 (emitln "case " pcnt ":")
                 (emitln "return " n "(" (if (zero? pcnt) nil
-                                                (list (comma-sep (take pcnt maxparams)))) ")"))))
+                                            (list (comma-sep (take pcnt maxparams)))) ")"))))
           (emitln "}")
           (emitln "panic(js.Error{fmt.Sprint(\"Invalid arity: \", len(arguments))})")
           (emitln "}")

(defn go-public [s]
  (str (string/upper-case (subs (name s) 0 1)) (subs (name s) 1)))

(def ^:dynamic *go-return* nil)
(def ^:dynamic *go-line-numbers* false) ;; https://golang.org/cmd/gc/#hdr-Compiler_Directives

(defn emitln [& xs]
  (when-let [line (and *go-line-numbers* (some (comp :line :env) xs))]

  [file-str]
  (clojure.string/replace file-str #"\.cljs$" ".go"))

(defn mkdirs
  "Create all parent directories for the passed file."
  [^File f]
  (.mkdirs (.getParentFile (.getCanonicalFile f))))

(defmacro with-core-cljs
  "Ensure that core.cljs has been loaded."
  [& body]
  `(do (when-not (get-in @env/*compiler* [::ana/namespaces 'cljs.core :defs])
         (ana/analyze-file "cljs/core.cljs"))
       ~@body))

(defn url-path [^File f]
  (.getPath (.toURL (.toURI f))))

(defn compile-file*
  ([src dest] (compile-file* src dest nil))
  ([src dest opts]
    (env/ensure
      (with-core-cljs
        (with-open [out ^java.io.Writer (io/make-writer dest {})]
          (binding [*out* out
                    ana/*cljs-ns* 'cljs.user
                    ana/*cljs-file* (.getPath ^File src)
                    reader/*alias-map* (or reader/*alias-map* {})
                    *source-map-data* (when (:source-map opts)
                                        (atom
                                          {:source-map (sorted-map)
                                           :gen-col 0
                                           :gen-line 0}))]
            (emitln "// Compiled by ClojureScript " (clojurescript-version))
            (loop [forms (ana/forms-seq src)
                   ns-name nil
                   deps nil]
              (if (seq forms)
                (let [env (ana/empty-env)
                      ast (ana/analyze env (first forms))]
                  (do (emit ast)
                    (if (= (:op ast) :ns)
                      (recur (rest forms) (:name ast) (merge (:uses ast) (:requires ast)))
                      (recur (rest forms) ns-name deps))))
                (let [sm-data (when *source-map-data* @*source-map-data*)
                      ret (merge
                            {:ns (or ns-name 'cljs.user)
                             :provides [ns-name]
                             :requires (if (= ns-name 'cljs.core)
                                         (set (vals deps))
                                         (cond-> (conj (set (vals deps)) 'cljs.core)
                                           (get-in @env/*compiler* [:opts :emit-constants])
                                           (conj 'constants-table)))
                             :file dest
                             :source-file src}
                            (when sm-data
                              {:source-map (:source-map sm-data)}))]
                  (when (and sm-data (= (:optimizations opts) :none))
                    (let [sm-file (io/file (str (.getPath ^File dest) ".map"))]
                      (emits "\n//# sourceMappingURL=" (.getName sm-file))
                      (spit sm-file
                        (sm/encode {(url-path src) (:source-map sm-data)}
                          {:lines (+ (:gen-line sm-data) 2)
                           :file (url-path dest)}))))
                  (let [path (.getPath (.toURL ^File dest))]
                    (swap! env/*compiler* assoc-in [::compiled-cljs path] ret)
                    (swap! env/*compiler* assoc-in [::ana/analyzed-cljs path] true))
                  ret)))))))))

(defn compiled-by-version [^File f]
  (with-open [reader (io/reader f)]
    (let [match (->> reader line-seq first
                     (re-matches #".*ClojureScript (.*)$"))]
      (and match (second match)))))

(defn requires-compilation?
  "Return true if the src file requires compilation."
  ([src dest] (requires-compilation? src dest nil))
  ([^File src ^File dest opts]
    (env/ensure
      (or (not (.exists dest))
          (> (.lastModified src) (.lastModified dest))
          (let [version' (compiled-by-version dest)
                version  (clojurescript-version)]
            (and version (not= version version')))
          (and opts
            (:source-map opts)
            (if (= (:optimizations opts) :none)
              (not (.exists (io/file (str (.getPath dest) ".map"))))
              (not (get-in @env/*compiler* [::compiled-cljs (.getAbsolutePath dest)]))))))))

(defn parse-ns
  ([src] (parse-ns src nil nil))
  ([src dest opts]
    (env/ensure
      (let [namespaces' (::ana/namespaces @env/*compiler*)
            ret
            (binding [ana/*cljs-ns* 'cljs.user
                      ana/*analyze-deps* false]
              (loop [forms (ana/forms-seq src)]
                (if (seq forms)
                  (let [env (ana/empty-env)
                        ast (ana/no-warn (ana/analyze env (first forms)))]
                    (if (= (:op ast) :ns)
                      (let [ns-name (:name ast)
                            deps    (merge (:uses ast) (:requires ast))]
                        (merge
                          {:ns (or ns-name 'cljs.user)
                           :provides [ns-name]
                           :requires (if (= ns-name 'cljs.core)
                                       (set (vals deps))
                                       (cond-> (conj (set (vals deps)) 'cljs.core)
                                         (get-in @env/*compiler* [:opts :emit-constants])
                                         (conj 'constants-table)))
                           :file dest
                           :source-file src}
                          (when (and dest (.exists ^File dest))
                            {:lines (with-open [reader (io/reader dest)]
                                      (-> reader line-seq count))})))
                      (recur (rest forms)))))))]
        ;; TODO this _was_ a reset! of the old ana/namespaces atom; should we capture and
        ;; then restore the entirety of env/*compiler* here instead?
        (swap! env/*compiler* assoc ::ana/namespaces namespaces')
        ret))))

(defn compile-file
  "Compiles src to a file of the same name, but with a .js extension,
   in the src file's directory.

   With dest argument, write file to provided location. If the dest
   argument is a file outside the source tree, missing parent
   directories will be created. The src file will only be compiled if
   the dest file has an older modification time.

   Both src and dest may be either a String or a File.

   Returns a map containing {:ns .. :provides .. :requires .. :file ..}.
   If the file was not compiled returns only {:file ...}"
  ([src]
    (let [dest (rename-to-js src)]
      (compile-file src dest nil)))
  ([src dest]
    (compile-file src dest nil))
  ([src dest opts]
    (let [src-file (io/file src)
          dest-file (io/file dest)]
      (if (.exists src-file)
        (try
          (let [{ns :ns :as ns-info} (parse-ns src-file dest-file opts)]
            (if (requires-compilation? src-file dest-file opts)
              (do (mkdirs dest-file)
                (when (contains? (::ana/namespaces @env/*compiler*) ns)
                  (swap! env/*compiler* update-in [::ana/namespaces] dissoc ns))
                (compile-file* src-file dest-file opts))
              (do
                (when-not (contains? (::ana/namespaces @env/*compiler*) ns)
                  (with-core-cljs
                    (ana/analyze-file src-file)))
                ns-info)))
          (catch Exception e
            (throw (ex-info (str "failed compiling file:" src) {:file src} e))))
        (throw (java.io.FileNotFoundException. (str "The file " src " does not exist.")))))))

(defn path-seq
  [file-str]
  (->> File/separator
       java.util.regex.Pattern/quote
       re-pattern
       (string/split file-str)))

(defn to-path
  ([parts]
     (to-path parts File/separator))
  ([parts sep]
    (apply str (interpose sep parts))))

(defn ^File to-target-file
  [target cljs-file]
  (let [relative-path (string/split
