Skip to content

Commit cc65ad3

Browse files
arichiardiswannodette
authored andcommitted
CLJS-1515: Self-host: Allow :file key in cljs.js/*load-fn*
Bootstrapped ClojureScript is abstracted away from direct I/O by use of a *load-fn* callback. A result is that when a namespace is loaded, the :file attribute associated with def s in [:cljs.analyzer/namespaces 'foo.ns :defs] in the AST is nil, because cljs.analyzer/*cljs-file* cannot be set to a meaningful value. This ticket asks for an extension to *load-fn*, allowing a :file key to be optionally included by cljs.js clients, and for cljs.analyzer/*cljs-file* to be bound to that value in appropriate places in cljs.js so that the :file info appears in the AST. One rationale for this :file attribute is that it makes it easier for clients of cljs.js to look up the file for a def, say, for use when implementing a source REPL special, for example.
1 parent 60d5349 commit cc65ad3

File tree

2 files changed

+33
-7
lines changed

2 files changed

+33
-7
lines changed

src/main/cljs/cljs/js.cljs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@
7171
7272
:lang - the language, :clj or :js
7373
:source - the source of the library (a string)
74+
:file - optional, the file path, it will be added to AST's :file keyword
75+
(but not in :meta)
7476
:cache - optional, if a :clj namespace has been precompiled to :js, can
7577
give an analysis cache for faster loads.
7678
:source-map - optional, if a :clj namespace has been precompiled to :js, can
@@ -246,9 +248,9 @@
246248
(assert (or (map? resource) (nil? resource))
247249
"*load-fn* may only return a map or nil")
248250
(if resource
249-
(let [{:keys [lang source cache source-map]} resource]
251+
(let [{:keys [lang source cache source-map file]} resource]
250252
(condp = lang
251-
:clj (eval-str* bound-vars source name opts
253+
:clj (eval-str* bound-vars source name (assoc opts :cljs-file file)
252254
(fn [res]
253255
(if (:error res)
254256
(cb res)
@@ -379,9 +381,9 @@
379381
(assert (or (map? resource) (nil? resource))
380382
"*load-fn* may only return a map or nil")
381383
(if resource
382-
(let [{:keys [name lang source]} resource]
384+
(let [{:keys [name lang source file]} resource]
383385
(condp = lang
384-
:clj (analyze-str* bound-vars source name opts
386+
:clj (analyze-str* bound-vars source name (assoc opts :cljs-file file)
385387
(fn [res]
386388
(if-not (:error res)
387389
(analyze-deps bound-vars ana-env lib (next deps) opts cb)
@@ -517,7 +519,8 @@
517519
r/*alias-map* (current-alias-map)
518520
r/*data-readers* (:*data-readers* bound-vars)
519521
r/resolve-symbol resolve-symbol
520-
comp/*source-map-data* (:*sm-data* bound-vars)]
522+
comp/*source-map-data* (:*sm-data* bound-vars)
523+
ana/*cljs-file* (:cljs-file opts)]
521524
(let [res (try
522525
{:value (r/read {:eof eof :read-cond :allow :features #{:cljs}} rdr)}
523526
(catch :default cause
@@ -780,7 +783,8 @@
780783
r/*alias-map* (current-alias-map)
781784
r/*data-readers* (:*data-readers* bound-vars)
782785
r/resolve-symbol resolve-symbol
783-
comp/*source-map-data* (:*sm-data* bound-vars)]
786+
comp/*source-map-data* (:*sm-data* bound-vars)
787+
ana/*cljs-file* (:cljs-file opts)]
784788
(let [res (try
785789
{:value (r/read {:eof eof :read-cond :allow :features #{:cljs}} rdr)}
786790
(catch :default cause

src/test/self/self_host/test.cljs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
(:require [cljs.test :as test
33
:refer-macros [run-tests deftest testing is async]]
44
[cljs.js :as cljs]
5+
[cljs.analyzer :as ana]
56
[clojure.string :as string]
67
[cljs.nodejs :as nodejs]))
78

@@ -47,6 +48,27 @@
4748
(defn elide-env [env ast opts]
4849
(dissoc ast :env))
4950

51+
(defn var-ast
52+
"Given an already derefed compiler state plus the symbols of a
53+
namespace and a var (e.g. 'clojure.string and 'trim) , return the var
54+
AST representation or nil if not found, probably because not required
55+
yet.
56+
57+
The 1-arity function does the splitting in case of a fully qualified
58+
symbol (e.g. 'clojure.string/trim)."
59+
([st sym]
60+
(var-ast st (symbol (namespace sym)) (symbol (name sym))))
61+
([st ns-sym sym]
62+
(get-in st [:cljs.analyzer/namespaces ns-sym :defs sym])))
63+
64+
(defn file->lang
65+
"Converts a file path to a :lang keyword by inspecting the file
66+
extension."
67+
[file-path]
68+
(if (string/ends-with? file-path ".js")
69+
:js
70+
:clj))
71+
5072
(defn str-evals-to
5173
"Checks that a string evaluates to an expected value."
5274
([st l expected s]
@@ -750,7 +772,7 @@
750772
(str-evals-to st l [1 1 1 1 1]
751773
"(let [an-array (int-array 5 0)] (js->clj (amap an-array idx ret (+ 1 (aget an-array idx)))))" {:ns 'foo.core})))))
752774

753-
#_(deftest test-eval-str-with-require
775+
(deftest test-eval-str-with-require
754776
(async done
755777
(let [l (latch 3 done)]
756778
(cljs/eval-str st

0 commit comments

Comments
 (0)