summaryrefslogtreecommitdiff
path: root/extra.lisp
blob: 2963e94a0f05a534ec8dce8fdc0579ec5263d31f (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
59
60
61
62
(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 (not x)
               (fail "Parsing result is empty.")
               (optional (many p)))))
        (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 #\Tab)))

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

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

(defun surrounded (left p right &key include-surrounding)
  (comp ((l left)
         (body p :lazy)
         (r right))
        (if include-surrounding
          (list l body r)
          body)))