-
Notifications
You must be signed in to change notification settings - Fork 15
/
Copy pathmodulesys.shen
286 lines (228 loc) · 8.72 KB
/
modulesys.shen
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
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
\* modulesys - public domain module system for Shen
## Description
Module system is a tool for managing Shen libraries.
## Basic usage
* `(module.use [Mod1 ...])` or `(use-modules [Mod1 ...])`
loads given modules with all their dependencies. Any module already loaded
won't be loaded twice.
* `(module.reload Mod1)`
reloads given module.
* `(module.files-to-translate Mod Language Implementation)`
returns a list of module Mod files to translate which can be passed to
a language dependent translator. Note that it loads module with all its
dependencies first.
* `(module.add-path Dir)`
adds directory to a list where modules are searched.
## Module definition
Sample contents of `mod1/module.shen` where `mod1` is module name:
(register-module [[load: "file1" "file2"]
[depends: "mod3" mod4]])
*\
(package module [use-modules load/tc register-module
name depends translate-depends load translate load-fn
unload-fn translate-fn]
(set *paths* [])
(set *list* [])
(set *db* (trap-error (shen.dict 256) (/. _ (vector 256))))
(set *fields* [path load translate depends translate-depends load-fn unload-fn
translate-fn])
(define add-path
X -> (set *paths* [X | (value *paths*)])
where (not (element? X (value *paths*))))
(define rm-path
X -> (set *paths* (remove X (value *paths*))))
(define normalize-id
X -> X where (string? X)
X -> (str X) where (symbol? X))
(define normalize-ids
X -> (map (function normalize-id) X) where (cons? X)
X -> [(normalize-id X)])
(define add-field
M Field Data Db -> (do (put M fields (adjoin Field (get M fields Db)) Db)
(put M Field Data Db)
true))
(define add-module-field
M [Field : X] -> (add-field M Field X (value *db*))
where (element? Field [load-fn unload-fn translate-fn])
M [depends : | Xs] -> (add-field M depends (normalize-ids Xs) (value *db*))
M [Field : | Xs] -> (add-field M Field Xs (value *db*))
_ _ -> false)
(define nil-load
-> false)
(set *nil-load* nil-load)
(set *nil-translate* (/. _ _ []))
(define init-module-data
M -> (do (put M path (value *home-directory*) (value *db*))
(put M load [] (value *db*))
(put M translate [] (value *db*))
(put M depends [] (value *db*))
(put M translate-depends [] (value *db*))
(put M load-fn (value *nil-load*) (value *db*))
(put M unload-fn (value *nil-load*) (value *db*))
(put M translate-fn (value *nil-translate*) (value *db*))
(put M fields (value *fields*) (value *db*))
true))
(define rm-module-data'
[] _ _ -> true
[X | Xs] M D -> (do (unput M X D)
(rm-module-data' Xs M)))
(define rm-module-data
M -> (rm-module-data' (get M fields (value *db*)) M (value *db*)))
(define add-module-data
_ [] -> true
M [X | Xs] -> (do (add-module-field M X)
(add-module-data M Xs)))
(define register
Def -> (let Name (value *current-module*)
(and (init-module-data Name)
(add-module-data Name Def))))
(define register-module
Def -> (register Def))
(define call-module-unload
M -> (let F (get M unload-fn (value *db*))
(if (= F (value *nil-load*))
true
((function F) unload))))
(define forget-module
M -> true where (not (element? (normalize-id M) (value *list*)))
M -> (let M-id (normalize-id M)
. (call-module-unload M-id)
. (set *list* (remove M-id (value *list*)))
(rm-module-data M-id)))
(define manifest-exists?
F -> (trap-error (do (close (open (cn F "/module.shen") in))
true)
(/. E false)))
(define in-directory
Dir Proc Err -> (let Prev (value *home-directory*)
(trap-error (let Ret (Proc (cd Dir))
. (cd Prev)
Ret)
(/. E (do (cd Prev)
(Err E))))))
(define find-module-dir
M [] -> (error "Unable to locate module ~A" M)
M [D | Ds] -> (let Dir (cn D (cn "/" M))
(if (manifest-exists? Dir)
Dir
(find-module-dir M Ds))))
(define load-manifest'
M S -> (let . (set *current-module* M)
. (load/tc - "module.shen")
. (set *current-module* "")
S))
(define module-error
S M R E -> (do (rm-module-data M)
(set *current-module* "")
(error "~A ~S: ~S" S M (error-to-string E))
R))
(define load-manifest
M Ds -> (in-directory (find-module-dir M Ds)
(load-manifest' M)
(module-error "Loading manifest" M "")))
(define module-trans-deps
M -> (let D (get M translate-depends (value *db*))
(if (empty? D)
(get M depends (value *db*))
D)))
(define resolve-deps'
{string --> (list string) --> get-deps-fn --> (string --> boolean)
--> (list string) --> (list string)}
_ [] _ _ Acc -> Acc
P [D | Ds] Get Pred Acc -> (resolve-deps' P Ds Get Pred Acc) where (Pred D)
P [D | Ds] Get Pred Acc -> (let Ps [P "." | (value *paths*)]
Dir (load-manifest D Ps)
Acc [D | Acc]
Acc (resolve-deps' Dir (Get D) Get Pred Acc)
(resolve-deps' P Ds Get Pred Acc)))
(define remove-dups'
[] Acc -> (reverse Acc)
[X | Xs] Acc -> (remove-dups' Xs Acc) where (element? X Acc)
[X | Xs] Acc -> (remove-dups' Xs [X | Acc]))
(define remove-dups
X -> (remove-dups' X []))
(define resolve-deps
Deps Get Pred -> (remove-dups (resolve-deps' "." Deps Get Pred [])))
(define load-module-files
[] -> true
[F | Fs] -> (do (load F)
(load-module-files Fs)))
(define load-module-sources
M -> (let F (get M load-fn (value *db*))
R (if (= F (value *nil-load*))
(load-module-files (get M load (value *db*)))
((function F) load))
. (set *list* [M | (value *list*)])
R))
(define load-module
M -> (in-directory (get M path (value *db*))
(/. _ (load-module-sources M))
(module-error "Failed loading" M false)))
(define load-modules
[] -> true
[M | Ms] -> (do (load-module M)
(load-modules Ms)))
(define use
Ms -> (let Mods (resolve-deps (normalize-ids Ms)
(/. M (get M depends (value *db*)))
(/. X (element? X (value *list*))))
(load-modules Mods)))
(define use-modules
Ms -> (use Ms))
(define reload
M -> (do (forget-module M)
(use [M])))
(define fullpath
P Files -> (map (/. X (cn P X)) Files))
(define ls-module-trans-files
M Lang Impl Acc ->
(in-directory
(get M path (value *db*))
(/. Dir (let F (get M translate-fn (value *db*))
(append Acc (fullpath Dir
(if (= F (value *nil-translate*))
(let L (get M translate (value *db*))
(if (empty? L)
(get M load (value *db*))
L))
((function F) Lang Impl))))))
(module-error "Failed translating" M [])))
(define collect-trans-files
[] _ _ Acc -> Acc
[M | Ms] Lang Impl Acc ->
(collect-trans-files Ms Lang Impl (ls-module-trans-files M Lang Impl Acc)))
(define files-to-translate
M Lang Impl -> (let M-id (normalize-id M)
. (use [M])
Mods (resolve-deps [M-id]
(function module-trans-deps)
(/. _ false))
(collect-trans-files Mods Lang Impl [])))
(define load/tc
Tc File -> (let Old-tc (if (tc?) + -)
. (tc Tc)
R (trap-error (load File)
(/. E (do (tc Old-tc)
(error (error-to-string E)))))
. (tc Old-tc)
R))
(datatype module-types
X : string;
______________
X : module-id;
X : symbol;
______________
X : module-id;
X : module-id;
_____________
X : module-list;
X : (list module-id);
_________________
X : module-list;
)
(declare files-to-translate
[module-id --> string --> string --> [list string]])
(declare use [module-list --> boolean])
(declare use-modules [module-list --> boolean])
(declare reload [module-id --> boolean])
(declare load/tc [symbol --> string --> symbol]))