blob: 30c68fd80ead56789efc2924f3f447ba815a8f65 (
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
|
(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)
(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 fail (&optional (message "Unknown error."))
(lambda (input)
(make-failure :place input :message message)))
(defun either (first-parser &rest other-parsers)
(lambda (input)
(labels ((either-rec (body)
(if (cdr body)
(let ((r (funcall (car body) input)))
(if (parsing-p r)
r
(either-rec (cdr body))))
(funcall (car body) input))))
(either-rec (cons first-parser other-parsers)))))
(defun unit (&optional (predicate #'characterp))
(lambda (input)
(if (input::has-data? input)
(let ((c (input::element input)))
(if (funcall predicate c)
(make-parsing :tree c :left (input::advance input))
(make-failure :place input :message "Predicate not satisfied.")))
(make-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 '_)
`(bind ,p (lambda () (comp ,(cdr bindings) ,@body)))
`(bind ,p (lambda (,v) (comp ,(cdr bindings) ,@body)))))))
(defparameter nothing
(new nil))
(defun zero-or-one (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)))
|