blob: 2da997589fe298134a63e08b288476f93d9ad2c2 (
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
(in-package #:parser)
(defun run (p input)
(let ((r (funcall p input)))
(if (parsing-p r)
(parsing-tree r)
(input::generate-report (failure-place r) (failure-message r)))))
(defstruct parsing
tree
left)
(defstruct failure
place
message)
(defstruct (normal-failure (:include failure)))
(defstruct (critical-failure (:include failure)))
(defun new (tree)
(lambda (input)
(make-parsing :tree tree :left input)))
(defun bind (p f)
(lambda (input)
(let ((r (funcall p input)))
(if (parsing-p r)
(funcall (funcall f (parsing-tree r)) (parsing-left r))
r))))
(defun discarding-bind (p q)
(lambda (input)
(let ((r (funcall p input)))
(if (parsing-p r)
(funcall q (parsing-left r))
r))))
(defun fail (&optional (message "Unknown error."))
(lambda (input)
(make-critical-failure :place input :message message)))
(defun either (first-parser second-parser &rest other-parsers)
(lambda (input)
(labels ((either-rec (body)
(if (cdr body)
(let ((r (funcall (car body) input)))
(if (normal-failure-p r)
(either-rec (cdr body))
r))
(funcall (car body) input))))
(either-rec (cons first-parser (cons second-parser other-parsers))))))
(defun unit (&optional (predicate #'characterp))
(lambda (input)
(if (input::has-data? input)
(let ((c (input::peek-1 input)))
(if (funcall predicate c)
(make-parsing :tree c :left (input::advance input))
(make-normal-failure :place input :message "Predicate not satisfied.")))
(make-normal-failure :place input :message "Reached end of input."))))
(defun literal (str)
(lambda (input)
(if (input::has-data? input (length str))
(let ((c (input::peek-n input (length str))))
(if (string= str c)
(make-parsing :tree c :left (input::advance input (length c)))
(make-normal-failure :place input :message "Predicate not satisfied.")))
(make-normal-failure :place input :message "Reached end of input."))))
(defmacro comp (bindings &body body)
(if (null bindings)
`(new (progn ,@body))
(let ((v (first (car bindings)))
(p (second (car bindings))))
(if (eq v '_)
`(discarding-bind ,p (comp ,(cdr bindings) ,@body))
`(bind ,p (lambda (,v) (comp ,(cdr bindings) ,@body)))))))
(defparameter nothing
(new nil))
(defun optional (p)
(either p nothing))
(defun zero-or-more (p)
(either (comp ((x p)
(xs (zero-or-more p)))
(cons x xs))
nothing))
(defun one-or-more (p)
(comp ((x p)
(xs (zero-or-more p)))
(cons x xs)))
(defun separated-list (p separator)
(comp ((v p)
(sep (optional (the-char separator)))
(vn (if sep
(either (separated-list p separator)
(fail "Value expected."))
nothing)))
(cons v vn)))
|