-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathoat.rkt
115 lines (100 loc) · 3.95 KB
/
oat.rkt
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
#lang racket/base
(require racket/contract
racket/file
racket/list
racket/match
racket/string)
(struct cond-section (title flag then else) #:transparent)
(struct uncond-section (title body) #:transparent)
(struct body (directives text next-opts) #:transparent)
(struct directive () #:transparent)
(struct set-flag-directive directive (flag) #:transparent)
(struct set-image-directive directive (image-name) #:transparent)
(struct next-opt (name label) #:transparent)
(define/contract (parse-section str)
(-> string? (or/c cond-section? uncond-section?))
(define title-line (first (string-split str "\n")))
(cond
[(string-prefix? title-line "# ")
(parse-uncond-section str)]
[(string-prefix? title-line "#? ")
(parse-cond-section str)]
[else (error 'missing-title-line (string-append "\n" str))]))
(define/contract (parse-uncond-section str)
(-> string? uncond-section?)
(define title-line (first (string-split str "\n")))
(define title (string-trim-prefix title-line "# "))
(define body-str (string-trim-prefix str title-line))
(uncond-section (parse-title title) (parse-body body-str)))
(define/contract (parse-cond-section str)
(-> string? cond-section?)
(define title-line (first (string-split str "\n")))
(define flag (string-trim-suffix
(string-trim-prefix
(last (string-split title-line " ")) "{") "}"))
(define title (string-trim-suffix
(string-trim-prefix title-line "#? ")
(string-append " {" flag "}")))
(define body-str (string-trim-prefix str title-line))
(define body-parts (string-split body-str "---"))
(unless (= 2 (length body-parts))
(error 'wrong-number-of-body-parts (string-append "\n" str)))
(cond-section (parse-title title)
(parse-flag flag)
(parse-body (first body-parts))
(parse-body (second body-parts))))
(define/contract (parse-body str)
(-> string? body?)
(define-values (directives textlines nexts)
(for/fold ([directives '()]
[textlines '()]
[nexts '()])
([line (string-split str "\n")])
(cond
[(string-prefix? line "(")
(values (cons (parse-directive line) directives)
textlines nexts)]
[(string-prefix? line "@")
(values directives textlines
(cons (parse-next-opt line) nexts))]
[else (values directives (cons line textlines) nexts)])))
(body (reverse directives)
(string-join (reverse textlines) "\n")
(reverse nexts)))
(define/contract (parse-directive str)
(-> string? directive?)
(match
(with-handlers ([exn:fail?
(λ (e) (error 'error-reading-directive
(string-append "\n" str)))])
(read (open-input-string str)))
[(list 'set-flag flag)
(set-flag-directive flag)]
[(list 'set-image image-name)
(set-image-directive image-name)]
[_ (error 'unknown-directive-type (string-append "\n" str))]))
(define/contract (parse-next-opt str)
(-> string? next-opt?)
(define name (string-trim-prefix
(first (string-split str " ")) "@"))
(define label (string-trim-suffix
(string-trim-prefix
str (string-append "@" name " [")) "]"))
(next-opt (parse-title name) label))
(define/contract (parse-title str)
(-> string? symbol?)
(if (string-contains? str " ")
(error 'bad-section-title (string-append "\n" str))
(string->symbol str)))
(define/contract (parse-flag str)
(-> string? symbol?)
(if (string-contains? str " ")
(error 'bad-flag-name (string-append "\n" str))
(string->symbol str)))
(define (string-trim-prefix str pre)
(string-trim str pre #:right? #f))
(define (string-trim-suffix str suf)
(string-trim str suf #:left? #f))
(define ex (file->string "test.oat.rkt"))
(define sections (string-split ex "\n\n"))
(map parse-section sections)