Skip to content

Commit

Permalink
Switch to edamame for side-effect-free parsing
Browse files Browse the repository at this point in the history
  • Loading branch information
NoahTheDuke committed May 15, 2024
1 parent faa1845 commit 6af8c97
Show file tree
Hide file tree
Showing 18 changed files with 69 additions and 40 deletions.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
1 change: 1 addition & 0 deletions corpus/read_eval.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
(if true (do #=(prn :hello :world!) :a))
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
#?(:clj (+ 1 1)
:cljs (+ 2 2)
:default (+ 3 3))

{:a 1 :b 2 #?@(:clj [:c 3 :d 4])}
File renamed without changes.
File renamed without changes.
File renamed without changes.
10 changes: 4 additions & 6 deletions deps.edn
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
{:paths ["src"]
:deps {org.clojure/clojure {:mvn/version "1.8.0"}
:deps {org.clojure/clojure {:mvn/version "1.11.1"}
org.clojure/core.logic {:mvn/version "1.1.0"}
org.clojure/tools.cli {:mvn/version "1.1.230"}
org.clojure/tools.reader {:mvn/version "1.4.2"}
borkdude/edamame {:mvn/version "1.4.25"}
rewrite-clj/rewrite-clj {:mvn/version "1.1.47"}}
;; At least Clojure v1.9 is required to run `clojure -X:`. Run this as
;; `clojure -X:exec` or `clojure -X:exec -i -r markdown`, for example.
:aliases {:exec {:extra-deps {org.clojure/clojure {:mvn/version "1.9.0"}
org.babashka/cli {:mvn/version "0.7.51"}}
;; Run this as `clojure -X:exec` or `clojure -X:exec -i -r markdown`, for example.
:aliases {:exec {:extra-deps {org.babashka/cli {:mvn/version "0.7.51"}}
:exec-fn kibit.driver/exec
:exec-args {:paths ["."]}
:main-opts ["-m" "babashka.cli.exec"]}}}
3 changes: 1 addition & 2 deletions project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
[org.clojure/core.logic "1.1.0"]
[org.clojure/tools.cli "1.1.230"]
[rewrite-clj "1.1.47"]
[org.clojure/tools.reader "1.4.2"]]
:profiles {:dev {:resource-paths ["test/resources"]}}
[borkdude/edamame "1.4.25"]]
:deploy-repositories [["clojars" {:url "https://clojars.org/repo"
:sign-releases false}]
["snapshots" :clojars]]
Expand Down
3 changes: 0 additions & 3 deletions src/kibit/check.clj
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,6 @@

;; The default resolution is overridden via the `merge`
(defn check-expr
""
[expr & kw-opts]
(let [{:keys [rules guard resolution]}
(merge default-args
Expand All @@ -175,7 +174,6 @@
(check-aux expr simplify-fn guard)))

(defn check-reader
""
[reader & kw-opts]
(let [{:keys [rules guard resolution init-ns]}
(merge default-args
Expand All @@ -190,7 +188,6 @@
{(resolve '*default-data-reader-fn*) (fn [tag val] val)}))

(defn check-file
""
[source-file & kw-opts]
(let [{:keys [rules guard resolution reporter init-ns]
:or {reporter reporters/cli-reporter}}
Expand Down
32 changes: 26 additions & 6 deletions src/kibit/check/reader.clj
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
(ns kibit.check.reader
(:require [clojure.tools.reader :as reader])
(:require [edamame.core :as e])
(:import [clojure.lang LineNumberingPushbackReader]))

;; Preprocessing
Expand Down Expand Up @@ -142,18 +142,38 @@ into the namespace."

(def eof (Object.))

(defn- make-edamame-opts [alias-map]
(e/normalize-opts
{:all true
:read_eval true
:eof eof
:row-key :line
:col-key :column
:end-row-key :end-line
:end-col-key :end-column
:end-location true
:features #{:clj :cljs}
:read-cond :allow
:readers (fn reader [r]
(fn reader-value [v]
(list r v)))
:auto-resolve (fn [x]
(if (= :current x)
*ns*
(get alias-map x)))}))

(defn read-file
"Generate a lazy sequence of top level forms from a
LineNumberingPushbackReader"
[^LineNumberingPushbackReader r init-ns]
(let [ns (careful-refer (create-ns init-ns))
do-read (fn do-read [ns alias-map]
(lazy-seq
(let [form (binding [*ns* ns
reader/*alias-map* (merge (ns-aliases ns)
(alias-map ns))]
(reader/read {:eof eof :read-cond :preserve} r))
[ns? new-ns k] (when (sequential? form) form)
(let [form (binding [*ns* ns]
(e/parse-next r (make-edamame-opts
(merge (ns-aliases ns)
(alias-map ns)))))
[ns? new-ns] (when (sequential? form) form)
new-ns (unquote-if-quoted new-ns)
ns (if (and (symbol? new-ns)
(#{'ns 'in-ns} ns?))
Expand Down
2 changes: 1 addition & 1 deletion src/kibit/driver.clj
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
(defn ends-with?
"Returns true if the java.io.File ends in any of the strings in coll"
[file coll]
(some #(.endsWith (.getName ^File file) %) coll))
(boolean (some #(.endsWith (.getName ^File file) %) coll)))

(defn clojure-file?
"Returns true if the java.io.File represents a Clojure source file.
Expand Down
56 changes: 34 additions & 22 deletions test/kibit/test/driver.clj
Original file line number Diff line number Diff line change
Expand Up @@ -6,32 +6,33 @@

(deftest clojure-file-are
(are [expected file] (= expected (driver/clojure-file? (io/file file)))
true "test/resources/first.clj"
true "test/resources/second.cljx"
true "test/resources/third.cljs"
false "test.resources/fourth.txt"))
true "corpus/first.clj"
true "corpus/second.cljx"
true "corpus/third.cljs"
false "corpus/fourth.txt"))

(deftest find-clojure-sources-are
(is (= [(io/file "test/resources/as_alias.clj")
(io/file "test/resources/double_pound_reader_macros.clj")
(io/file "test/resources/first.clj")
(io/file "test/resources/keyword_suggestions.clj")
(io/file "test/resources/keywords.clj")
(io/file "test/resources/namespaced_maps.clj")
(io/file "test/resources/reader_conditionals.cljc")
(io/file "test/resources/second.cljx")
(io/file "test/resources/sets.clj")
(io/file "test/resources/third.cljs")]
(driver/find-clojure-sources-in-dir (io/file "test/resources")))))
(is (= [(io/file "corpus/as_alias.clj")
(io/file "corpus/double_pound_reader_macros.clj")
(io/file "corpus/first.clj")
(io/file "corpus/keyword_suggestions.clj")
(io/file "corpus/keywords.clj")
(io/file "corpus/namespaced_maps.clj")
(io/file "corpus/read_eval.clj")
(io/file "corpus/reader_conditionals.cljc")
(io/file "corpus/second.cljx")
(io/file "corpus/sets.clj")
(io/file "corpus/third.cljs")]
(driver/find-clojure-sources-in-dir (io/file "corpus")))))

(deftest test-set-file
(is (driver/run ["test/resources/sets.clj"] nil)))
(is (driver/run ["corpus/sets.clj"] nil)))

(deftest test-keywords-file
(let [test-buf (ByteArrayOutputStream.)
test-err (PrintWriter. test-buf)]
(binding [*err* test-err]
(driver/run ["test/resources/keywords.clj"] nil))
(driver/run ["corpus/keywords.clj"] nil))
(is (zero? (.size test-buf))
(format "Test err buffer contained '%s'" (.toString test-buf)))))

Expand All @@ -45,7 +46,7 @@
{:alt (vec [:clojure.pprint/printing-key :resources.keyword-suggestions/local-key4 :some/other-key4])
:expr (into [] [:clojure.pprint/printing-key :resources.keyword-suggestions/local-key4 :some/other-key4])})
(map #(select-keys % [:expr :alt])
(driver/run ["test/resources/keyword_suggestions.clj"] nil "--reporter" "no-op")))))
(driver/run ["corpus/keyword_suggestions.clj"] nil "--reporter" "no-op")))))

(defmacro with-err-str
[& body]
Expand All @@ -57,10 +58,21 @@
(deftest process-reader-macros
(is (= ["" "" "" ""]
[(with-err-str
(driver/run ["test/resources/reader_conditionals.cljc"] nil))
(driver/run ["corpus/reader_conditionals.cljc"] nil "--reporter" "no-op"))
(with-err-str
(driver/run ["test/resources/double_pound_reader_macros.clj"] nil))
(driver/run ["corpus/double_pound_reader_macros.clj"] nil "--reporter" "no-op"))
(with-err-str
(driver/run ["test/resources/namespaced_maps.clj"] nil))
(driver/run ["corpus/namespaced_maps.clj"] nil "--reporter" "no-op"))
(with-err-str
(driver/run ["test/resources/as_alias.clj"] nil))])))
(driver/run ["corpus/as_alias.clj"] nil "--reporter" "no-op"))])))

(deftest no-read-eval-test
(is (= [{:expr
'(if true (do (edamame.core/read-eval (prn :hello :world!)) :a))
:line 1
:column 1
:end-line 1
:end-column 41
:alt '(when true (edamame.core/read-eval (prn :hello :world!)) :a)}]
(map #(dissoc % :file)
(driver/run ["corpus/read_eval.clj"] nil "--reporter" "no-op")))))

0 comments on commit 6af8c97

Please sign in to comment.