Skip to content

Commit

Permalink
[lang] improve compile-time error messages for unknown symbols
Browse files Browse the repository at this point in the history
  • Loading branch information
xificurC committed Sep 19, 2024
1 parent 31c2c33 commit 693bc48
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 46 deletions.
8 changes: 3 additions & 5 deletions src/hyperfiddle/electric/impl/lang3.clj
Original file line number Diff line number Diff line change
Expand Up @@ -336,17 +336,15 @@
(defn fail!
([env msg] (fail! env msg {}))
([env msg data] (throw (ex-info (str "\n" (get-ns env) (when-some [d (::def env)] (str "/" d)) ":" (-> env ::meta :line) ":" (-> env ::meta :column) "\n" msg)
(merge {:in (::def env) :for (or (::current env) ::unsited)} data)))))
(cond-> data (::def env) (assoc :in (::def env), (::current env) (assoc :for (::current env))))))))

(defn get-them [env] (-> env ::peers keys set (disj (::current env)) first))

(defn cannot-resolve! [env form]
(fail! env (str "I cannot resolve " "`"form"`"
(fail! env (str "I cannot resolve [" form "]"
(when-let [them (get-them env)]
(let [site (name them)]
(str ", maybe it's defined only on the " site "?"
\newline "If `" form "` is supposed to be a macro, you might need to :refer it in the :require-macros clause."))))
{:locals (keys (:locals env))}))
(str ", maybe it's only defined on the " site "?"))))))

(defn ns-qualify [node] (if (namespace node) node (symbol (str *ns*) (str node))))

Expand Down
62 changes: 21 additions & 41 deletions test/hyperfiddle/electric3_test.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -2004,47 +2004,6 @@
(tap [(.aPlus o 1) (.-a o)]))) tap tap)
% := [2 1])))

;; TODO cljs
#?(:clj
(skip "we capture invalid calls"
(binding [expand/*electric* true]
(try (lang/analyze (assoc (l/->local-config {}) ::lang/current :server ::lang/me :server) '(jjj 1))
(throw (Throwable. "shouldn't"))
(catch ExceptionInfo e
(ex-message e) := "in: (jjj 1)\nI cannot resolve `jjj`, maybe it's defined only on the client?\nIf `jjj` is supposed to be a macro, you might need to :refer it in the :require-macros clause."
(:form (ex-data e)) := 'jjj))

"in cc/fn"
(try (lang/analyze (assoc (l/->local-config {}) ::lang/current :server ::lang/me :server) '(fn [] (jjj 1)))
(throw (Throwable. "shouldn't"))
(catch ExceptionInfo e
(ex-message e) := "in: (jjj 1)\nI cannot resolve `jjj`, maybe it's defined only on the client?\nIf `jjj` is supposed to be a macro, you might need to :refer it in the :require-macros clause."
(:form (ex-data e)) := 'jjj))

"named cc/fn"
(try (lang/analyze (assoc (l/->local-config {}) ::lang/current :server ::lang/me :server) '(fn foo [] (jjj 1)))
(throw (Throwable. "shouldn't"))
(catch ExceptionInfo e
(ex-message e) := "in: (jjj 1)\nI cannot resolve `jjj`, maybe it's defined only on the client?\nIf `jjj` is supposed to be a macro, you might need to :refer it in the :require-macros clause."
(:form (ex-data e)) := 'jjj))

"in letfn"
(try (lang/analyze (assoc (l/->local-config {}) ::lang/current :server ::lang/me :server) '(letfn [(foo [] (jjj 1))]))
(throw (Throwable. "shouldn't"))
(catch ExceptionInfo e
(ex-message e) := "in: (jjj 1)\nI cannot resolve `jjj`, maybe it's defined only on the client?\nIf `jjj` is supposed to be a macro, you might need to :refer it in the :require-macros clause."
(:form (ex-data e)) := 'jjj))

"arbitrary symbols"
(try (lang/analyze (assoc (l/->local-config {}) ::lang/current :server ::lang/me :server)
'(let [x js/document.body]))
(catch ExceptionInfo e
(ex-message e) := "in: (let* [x js/document.body])\nI cannot resolve `js/document.body`, maybe it's defined only on the client?\nIf `js/document.body` is supposed to be a macro, you might need to :refer it in the :require-macros clause."
(:form (ex-data e)) := 'js/document.body))

"clj static field works"
(lang/analyze (assoc (l/->local-config {}) ::lang/current :server ::lang/me :server) 'clojure.lang.PersistentArrayMap/EMPTY))))

(tests "e/server e/client body"
(with ((l/single {} (tap (e/client 1 2))) tap tap)
% := 2))
Expand Down Expand Up @@ -2312,6 +2271,10 @@
(swap! !x inc) % := 3
(reset! !x false) % := :not)))

;;;;;;;;;;;;;;;;;;;;
;; ERROR MESSAGES ;;
;;;;;;;;;;;;;;;;;;;;

#?(:clj (defn clj-only [] :clj))
#?(:cljs
(tests (with ((l/single {} (tap (clj-only))) tap tap)
Expand All @@ -2327,3 +2290,20 @@
#?(:clj
(tests (with ((l/single {} (#(cljs-only))) tap tap)
(ex-message %) := "I cannot resolve [cljs-only], maybe it's only defined on the other peer?")))

#?(:clj
(tests (let [ex (try (lang/->source (merge (lang/normalize-env {}) e/web-config) `root '(e/fn [] (e/client (clj-only))))
(catch ExceptionInfo e e))]
(str/includes? (ex-message ex) "I cannot resolve [clj-only], maybe it's only defined on the server?") := true)))
#?(:clj
(tests (let [ex (try (lang/->source (merge (lang/normalize-env {}) e/web-config) `root '(e/fn [] (e/client #(clj-only))))
(catch ExceptionInfo e e))]
(str/includes? (ex-message ex) "I cannot resolve [clj-only], maybe it's only defined on the server?") := true)))
#?(:clj
(tests (let [ex (try (lang/->source (merge (lang/normalize-env {}) e/web-config) `root '(e/fn [] (e/server (cljs-only))))
(catch ExceptionInfo e e))]
(str/includes? (ex-message ex) "I cannot resolve [cljs-only], maybe it's only defined on the client?") := true)))
#?(:clj
(tests (let [ex (try (lang/->source (merge (lang/normalize-env {}) e/web-config) `root '(e/fn [] (e/server #(cljs-only))))
(catch ExceptionInfo e e))]
(str/includes? (ex-message ex) "I cannot resolve [cljs-only], maybe it's only defined on the client?") := true)))

0 comments on commit 693bc48

Please sign in to comment.