Commits

Steve Losh committed 0d8ab5e

Add separated and separated1 and tests, and clean up with them.

Comments (0)

Files changed (2)

src/dram/parser.clj

   (either (attempt p)
           (always nil)))
 
+(defparser separated1 [p separatorp]
+  (attempt
+    (let->> [fst p
+             rst (many (attempt (>> separatorp p)))]
+      (always (concat [fst] rst)))))
+
+(defparser separated [p separatorp]
+  (let->> [result (optional (separated1 p separatorp))]
+    (always (if (nil? result)
+              []
+              result))))
+
 
 ; Whitespace ------------------------------------------------------------------
 (defparser whitespace-char []
     (always (apply str contents))))
 
 (defparser path []
-  (let->> [seg (path-segment)
-           segs (many (>> (char \.) (path-segment)))]
-    (always (concat [seg] segs))))
+  (separated1 (path-segment) (char \.)))
 
 
 ; Context Values --------------------------------------------------------------
 
 (defparser value-filter-args []
   (char \:)
-  (let->> [arg (value-filter-arg)
-           args (many (>> (char \,) (value-filter-arg)))]
-    (always (concat [arg] args))))
+  (separated1 (value-filter-arg) (char \,)))
 
 (defparser value-filter []
   (char \|)

test/dram/test/parser.clj

 (ns dram.test.parser
   (:require [dram.parser :as p]
             [clojure.test :refer :all]
-            [the.parsatron :refer [run]]))
+            [the.parsatron :as parsatron :refer [run]]))
 
 
 (defmacro is-error [input parser]
     "42" 42
     "a"  nil))
 
+(deftest separator-test
+  (testing-parser
+    (p/separated1 (parsatron/digit) (parsatron/char \,))
+    "The separated1 parser parses items separated by things."
+
+    "1"     [\1]
+    "1,2"   [\1 \2]
+    "1,2,3" [\1 \2 \3])
+
+  (testing-parser
+    (p/separated1 (p/literal) (parsatron/char \,))
+    "Separated items can be complex."
+
+    "1"                  [1]
+    "42,\"hello world\"" [42 "hello world"])
+
+  (testing-parser-errors
+    (p/separated1 (p/literal) (parsatron/char \,))
+    "The separated1 parser requires at least one item."
+
+    ""
+    ",")
+
+  (testing-parser-errors
+    (parsatron/>>
+      (p/separated1 (p/literal) (parsatron/char \,))
+      (parsatron/eof))
+    "The separated1 parser doesn't allow garbage."
+
+    "dogs"
+    "1,,2")
+
+  (testing-parser
+    (p/separated (parsatron/digit) (parsatron/char \,))
+    "The separated parser is like separated1, but allows zero-length seqs."
+
+    "1"     [\1]
+    "1,2"   [\1 \2]
+    "1,2,3" [\1 \2 \3]
+    ""      [])
+
+  (testing-parser
+    (parsatron/>>
+      (p/separated (parsatron/digit) (parsatron/char \,))
+      (parsatron/char \!))
+    "The separated parser does not consume input if it fails."
+
+    "1!"   \!
+    "1,2!" \!
+    "!"    \!)
+
+  (testing-parser
+    (parsatron/either
+      (p/separated1 (parsatron/digit) (parsatron/char \,))
+      (parsatron/char \!))
+    "The separated1 parser does not consume input if it fails."
+
+    "1,2" [\1 \2]
+    "!"   \!)
+
+  (testing-parser
+    (parsatron/let->> [a (p/separated (parsatron/digit) (parsatron/char \,))
+                       b (parsatron/char \,)]
+                      (parsatron/always [a b]))
+    "A more complicated example of input consumption."
+
+    "1,2," [[\1 \2] \,]
+    "1,"   [[\1] \,]
+    ","    [[] \,]))
+
 (deftest whitespace-test
   (testing-parser
     (p/optional-whitespace) "Optional whitespace parses to nil."