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

时间:2016-10-11 11:55:16

标签: clojure

假设我在磁盘上有一个非常简单的.clj文件,其中包含以下内容:

(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.在slurp上使用(io/file file-name.clj)生成包含文件内容的字符串,2。将该字符串传递给Clojure代码的解析器,以及3。将解析器生成的序列注入列表(即(into '() parsed-code))。

然而,这种方法似乎有点笨拙且容易出错。 是否有人知道将Clojure文件作为S-Expressions列表读取更优雅和/或惯用的方式?

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

=> (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\n  (:gen-class)\n  (:require [clj-antlr.core :as antlr]))\n\n(def foo 42)\n\n(defn parse-program\n  \"uses antlr grammar to \"\n  [program]\n  ((antlr/parser \"src/grammars/Clojure.g4\") program))\n\n\n(defn -main\n  \"I don't do a whole lot ... yet.\"\n  [& args]\n  (println \"tlc is tcl\"))\n"}
nil

有谁知道如何将此输出转换为最初预期的S-Expressions列表?也就是说,如何从clj解析结果中挤出有效的Clojure代码/数据? -antlr?

2 个答案:

答案 0 :(得分:4)

(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)

你需要这样的东西吗?

(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)))