forked from philhofer/distill
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathautodep.scm
172 lines (159 loc) · 5 KB
/
autodep.scm
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
(import
scheme
(chicken file)
(chicken string)
(chicken platform)
(chicken pretty-print))
(define mod-to-import
;; mutable, but these ones we know
;; in advance:
'((matchable . "matchable.import.scm")
((srfi 69) . "srfi-69.import.scm")))
(define (lib-name form)
(let ((n (cadr form)))
(cond
((symbol? n) (symbol->string n))
((list? n) (string-intersperse (map symbol->string n) "."))
(else (error "unexpected library name" n)))))
(define (lib-import form)
(string-append (lib-name form) ".import.scm"))
;; perform a left-associative fold
;; over forms beginning with the given symbol
(define (form-fold sym proc seed form)
(let loop ((lst (cddr form))
(state seed))
(if (null? lst)
state
(let ((head (car lst))
(rest (cdr lst)))
(if (pair? head)
(cond
((eq? (car head) sym)
(loop rest (proc state head)))
((eq? (car head) 'cond-expand)
;; walk each arm of the cond-expand until 'feature?' is #t
(let inner ((expr (cadr head)))
(cond
((null? expr)
(error "didn't match any cond-expand expression"))
((eq? (car expr) 'else)
(loop rest (loop (cdr expr) state)))
((and (symbol? (car expr)) (feature? (car expr)))
(loop rest (loop (cdr expr) state)))
;; TODO: match (and feature ...), (or feature ...)
(else (inner (cdr expr))))))
(else (loop rest state)))
(loop rest state))))))
;; strip away import modifiers
(define (unpack-import expr)
(if (and (pair? expr)
(memq (car expr)
'(only except rename prefix)))
(unpack-import (cadr expr))
expr))
;; TODO: need to walk cond-expand forms as well
(define (lib-imports form)
(form-fold
'import
(lambda (lst im)
(foldl
(lambda (lst iexpr)
(cons (unpack-import iexpr) lst))
lst
(cdr im)))
'()
form))
(define (lib-includes form)
(form-fold
'include
(lambda (lst inc)
(cons (cadr inc) lst))
'()
form))
(define (lib-depends form)
;; a library depends on locally-defined *.sld
;; files and anything that is (include)'d
(foldl
(lambda (lst im)
(let ((v (assoc im mod-to-import)))
(if v (cons (cdr v) lst) lst)))
(lib-includes form)
(lib-imports form)))
;; %.sld -> %.mod.scm
(define (modfile-name orig)
(string-append
(substring orig 0 (- (string-length orig)
(string-length ".sld")))
".mod.scm"))
(define (write-mod form modf)
(define (chicken-import expr)
;; normalize 'expr' to a non-R7RS chicken import
(if (pair? expr)
(case (car expr)
((srfi) (string->symbol (conc "srfi-" (cadr expr))))
((only rename prefix except)
(cons (car expr) (cons (chicken-import (cadr expr)) (cddr expr))))
(else expr))
expr))
;; walk top-level forms in a define-library
;; and rewrite imports as appropriate
(define (rewrite-sld-form expr)
(case (car expr)
((export) #f)
((import) (cons 'import (map chicken-import (cdr expr))))
((cond-expand) (cons 'cond-expand
(map (lambda (cpr)
(cons (car cpr) (map rewrite-sld-form (cdr cpr))))
(cdr expr))))
((include include-ci begin) expr)
(else expr)))
(with-output-to-file
modf
(lambda ()
(pp
`(module ,(cadr form)
,(form-fold
'export
(lambda (lst expr)
(append (cdr expr) lst))
'()
form)
,@(let loop ((rest (cddr form)))
(if (null? rest)
'()
(let ((v (rewrite-sld-form (car rest))))
(if v (cons v (loop (cdr rest))) (loop (cdr rest)))))))))))
(define slds
(map
(lambda (f)
(let ((form (call-with-input-file f (cut read <>))))
(unless (eq? (car form) 'define-library)
(error "expected define-library form in" f))
(set! mod-to-import
(cons
(cons (cadr form) (lib-import form))
mod-to-import))
(let ((modfile (modfile-name f)))
(write-mod form modfile)
(cons (cons f modfile) form))))
(glob "*.sld")))
(display "# generated by autodep.scm\n")
(for-each
(lambda (sld)
(let* ((form (cdr sld))
(filep (car sld))
(sldf (car filep))
(modf (cdr filep))
(deps (lib-depends form))
(name (lib-name form)))
(display modf)
(display ": ")
(display sldf)
(newline)
(display (string-append name ".import.scm "))
(display (string-append name ".c: "))
(display modf)
(display " ")
(display (string-intersperse deps " "))
(newline)))
slds)