summaryrefslogtreecommitdiff
path: root/extra.lisp
blob: 4a67d84ce6628da354ee2b64c3dddca3c056e3e5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
(in-package #:monparser)

(defmacro literal (word)
  (when (not (stringp word))
    (error "Literal only accepts strings as input."))
  (let ((binding-list '())
        (name-list '()))
    (loop :for c :across word :do
          (when c
            (let ((name (gensym)))
              (push name name-list)
              (push `(,name (unit ,c)) binding-list))))
    `(comp ,(reverse binding-list)
           (coerce ,(cons 'list (reverse name-list)) 'string))))

(defparameter nothing
  (new nil))

(defun optional (p)
  (one-of p nothing))

(defun many (p)
  (comp ((x p)
         (xs (if x
               (optional (many p))
               (fail "Parsing result is empty."))))
        (cons x xs)))

(defun repeat (p min &optional (max 0))
  (if (> min 0)
    (comp ((x p)
           (xs (repeat p (1- min) (1- max))))
          (cons x xs))
    (if (> max 0)
      (comp ((x (optional p))
             (xs (repeat p 0 (if x (1- max) 0))))
            (if x (cons x xs) x))
      nothing)))

(defun whitespace? (x)
  (some (lambda (y) (char= x y)) '(#\Space #\Newline #\Return #\Tab)))

(defparameter whitespace
  (optional (many (unit whitespace?))))

(defun separated-list (p separator)
  (comp ((v p)
         (sep (optional separator))
         (vn (if sep
               (separated-list p separator)
               nothing)))
        (cons v vn)))

(defun surrounded (p left &optional right)
  (comp ((_ left)
         (body p)
         (_ (or right left)))
        body))