diff options
author | Boutade <thegoofist@protonmail.com> | 2020-03-06 20:58:00 -0600 |
---|---|---|
committer | Boutade <thegoofist@protonmail.com> | 2020-03-06 20:58:00 -0600 |
commit | 1181af61564962efcd3cfcfcb651371d86e86714 (patch) | |
tree | a809a1d29bd00be6d1a7955a54291e61d8393c67 /parzival.lisp | |
parent | f448fcdb3319e74644d66c671c30c232d770615f (diff) |
added <<until combinator
Diffstat (limited to 'parzival.lisp')
-rw-r--r-- | parzival.lisp | 21 |
1 files changed, 20 insertions, 1 deletions
diff --git a/parzival.lisp b/parzival.lisp index 35d6304..d00a1d4 100644 --- a/parzival.lisp +++ b/parzival.lisp @@ -119,6 +119,26 @@ in then. If the parse fails the combinator else is run instead." (rewind-to stream chkpt) parser2))))) +(defun <<until (parser) + "Consumes the stream one character at a time until PARSER succeeds. The parse + value of (<<UNTIL PARSER) is a list of the characters consumed, ending in the + value parsed by PARSER." + (lambda (stream) + (let ((collected nil)) + (labels ((rec (stream) + (let ((chkpt (replay-streams:checkpoint stream))) + (<<if (result parser stream) + (progn + (replay-streams:free-checkpoint stream chkpt) + (<<result (reverse (cons result collected)))) + (progn + (replay-streams:rewind-to stream chkpt) + (<<bind <item< + (lambda (item) + (push item collected) + #'rec))))))) + (rec stream))))) + (defun <<or (&rest parsers) "Tries each parser one after the other, rewinding the input stream after each failure, and resulting in the first successful parse." @@ -200,7 +220,6 @@ in then. If the parse fails the combinator else is run instead." (lambda (result) (<<map (returning result) <eof<)))) - ;;; PARSING INDIVIDUAL ITEMS from the stream. The basic parser thats of any real ;;; use is <<sat. It lets you check that a stream item meets some kind of ;;; condition, and fails to parse if it does not. The follwing section contains |