summaryrefslogtreecommitdiff
path: root/parzival.lisp
diff options
context:
space:
mode:
authorBoutade <thegoofist@protonmail.com>2019-04-25 20:39:38 -0500
committerBoutade <thegoofist@protonmail.com>2019-04-25 20:39:38 -0500
commitea4eb6812dc310b29dd4cdda344067c46c27e175 (patch)
tree8cdca8fcef6aa9c7dc2af8c1bf7fd90137bfc9f7 /parzival.lisp
parent4077fc0b2e2570ae32372691c274201d256cbe13 (diff)
renamed <<cons to <<map-cons and defined new <<cons
Diffstat (limited to 'parzival.lisp')
-rw-r--r--parzival.lisp59
1 files changed, 36 insertions, 23 deletions
diff --git a/parzival.lisp b/parzival.lisp
index 2e2953a..afe20d7 100644
--- a/parzival.lisp
+++ b/parzival.lisp
@@ -142,6 +142,8 @@ is the result of PN."
(<<bind p1 (lambda (ignore) p2))))
+
+
;;; 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
@@ -224,26 +226,48 @@ the character C."
(<<when (val p s) (<<result (funcall f val)))))
-(defun <<cons (x p)
- "If the parser P results in Y then the parser (<<CONS X P) results in
-(CONS X Y). If P fails, then so does (<<CONS X P)"
+(defun <<map-cons (x p)
+ "If the parser P results in Y then the parser (<<MAP-CONS X P) results in
+(CONS X Y). If P fails, then so does (<<MAP-CONS X P)"
(<<map (lambda (xs) (cons x xs)) p))
-(defun <<cons? (x p)
- "Like <<CONS except if the parser P fails, then the result is (CONS X NIL)"
- (<<cons x (<<? p)))
+(defun <<map-cons? (x p)
+ "Like <<MAP-CONS except if the parser P fails, then the result is (CONS X NIL)"
+ (<<map-cons x (<<? p)))
;;; PARSING SEQUENCES
+(defun <<cons (hd tl)
+ "Returns a parser that conses the result of parsing head to the result of
+ parsing tail, fails if either fails"
+ (<<bind hd
+ (lambda (head)
+ (<<map (lambda (tail) (cons head tail)) tl))))
+
(defun <<* (p)
"Runs the parser P zero or more times, resulting in of list of parsed values."
- (<<? (<<bind p (lambda (x) (<<cons x (<<* p))))))
+ (<<? (<<cons p (<<* p))))
(defun <<+ (p)
"Like <<* but fails if P does not succeed at least once."
- (<<bind p (lambda (x) (<<cons x (<<* p)))))
+ (<<cons p (<<* p)))
+
+
+(defun <<times (n p)
+ (if (<= n 0) (<<result nil)
+ (<<cons p (<<times (1- n) p))))
+
+(defun <<min-times (n p)
+ (if (<= n 0) (<<* p)
+ (<<cons p (<<min-times (1- n) p))))
+
+(defun <<max-times (n p)
+ (let ((count 0))
+ (<<bind (<<* (<<map (lambda (r) (incf count) r) p))
+ (lambda (results) (if (> count n) <fail<
+ (<<result results))))))
(defun <<sep-by (val-p sep-p)
@@ -252,8 +276,9 @@ E.g. (<<sep-by <digit< (<<char #\,)) would parse a string like '1,2,3,4' and
result the list in a list (#\1 #\2 #\3 #\4)"
(<<bind val-p
(lambda (val)
- (<<and sep-p
- (<<cons? val (<<sep-by val-p sep-p))))))
+ (<<or (<<and sep-p
+ (<<map-cons? val (<<sep-by val-p sep-p)))
+ (<<result (list val))))))
;;; VALUE PARSERS. The following section contains utilities for parsing common
@@ -275,7 +300,7 @@ result the list in a list (#\1 #\2 #\3 #\4)"
(read-from-string (concatenate 'string l)))
-(<<~def <nat< (<<map #'read-from-char-list (<<many1 <digit<))
+(<<~def <nat< (<<map #'read-from-char-list (<<+ <digit<))
"Parses a natural number.")
@@ -286,17 +311,5 @@ result the list in a list (#\1 #\2 #\3 #\4)"
<nat<)))
"Parses an integer")
-(<<~def <frac<
- (<<bind (<<char #\.)
- (lambda (dot)
- (<<map #'read-from-char-list
- (<<cons dot (<<many1 <digit<)))))
- "Parses a number like .123")
-
-(<<~def <real<
- (<<= (<<? (<<char #\-))
- (lambda (neg) (if neg (<<map (lambda (x) (* -1 x)) <nat<) <nat<))
- (lambda (whole) (<<map (lambda (frac) (+ frac whole)) <frac<)))
- "Parses a number like 123.456")