about summary refs log tree commit diff stats
path: root/fff.parse.ss
blob: 0ff7806095e050442959ecb21c3ec45ebba2aa73 (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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
;;; Syntax
;; an fff document translates to a key-value object containing lists or other
;; objects.  Nesting objects are accomplished using references, which start with @.

;; # comments start with '#' and go to the end of the line.
;; fff-object::
;; key: value
;; key2: value2
;; key3: @reference # a reference refers to another defined object
;;
;; # lists are similar to objects, just without keys
;; fff-list::
;; : item1
;; : item2
;; : item3
;;
;; name: something # this is okay too

(import (scheme base)
        (scheme case-lambda)
        (utf8)
        (comparse)
        (srfi 14))

(define anything
  (in char-set:full))

(define nl+ws
  (sequence* ((_ (is #\newline))
              (_ ws*))
    (result " ")))

(define end
  (any-of nl+ws
          end-of-input))

(define end*
  (any-of (one-or-more nl+ws)
          end-of-input))

(define (escaped parser)
  (preceded-by (is #\\) parser))

(define (unescaped parser)
  (none-of* (escaped parser)
            parser))

(define ws
  (in char-set:blank))

(define ws*
  (zero-or-more ws))

(define nonl
  (in (char-set-delete char-set:full #\newline)))

(define fff-val
  (sequence* ((@? (maybe (escaped (is #\@))))
              (v (as-string
                  (zero-or-more
                   (any-of (escaped nl+ws)
                           (none-of* nl+ws item))))))
    (result (if @?
                (string-append "@" v)
                v))))

(define fff-key
  (as-string
   (one-or-more
    (all-of (any-of (escaped (is #\:))
                    (escaped nl+ws)
                    (none-of* (is #\:) nl+ws item))))))

(define fff-ref
  (sequence* ((_ (unescaped (is #\@)))
              (k fff-key))
    (result (cons 'ref k))))

(define fff-comment
  (sequence* ((_ (one-or-more (is #\#)))
              (_ ws*)
              (c (as-string (zero-or-more nonl)))
              (_ end*))
    (result (cons 'comment c))))

(define fff-comment+
  (bind (one-or-more fff-comment)
        (lambda (xs)
          (result (cons 'comment (map cdr xs))))))

(define fff-item
  (sequence* ((k (maybe fff-key))
              (_ ws*)
              (_ (is #\:))
              (_ ws*)
              (v (any-of fff-ref fff-val))
              (_ end))
    (result (cons k v))))

(define fff-item*
  (sequence* ((k fff-key)
              (_ ws*)
              (_ (is #\:))
              (_ ws*)
              (v (any-of fff-ref fff-val))
              (_ end*))
    (result (cons k v))))

(define fff-object
  (sequence* ((name fff-key)
              (_ ws*)
              (_ (sequence (is #\:) (is #\:) (is #\newline)))
              (contents (one-or-more
                         (any-of fff-comment+
                                 fff-item)))
              (_ end*))
    (result (cons name contents))))

(define fff-document
  (zero-or-more (any-of fff-comment+
                        fff-object
                        fff-item*)))

(define (parse-fff x)
  (parse fff-document x))