readit

Tooling for managing structured reading notes for scientific publications

git clone https://git.8pit.net/readit.git

  1(module (readit parser)
  2  (make-meta meta-state meta-key meta-title parse-fields
  3   parse-readit readit-ref? readit-set? parse-indent parse-note parse-notes)
  4  (import scheme (chicken base) comparse srfi-1 srfi-14)
  5
  6  (define-record-type metadata
  7    (make-meta state key title)
  8    metadata?
  9    (state meta-state)
 10    (key meta-key)
 11    (title meta-title))
 12
 13  (define-record-printer (metadata input port)
 14    (define (join . strings)
 15      (fold (lambda (str output)
 16              (string-append
 17                (if (zero? (string-length output))
 18                  output
 19                  (string-append output " ")) str)) "" strings))
 20
 21    (display (join
 22               (string (meta-state input))
 23               (string-append "[" (symbol->string (meta-key input)) "]:")
 24               (meta-title input))))
 25
 26  (define symbol-charset
 27    (char-set-union
 28      char-set:letter
 29      char-set:digit
 30      (->char-set "!$%&*+-./:<=>?@^_~")))
 31
 32  (define symbol-charset-start
 33    (char-set-difference symbol-charset char-set:digit))
 34
 35  ;;;;
 36  ;; Utility functions
 37  ;;;;
 38
 39  (define parse-symbol
 40    (bind (as-string (all-of
 41                       (in symbol-charset-start)
 42                       (zero-or-more (in symbol-charset))))
 43          (lambda (str) (result (string->symbol str)))))
 44
 45  (define (parse-any-except char . chars)
 46    (as-string (one-or-more
 47      (in (char-set-complement (list->char-set
 48                                  (cons char chars)))))))
 49
 50  (define parse-indent
 51    (any-of
 52      (is #\tab)
 53      (repeated (is #\space) min: 4 max: 4)))
 54
 55  (define parse-blanks
 56    (zero-or-more (in char-set:blank)))
 57
 58  (define parse-text
 59    (parse-any-except #\newline))
 60
 61  ;;;;
 62  ;; Parser for literals
 63  ;;;;
 64
 65  (define (parse-escaped ctrl-chars)
 66    (define parse-char
 67      (any-of
 68        (sequence* ((_ (is #\\))
 69                    (i item))
 70          (result i))
 71        (in (char-set-complement (list->char-set ctrl-chars)))))
 72
 73    (as-string (one-or-more parse-char)))
 74
 75  (define (parse-vector parser)
 76    (define (parse-vector*)
 77      (one-or-more
 78        (sequence* ((elem parser)
 79                    (_    (maybe (is #\,)))
 80                    (_    parse-blanks))
 81          (result elem))))
 82
 83    (bind (parse-vector*)
 84          (lambda (lst)
 85            (result (list->vector lst)))))
 86
 87  (define parse-set
 88    (enclosed-by (is #\{)
 89                 (parse-vector (parse-escaped '(#\, #\})))
 90                 (is #\})))
 91
 92  (define parse-ref
 93    (enclosed-by (is #\[)
 94                 (parse-vector parse-symbol)
 95                 (is #\])))
 96
 97  ;;;;
 98  ;; Parsers for entry parts
 99  ;;;;
100
101  (define parse-state
102    (in (string->char-set "-x")))
103
104  (define parse-key
105    (enclosed-by (is #\[) parse-symbol (is #\])))
106
107  (define parse-title
108    parse-text)
109
110  ;;;;
111  ;; Parsers for optional field values
112  ;;;;
113
114  (define parse-field-name
115    (parse-any-except #\:))
116
117  (define parse-field-value
118    (any-of
119      parse-set
120      parse-ref
121      parse-text))
122
123  (define parse-field
124    (sequence* ((_     parse-indent)
125                (_     (is #\*))
126                (_     parse-blanks)
127                (name  parse-field-name)
128                (_     (is #\:))
129                (_     parse-blanks)
130                (value parse-field-value)
131                (_     parse-blanks)
132                (_     (is #\newline)))
133      (result (cons name value))))
134
135  (define parse-fields
136    (zero-or-more parse-field))
137
138  ;;;;
139  ;; Parser for optional notes
140  ;;;;
141
142  (define parse-note
143    (sequence* ((_    parse-indent)
144                (text parse-text)
145                (_    (one-or-more (is #\newline))))
146      (result (string-append text "\n"))))
147
148  (define parse-notes
149    (as-string (zero-or-more parse-note)))
150
151  ;;;;
152  ;; Combine utility parsers
153  ;;;;
154
155  (define parse-info
156    (sequence* ((fields (maybe parse-fields '()))
157                (notes  (maybe (preceded-by
158                                 (is #\newline)
159                                 parse-notes) "")))
160      (result (list fields notes))))
161
162  (define parse-entry
163    (sequence* ((state  parse-state)
164                (_      parse-blanks)
165                (key    parse-key)
166                (_      (is #\:))
167                (_      parse-blanks)
168                (title  parse-title)
169                (_      (is #\newline))
170                (info   (maybe parse-info (list '() '()))))
171      (result (cons (make-meta state key title) info))))
172
173  (define parse-entries
174    (one-or-more (preceded-by
175                   (zero-or-more (in char-set:whitespace))
176                   parse-entry)))
177
178  ;;;;
179  ;; Interface functions
180  ;;;;
181
182  (define (readit-ref? obj)
183    (and (vector? obj)
184         (>= (vector-length obj) 1)
185         (every symbol? (vector->list obj))))
186
187  (define (readit-set? obj)
188    (and (vector? obj)
189         (>= (vector-length obj) 1)
190         (every string? (vector->list obj))))
191
192  (define (parse-readit input)
193    (parse (sequence* ((r parse-entries)
194                       (_ end-of-input))
195           (result r)) input)))