Anonymous avatar Anonymous committed 451184a

Add `until' option to `repeated'

Comments (0)

Files changed (2)

               (y (zero-or-more parser)))
     (result (cons x y))))
 
-(define (repeated parser #!key (min 0) max)
-  (let loop ((min min) (max max))
-    (any-of (sequence* ((x parser)
-                        (y (loop (- min 1)
-                                 (and max (- max 1)))))
-              (result (cons x y)))
-            (if (and (<= min 0) (or (not max) (>= max 0)))
-                (result '())
-                fail))))
+(define (repeated-until parser end)
+  (any-of (all-of end (result '()))
+          (sequence* ((x parser)
+                      (y (repeated-until parser end)))
+            (result (cons x y)))))
+
+(define (repeated* parser min max)
+  (any-of (sequence* ((x parser)
+                      (y (repeated* parser
+                                    (- min 1)
+                                    (and max (- max 1)))))
+            (result (cons x y)))
+          (if (and (<= min 0) (or (not max) (>= max 0)))
+              (result '())
+              fail)))
+
+(define (repeated parser #!key (min 0) max until)
+  (if until
+      (cond (max
+             (followed-by (repeated* parser min max) until))
+            ((zero? min)
+             (repeated-until parser until))
+            (else
+             (sequence* ((x (repeated* parser min min))
+                         (y (repeated-until parser until)))
+               (result (append x y)))))
+      (repeated* parser min max)))
 
 (define (maybe parser)
   (any-of parser (result #f)))
   (test-parse* "hohoho" (repeated (char-seq "ho")) "hohoho")
   (test-parse* "ho    ho ho "
                (repeated (sequence (char-seq "ho")
-                                     (zero-or-more (is #\space)))
-                           min: 2)
-               "ho    ho ho rofl"))
+                                   (zero-or-more (is #\space)))
+                         min: 2)
+               "ho    ho ho rofl")
+  (test-parse* "foo" (repeated item until: (is #\.)) "foo.")
+
+  (let ((ok (repeated item min: 3 until: (is #\k))))
+    (test-parse* "oko" ok "okok")
+    (test-parse* #f ok "ooko"))
+
+  (let ((ok (repeated item max: 2 until: (is #\k))))
+    (test-parse* "oo" ok "ookay")
+    (test-parse* #f ok "ooookay")))
 
 (test-group "all-of"
   (test-parse #\b (all-of (none-of (is #\a)) (is #\b)) "b")
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.