假设我在磁盘上有一个非常简单的.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?
答案 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)))