读取另一个Clojure程序作为S表达式的列表

Reading another Clojure program as a list of S-Expressions

假设我的磁盘上有一个非常简单的.clj文件,内容如下:

1
2
3
4
(def a 2)
(def b 3)
(defn add-two [x y] (+ x y))
(println (add-two a b))

从单独的程序的上下文来看,我想将以上程序作为S-Expressions '((def a 2) (def b 3) ... (add-two a b)))的列表阅读。

我想一种解决方法包括1.在(io/file file-name.clj)上使用slurp生成包含文件内容的字符串,2.将字符串传递给Clojure代码的解析器,以及3.注入解析器生成的序列到列表(即(into '() parsed-code))。

但是,这种方法似乎笨拙且容易出错。有谁知道一种更优雅和/或更惯用的方式将Clojure文件读取为S表达式列表吗?

更新:根据评论部分的反馈,我决定尝试使用aphyr的clj-antlr在实际源文件中提到的方法,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
=> (def file-as-string (slurp (clojure.java.io/file"src/tcl/core.clj")))
=> tcl.core=> (pprint (antlr/parser"src/grammars/Clojure.g4" file-as-string))
{:parser
 {:local
  #object[java.lang.ThreadLocal 0x5bfcab6"java.lang.ThreadLocal@5bfcab6"],
  :grammar
  #object[org.antlr.v4.tool.Grammar 0x5b8cfcb9"org.antlr.v4.tool.Grammar@5b8cfcb9"]},
 :opts
"(ns tcl.core\
  (:gen-class)\
  (:require [clj-antlr.core :as antlr]))\
\
(def foo 42)\
\
(defn parse-program\
  \"uses antlr grammar to \"\
  [program]\
  ((antlr/parser \"src/grammars/Clojure.g4\") program))\
\
\
(defn -main\
  \"I don't do a whole lot ... yet.\"\
  [& args]\
  (println \"tlc is tcl\"))\
"}
nil

有谁知道如何将此输出转换为原本打算的S表达式列表?也就是说,如何用clj-antlr的解析结果来压缩有效的Clojure代码/数据?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
(import '[java.io PushbackReader])
(require '[clojure.java.io :as io])
(require '[clojure.edn :as edn])

;; adapted from: http://stackoverflow.com/a/24922859/6264
(defn read-forms [file]
  (let [rdr (-> file io/file io/reader PushbackReader.)
        sentinel (Object.)]
    (loop [forms []]
      (let [form (edn/read {:eof sentinel} rdr)]
        (if (= sentinel form)
          forms
          (recur (conj forms form)))))))

(comment
  (spit"/tmp/example.clj"
       "(def a 2)
(def b 3)
(defn add-two [x y] (+ x y))
(println (add-two a b))")

  (read-forms"/tmp/example.clj")
  ;;=> [(def a 2) (def b 3) (defn add-two [x y] (+ x y)) (println (add-two a b))]
)


你需要这样的东西吗?

1
2
3
4
5
6
7
8
(let [exprs (slurp"to_read.clj")]
  ;; adding braces to form a proper list
  (-> (str"("  (str  exprs")"))
  ;; read-string is potentially harmful, since it evals the string
  ;; there exist non-evaluating readers for clojure but I don't know
  ;; which one are good
      (read-string)
      (prn)))