Skip to content

Commit

Permalink
CLJS-1367: Better api call arguments
Browse files Browse the repository at this point in the history
This change adds additional arity for api calls which need compiler-env.
Old arities continue to use the dynamic var.

Also, api calls which take options map as argument, now use
:warning-handlers options to set value for dynamic var
cljs.analyzer/*cljs-warning-handlers*.
  • Loading branch information
Deraen authored and dnolen committed Jul 28, 2015
1 parent 70d9405 commit 9e662c3
Show file tree
Hide file tree
Showing 5 changed files with 153 additions and 81 deletions.
87 changes: 53 additions & 34 deletions src/main/clojure/cljs/analyzer/api.clj
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@

(defn get-options
"Return the compiler options from compiler state."
[]
(get @env/*compiler* :options))
([] (get-options env/*compiler*))
([state]
(get @state :options)))

(defn analyze
"Given an environment, a map containing {:locals (mapping of names to bindings), :context
Expand All @@ -52,9 +53,13 @@
containing at least :form, :op and :env keys). If expr has any (immediately)
nested exprs, must have :children [exprs...] entry. This will
facilitate code walking without knowing the details of the op set."
([env form] (ana/analyze env form nil))
([env form name] (ana/analyze env form name nil))
([env form name opts] (ana/analyze env form name opts)))
([env form] (analyze env form nil))
([env form name] (analyze env form name nil))
([env form name opts] (analyze env/*compiler* env form name opts))
([state env form name opts]
(env/with-compiler-env state
(binding [ana/*cljs-warning-handlers* (:warning-handlers opts ana/*cljs-warning-handlers*)]
(ana/analyze env form name opts)))))

(defn forms-seq
"Seq of Clojure/ClojureScript forms from rdr, a java.io.Reader. Optionally
Expand All @@ -72,9 +77,13 @@
be used for *analyze-deps* and *load-macros* bindings respectively. This
function does _not_ side-effect the ambient compilation environment unless
requested via opts where :restore is false."
([src] (ana/parse-ns src nil nil))
([src opts] (ana/parse-ns src nil opts))
([src dest opts] (ana/parse-ns src dest opts)))
([src] (parse-ns src nil nil))
([src opts] (parse-ns src nil opts))
([src dest opts] (parse-ns env/*compiler* src dest opts))
([state src dest opts]
(env/with-compiler-env state
(binding [ana/*cljs-warning-handlers* (:warning-handlers opts ana/*cljs-warning-handlers*)]
(ana/parse-ns src dest opts)))))

(defn analyze-file
"Given a java.io.File, java.net.URL or a string identifying a resource on the
Expand All @@ -85,8 +94,12 @@
compiler options, if :cache-analysis true will cache analysis to
\":output-dir/some/ns/foo.cljs.cache.edn\". This function does not return a
meaningful value."
([f] (ana/analyze-file f nil))
([f opts] (ana/analyze-file f opts)))
([f] (analyze-file f nil))
([f opts] (analyze-file env/*compiler* f opts))
([state f opts]
(env/with-compiler-env state
(binding [ana/*cljs-warning-handlers* (:warning-handlers opts ana/*cljs-warning-handlers*)]
(ana/analyze-file f opts)))))

;; =============================================================================
;; Main API
Expand All @@ -105,53 +118,59 @@
(defn all-ns
"Return all namespaces. Analagous to clojure.core/all-ns but
returns symbols identifying namespaces not Namespace instances."
[]
(keys (get @env/*compiler* ::ana/namespaces)))
([] (all-ns env/*compiler*))
([state]
(keys (get @state ::ana/namespaces))))

(defn find-ns
"Given a namespace return the corresponding namespace analysis map. Analagous
to clojure.core/find-ns."
[sym]
{:pre [(symbol? sym)]}
(get-in @env/*compiler* [::ana/namespaces sym]))
([sym] (find-ns env/*compiler* sym))
([state sym]
{:pre [(symbol? sym)]}
(get-in @state [::ana/namespaces sym])))

(defn ns-interns
"Given a namespace return all the var analysis maps. Analagous to
clojure.core/ns-interns but returns var analysis maps not vars."
[ns]
{:pre [(symbol? ns)]}
(merge
(get-in @env/*compiler* [::ana/namespaces ns :macros])
(get-in @env/*compiler* [::ana/namespaces ns :defs])))
([ns] (ns-interns env/*compiler*))
([state ns]
{:pre [(symbol? ns)]}
(merge
(get-in @state [::ana/namespaces ns :macros])
(get-in @state [::ana/namespaces ns :defs]))))

(defn ns-publics
"Given a namespace return all the public var analysis maps. Analagous to
clojure.core/ns-publics but returns var analysis maps not vars."
[ns]
{:pre [(symbol? ns)]}
(->> (merge
(get-in @env/*compiler* [::ana/namespaces ns :macros])
(get-in @env/*compiler* [::ana/namespaces ns :defs]))
(remove (fn [[k v]] (:private v)))
(into {})))
([ns] (ns-publics env/*compiler*))
([state ns]
{:pre [(symbol? ns)]}
(->> (merge
(get-in @state [::ana/namespaces ns :macros])
(get-in @state [::ana/namespaces ns :defs]))
(remove (fn [[k v]] (:private v)))
(into {}))))

(defn ns-resolve
"Given a namespace and a symbol return the corresponding var analysis map.
Analagous to clojure.core/ns-resolve but returns var analysis map not Var."
[ns sym]
{:pre [(symbol? ns) (symbol? sym)]}
(get-in @env/*compiler* [::ana/namespaces ns :defs sym]))
([ns sym] (ns-resolve env/*compiler* ns sym))
([state ns sym]
{:pre [(symbol? ns) (symbol? sym)]}
(get-in @state [::ana/namespaces ns :defs sym])))

(defn remove-ns
"Removes the namespace named by the symbol."
[ns]
{:pre [(symbol? ns)]}
(swap! env/*compiler* update-in [::ana/namespaces] dissoc ns))
([ns] (remove-ns env/*compiler* ns))
([state ns]
{:pre [(symbol? ns)]}
(swap! state update-in [::ana/namespaces] dissoc ns)))

(defmacro in-cljs-user
"Binds cljs.analyzer/*cljs-ns* to 'cljs.user and uses the given compilation
environment atom and runs body."
[env & body]
`(binding [cljs.analyzer/*cljs-ns* 'cljs.user]
(cljs.env/with-compiler-env ~env
~@body)))
~@body)))
63 changes: 38 additions & 25 deletions src/main/clojure/cljs/build/api.clj
Original file line number Diff line number Diff line change
Expand Up @@ -56,23 +56,23 @@
ClojureScript namespaces that require and use the macros from
'example.macros :
(cljs-dependents-for-macro-namespaces 'example.macros) ->
('example.core 'example.util)
This must be called when cljs.env/*compiler* is bound to the
compile env that you are inspecting. See cljs.env/with-compile-env."
[namespaces]
(map :name
(let [namespaces-set (set namespaces)]
(filter (fn [x] (not-empty
(intersection namespaces-set (-> x :require-macros vals set))))
(vals (:cljs.analyzer/namespaces @env/*compiler*))))))
('example.core 'example.util)"
([namespaces] (cljs-dependents-for-macro-namespaces env/*compiler* namespaces))
([state namespaces]
(map :name
(let [namespaces-set (set namespaces)]
(filter (fn [x] (not-empty
(intersection namespaces-set (-> x :require-macros vals set))))
(vals (:cljs.analyzer/namespaces @state)))))))

(defn cljs-ns-dependents
"Given a namespace symbol return a seq of all dependent
namespaces sorted in dependency order. Will include
transient dependents."
[ns]
(ana/ns-dependents ns))
([ns] (cljs-ns-dependents env/*compiler* ns))
([state ns]
(env/with-compiler-env state
(ana/ns-dependents ns))))

(defn parse-js-ns
"Given a Google Closure style JavaScript file or resource return the namespace
Expand All @@ -84,15 +84,22 @@
(defn ^File src-file->target-file
"Given a ClojureScript source file return the target file. May optionally
provide build options with :output-dir specified."
([src] (closure/src-file->target-file src))
([src opts] (closure/src-file->target-file src opts)))
([src] (src-file->target-file src nil))
([src opts] (src-file->target-file env/*compiler* src opts))
([state src opts]
(env/with-compiler-env state
(binding [ana/*cljs-warning-handlers* (:warning-handlers opts ana/*cljs-warning-handlers*)]
(closure/src-file->target-file src opts)))))

(defn ^String src-file->goog-require
"Given a ClojureScript or Google Closure style JavaScript source file return
the goog.require statement for it."
([src] (closure/src-file->goog-require src))
([src options]
(closure/src-file->goog-require src options)))
([src] (src-file->goog-require src nil))
([src options] (src-file->goog-require env/*compiler* src options))
([state src options]
(env/with-compiler-env state
(binding [ana/*cljs-warning-handlers* (:warning-handlers options ana/*cljs-warning-handlers*)]
(closure/src-file->goog-require src options)))))

;; =============================================================================
;; Main API
Expand Down Expand Up @@ -156,8 +163,10 @@

(defn compile
"Given a Compilable, compile it and return an IJavaScript."
[opts compilable]
(closure/compile compilable opts))
([opts compilable] (compile env/*compiler* opts compilable))
([state opts compilable]
(env/with-compiler-env state
(closure/compile compilable opts))))

(defn output-unoptimized
"Ensure that all JavaScript source files are on disk (not in jars),
Expand All @@ -172,18 +181,22 @@
(defn build
"Given a source which can be compiled, produce runnable JavaScript."
([source opts]
(closure/build source opts))
(build source opts nil))
([source opts compiler-env]
(closure/build source opts compiler-env)))
(binding [ana/*cljs-warning-handlers* (:warning-handlers opts ana/*cljs-warning-handlers*)]
(closure/build source opts compiler-env))))

(defn watch
"Given a source which can be compiled, watch it for changes to produce."
([source opts]
(closure/watch source opts))
(watch source opts (if-not (nil? env/*compiler*)
env/*compiler*
(env/default-compiler-env opts))))
([source opts compiler-env]
(closure/watch source opts compiler-env))
(watch source opts compiler-env nil))
([source opts compiler-env stop]
(closure/watch source opts compiler-env stop)))
(binding [ana/*cljs-warning-handlers* (:warning-handlers opts ana/*cljs-warning-handlers*)]
(closure/watch source opts compiler-env stop))))

(comment

Expand All @@ -204,4 +217,4 @@
#(target-file-for-cljs-ns % "out-dev")
(env/with-compiler-env test-cenv
(ns-dependents 'clojure.string)))
)
)
52 changes: 31 additions & 21 deletions src/main/clojure/cljs/compiler/api.clj
Original file line number Diff line number Diff line change
Expand Up @@ -19,22 +19,30 @@

(defn emit
"Given an AST node generated by the analyzer emit JavaScript as a string."
[ast]
(with-out-str
(comp/emit ast)))
([ast] (emit env/*compiler* ast))
([state ast]
(env/with-compiler-env state
(with-out-str
(comp/emit ast)))))

(defn with-core-cljs
"Ensure that core.cljs has been loaded."
([] (comp/with-core-cljs nil))
([opts] (comp/with-core-cljs opts (fn [])))
([opts body] (comp/with-core-cljs opts body)))
([opts] (with-core-cljs opts (fn [])))
([opts body] (with-core-cljs env/*compiler* opts body))
([state opts body]
(env/with-compiler-env state
(binding [ana/*cljs-warning-handlers* (:warning-handlers opts ana/*cljs-warning-handlers*)]
(comp/with-core-cljs opts body)))))

(defn requires-compilation?
"Return true if the src file requires compilation."
([src dest]
(comp/requires-compilation? src dest nil))
([src dest opts]
(comp/requires-compilation? src dest opts)))
([src dest] (requires-compilation? src dest nil))
([src dest opts] (requires-compilation? env/*compiler* src dest opts))
([state src dest opts]
(env/with-compiler-env state
(binding [ana/*cljs-warning-handlers* (:warning-handlers opts ana/*cljs-warning-handlers*)]
(comp/requires-compilation? src dest opts)))))

(defn compile-file
"Compiles src to a file of the same name, but with a .js extension,
Expand All @@ -49,12 +57,13 @@
Returns a map containing {:ns .. :provides .. :requires .. :file ..}.
If the file was not compiled returns only {:file ...}"
([src]
(comp/compile-file src))
([src dest]
(comp/compile-file src dest))
([src dest opts]
(comp/compile-file src dest opts)))
([src] (compile-file src))
([src dest] (compile-file src dest))
([src dest opts] (compile-file env/*compiler* src dest opts))
([state src dest opts]
(env/with-compiler-env state
(binding [ana/*cljs-warning-handlers* (:warning-handlers opts ana/*cljs-warning-handlers*)]
(comp/compile-file src dest opts)))))

(defn cljs-files-in
"Return a sequence of all .cljs and .cljc files in the given directory."
Expand All @@ -67,9 +76,10 @@
directory mirroring the source directory structure. Returns a list
of maps containing information about each file which was compiled
in dependency order."
([src-dir]
(comp/compile-root src-dir "out"))
([src-dir target-dir]
(comp/compile-root src-dir target-dir nil))
([src-dir target-dir opts]
(comp/compile-root src-dir target-dir opts)))
([src-dir] (compile-root src-dir "out"))
([src-dir target-dir] (compile-root src-dir target-dir nil))
([src-dir target-dir opts] (compile-root env/*compiler* src-dir target-dir opts))
([state src-dir target-dir opts]
(env/with-compiler-env state
(binding [ana/*cljs-warning-handlers* (:warning-handlers opts ana/*cljs-warning-handlers*)]
(with-bindings (api-opts opts) (comp/compile-root src-dir target-dir opts))))))
28 changes: 28 additions & 0 deletions src/test/clojure/cljs/analyzer_api_tests.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
(ns cljs.analyzer-api-tests
(:require [cljs.analyzer.api :as ana-api])
(:use clojure.test))

(def warning-form
'(do (defn x [a b] (+ a b))
(x 1 2 3 4)))

(defn warning-handler [counter]
(fn [warning-type env extra]
(when (ana-api/warning-enabled? warning-type)
(swap! counter inc))))

(def test-cenv (atom {}))
(def test-env (ana-api/empty-env))

(deftest with-warning-handlers-test
(let [counter (atom 0)]
(ana-api/analyze test-cenv test-env warning-form nil
{:warning-handlers [(warning-handler counter)]})
(is (= 1 @counter))))

(deftest vary-warning-handlers-test
(let [counter (atom 0)]
(cljs.analyzer/all-warn
(ana-api/analyze test-cenv test-env warning-form nil
{:warning-handlers [(warning-handler counter)]}))
(is (= 1 @counter))))
4 changes: 3 additions & 1 deletion src/test/clojure/cljs/build_api_tests.clj
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,6 @@
'(bar.core baz.core)))
(is (= (env/with-compiler-env test-cenv
(cljs-ns-dependents 'graph.foo.core))
'(graph.bar.core graph.baz.core))))
'(graph.bar.core graph.baz.core)))
(is (= (cljs-ns-dependents test-cenv 'graph.foo.core)
'(graph.bar.core graph.baz.core))))

0 comments on commit 9e662c3

Please sign in to comment.