-
Notifications
You must be signed in to change notification settings - Fork 2
/
backend-util.rkt
130 lines (105 loc) · 2.96 KB
/
backend-util.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
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#lang racket/base
#|
Utilities useful for implementing compiler back ends.
|#
(require (for-syntax racket/base)
racket/contract/base
racket/file
racket/port
racket/pretty
racket/string
"util.rkt")
;;;
;;; data processing
;;;
(define* (space-join l)
(string-join l " "))
(define* (for-each-sep elemact sepact lst)
(define first #t)
(for-each
(lambda (elem)
(if first
(set! first #f)
(when sepact (sepact)))
(when elemact (elemact elem)))
lst))
(define* (display-as-string x)
(format "~a" x))
(define* (write-as-string x)
(format "~s" x))
;;;
;;; IO
;;;
(define-syntax on-fail
(syntax-rules ()
((_ fail-expr expr)
(with-handlers
((exn:fail?
(lambda (e) fail-expr)))
expr))))
(define* (file-read file)
(call-with-input-file*
file
(lambda (in)
(port->string in))))
;; Checks whether a file either does not exist or has been changed.
(define* (file-changed? file s)
;; Would there be a good way to write a function for comparing two
;; input streams? Then we could handle large files as well. ((nin
;; (open-input-string s))) and then compare to file input.
(on-fail #t (not (equal? (file-read file) s))))
(define (write-file-unconditionally file s)
(display-to-file s file #:exists 'truncate/replace))
(define (write-changed-file file s)
(when (file-changed? file s)
(write-file-unconditionally file s)))
(define* dont-touch-generated-file? (make-parameter #f))
(define (write-generated-file file s)
((if (dont-touch-generated-file?)
write-changed-file
write-file-unconditionally)
file s))
(define (capture-output f)
(let ((output (open-output-string)))
(parameterize ((current-output-port output))
(f))
(get-output-string output)))
(define* (write-generated-output path out writer)
(if out
(parameterize ((current-output-port out))
(writer))
(write-generated-file
path
(capture-output writer))))
;;;
;;; pretty printing
;;;
(define* (display-divider n [pfx #f] #:cols [cols #f])
(define margin (if pfx (+ (string-length pfx) 1) 0))
(define s-lst
(for/list ((i (in-range margin (+ n 1))))
(if cols (format "~a" (modulo i 10)) "-")))
(when pfx
(display pfx) (display " "))
(displayln (apply string-append s-lst)))
(define* (display-banner pfx filename)
(define n (let ((col (pretty-print-columns)))
(if (exact-positive-integer? col)
col 40)))
(display-divider n pfx)
(display pfx)
(display " ")
(displayln filename)
(display-divider n pfx #:cols #t))
(define* (display-generated-notice pfx)
(display pfx)
(displayln " generated -- do not edit"))
(define path-censor-re #rx"[^a-z0-9_]")
(define-with-contract*
(-> path-string? string?)
(path-h-ifdefy p)
(string-append
"__"
(regexp-replace* path-censor-re
(string-downcase (path-basename-as-string p)) "_")
"__"))