Permalink
Browse files

Extract parsing to its own ns

  • Loading branch information...
trptcolin committed Apr 5, 2013
1 parent 386c936 commit 901780154d7158690ecfd23728e22963d277dc7b
@@ -1,44 +1,44 @@
-(ns reply.eval-modes.nrepl-spec
+(ns reply.parsing-spec
(:use [speclj.core]
- [reply.eval-modes.nrepl]))
+ [reply.parsing]))
(describe "parsed-forms"
(with eof (Object.))
- (around [it]
- (with-redefs [safe-read-line (fn [state] (read-line))]
- (it)))
+ (with read-line-fn (fn [state] (read-line)))
+ (with options {:request-exit @eof :read-line-fn @read-line-fn})
(it "gets an eof when readLine says it's done"
(should= [@eof]
(with-in-str ""
- (doall (parsed-forms {:request-exit @eof})))))
+ (doall (parsed-forms @options)))))
(it "gets one form"
(should= ["foo"]
(with-in-str "foo"
- (doall (parsed-forms {:request-exit @eof})))))
+ (doall (parsed-forms @options)))))
(it "gets multiline forms"
(should= ["(+ 1 2\n3)"]
(with-in-str "(+ 1 2\n3)"
- (doall (parsed-forms {:request-exit @eof})))))
+ (doall (parsed-forms @options)))))
(it "gets multiline forms, with overlap"
(should= ["(+ 1 2\n3)" "(- 3\n1)"]
(with-in-str "(+ 1 2\n3) (- 3\n1)"
- (doall (parsed-forms {:request-exit @eof})))))
+ (doall (parsed-forms @options)))))
(it "gets multiple forms on a single line"
(should= ["1" "2" "3"]
(with-in-str "1 2 3"
- (doall (parsed-forms {:request-exit @eof})))))
+ (doall (parsed-forms @options)))))
(it "gets an empty couple of lines"
(should= [""]
(with-in-str "\n\n"
- (doall (parsed-forms {:request-exit @eof})))))
+ (doall (parsed-forms @options)))))
(it "gets whitespace"
(should= [""]
(with-in-str " \n \n"
- (doall (parsed-forms {:request-exit @eof}))))))
+ (doall (parsed-forms @options))))))
+
@@ -10,11 +10,10 @@
[reply.exit]
[reply.eval-state :as eval-state]
[reply.initialization]
+ [reply.parsing :as parsing]
[reply.reader.simple-jline :as simple-jline]
[reply.reader.jline.completion :as jline.completion]
- [reply.signals :as signals]
- [net.cgrand.sjacket :as sjacket]
- [net.cgrand.sjacket.parser :as sjacket.parser]))
+ [reply.signals :as signals]))
(def current-command-id (atom nil))
(def current-session (atom nil))
@@ -85,50 +84,6 @@
(reset! current-command-id nil)
@current-ns))
-(defn parsed-forms [{:keys [ns request-exit text-so-far
- prompt-string input-stream] :as options}]
- (if-let [next-text (safe-read-line {:ns ns
- :input-stream input-stream
- :prompt-string prompt-string})]
- (let [interrupted? (= :interrupted next-text)
- parse-tree (when-not interrupted?
- (sjacket.parser/parser
- (if text-so-far
- (str text-so-far \newline next-text)
- next-text)))]
- (if (or interrupted? (empty? (:content parse-tree)))
- (list "")
- (let [completed?
- (fn [node]
- (or (not= :net.cgrand.parsley/unfinished (:tag node))
- (some #(= :net.cgrand.parsley/unexpected (:tag %))
- (tree-seq :tag :content node))))
- complete-forms (take-while completed? (:content parse-tree))
- remainder (drop-while completed? (:content parse-tree))
- form-strings (map sjacket/str-pt
- (remove #(contains?
- #{:whitespace :comment :discard}
- (:tag %))
- complete-forms))]
- (cond (seq remainder)
- (lazy-seq
- (concat form-strings
- (parsed-forms
- (assoc options
- :text-so-far
- (apply str (map sjacket/str-pt
- remainder))
- :prompt-string
- (apply str (concat (repeat (- (count prompt-string)
- (count "#_=> "))
- \space)
- "#_=> "))))))
- (seq form-strings)
- form-strings
- :else
- (list "")))))
- (list request-exit)))
-
(defn- handle-ns-init-error [ns connection options]
(if (= ns "reply.eval-modes.nrepl")
(let [fallback-ns
@@ -149,10 +104,12 @@
eof (Object.)
execute (partial execute-with-client connection
(assoc options :interactive true))
- forms (parsed-forms {:request-exit eof
- :prompt-string (prompt ns)
- :ns ns
- :text-so-far nil})]
+ forms (parsing/parsed-forms
+ {:request-exit eof
+ :prompt-string (prompt ns)
+ :ns ns
+ :read-line-fn safe-read-line
+ :text-so-far nil})]
(if (reply.exit/done? eof (first forms))
nil
(recur (last (doall (map execute forms))))))))))
View
@@ -0,0 +1,66 @@
+(ns reply.parsing
+ (:require [net.cgrand.sjacket :as sjacket]
+ [net.cgrand.sjacket.parser :as sjacket.parser]))
+
+(defn node-completed? [node]
+ (or (not= :net.cgrand.parsley/unfinished (:tag node))
+ (some #(= :net.cgrand.parsley/unexpected (:tag %))
+ (tree-seq :tag :content node))))
+
+(defn subsequent-prompt-string [prompt-string]
+ (apply str (concat (repeat (- (count prompt-string)
+ (count "#_=> "))
+ \space)
+ "#_=> ")))
+
+(defn remove-whitespace [forms]
+ (remove #(contains? #{:whitespace :comment :discard} (:tag %))
+ forms))
+
+(defn reparse [text-so-far next-text]
+ (sjacket.parser/parser
+ (if text-so-far
+ (str text-so-far \newline next-text)
+ next-text)))
+
+(declare parsed-forms)
+
+(defn process-parse-tree [parse-tree {:keys [prompt-string] :as options}]
+ (let [complete-forms (take-while node-completed? (:content parse-tree))
+ remainder (drop-while node-completed? (:content parse-tree))
+ form-strings (map sjacket/str-pt
+ (remove-whitespace complete-forms))]
+ (cond
+ (seq remainder)
+ (lazy-seq
+ (concat form-strings
+ (parsed-forms
+ (assoc options
+ :text-so-far
+ (apply str (map sjacket/str-pt remainder))
+ :prompt-string
+ (subsequent-prompt-string prompt-string)))))
+ (seq form-strings)
+ form-strings
+ :else
+ (list ""))))
+
+(defn parsed-forms
+ "Requires the following options:
+ - request-exit: the value to return on completion/EOF
+ - read-line-fn: a function that takes an options map that will include :ns
+ and :prompt-string.
+ - ns: the current ns, available because it can be useful for read-line-fn
+ - prompt-string: for customizing the prompt
+ - text-so-far: mostly useful in the recursion"
+ [{:keys [ns request-exit text-so-far
+ prompt-string read-line-fn] :as options}]
+ (if-let [next-text (read-line-fn {:ns ns :prompt-string prompt-string})]
+ (let [interrupted? (= :interrupted next-text)
+ parse-tree (when-not interrupted? (reparse text-so-far next-text))]
+ (if (or interrupted? (empty? (:content parse-tree)))
+ (list "")
+ (process-parse-tree parse-tree options)
+ ))
+ (list request-exit)))
+

0 comments on commit 9017801

Please sign in to comment.