]> gitweb.factorcode.org Git - factor.git/blob - basis/tools/scaffold/scaffold.factor
Revert "Fixes #2966"
[factor.git] / basis / tools / scaffold / scaffold.factor
1 ! Copyright (C) 2008 Doug Coleman.
2 ! See https://factorcode.org/license.txt for BSD license.
3 USING: accessors alien arrays assocs byte-arrays calendar
4 classes classes.error combinators combinators.short-circuit
5 continuations effects eval hashtables help.markup interpolate io
6 io.directories io.encodings.utf8 io.files io.pathnames
7 io.streams.string kernel math math.parser namespaces parser
8 prettyprint prettyprint.config quotations sequences sets sorting
9 splitting strings system timers unicode urls vocabs
10 vocabs.loader vocabs.metadata words words.symbol ;
11 IN: tools.scaffold
12
13 SYMBOL: developer-name
14 SYMBOL: using
15
16 ERROR: not-a-vocab-root string ;
17
18 ERROR: vocab-must-not-exist string ;
19
20 <PRIVATE
21
22 : vocab-root? ( string -- ? )
23     trim-tail-separators vocab-roots get member? ;
24
25 : ensure-vocab-exists ( string -- string )
26     dup lookup-vocab [ no-vocab ] unless ;
27
28 : check-vocab-root ( string -- string )
29     dup vocab-root? [ not-a-vocab-root ] unless ;
30
31 : check-vocab-root/name ( vocab-root string -- vocab-root string )
32     [ check-vocab-root ] [ check-vocab-name ] bi* ;
33
34 : replace-vocab-separators ( vocab -- path )
35     path-separator first CHAR: . associate substitute ;
36
37 : vocab-root/vocab>path ( vocab-root vocab -- path )
38     check-vocab-root/name
39     [ ] [ replace-vocab-separators ] bi* append-path ;
40
41 : vocab>path ( vocab -- path )
42     check-vocab [ find-vocab-root ] keep vocab-root/vocab>path ;
43
44 : vocab-root/vocab/file>path ( vocab-root vocab file -- path )
45     [ vocab-root/vocab>path ] dip append-path ;
46
47 : vocab-root/vocab/suffix>path ( vocab-root vocab suffix -- path )
48     [ vocab-root/vocab>path dup file-name append-path ] dip append ;
49
50 : vocab/file>path ( vocab file -- path )
51     [ vocab>path ] dip append-path ;
52
53 : vocab/suffix>path ( vocab suffix -- path )
54     [ vocab>path dup file-name append-path ] dip append ;
55
56 : directory-exists ( path -- )
57     "Not creating a directory, it already exists: " write print ;
58
59 : scaffold-directory ( vocab-root vocab -- )
60     vocab-root/vocab>path
61     [ directory-exists ] [ make-directories ] if-file-exists ;
62
63 : not-scaffolding ( path -- path )
64     "Not creating scaffolding for " write dup <pathname> . ;
65
66 : scaffolding ( path -- path )
67     "Creating scaffolding for " write dup <pathname> . ;
68
69 : scaffolding? ( path -- path ? )
70     [ not-scaffolding f ] [ scaffolding t ] if-file-exists ;
71
72 : scaffold-copyright ( -- )
73     "! Copyright (C) " write now year>> number>string write
74     developer-name get [ "Your name" ] unless* bl write "." print
75     "! See https://factorcode.org/license.txt for BSD license." print ;
76
77 : main-file-string ( vocab -- string )
78     [
79         scaffold-copyright
80         "USING: ;" print
81         "IN: " write print
82     ] with-string-writer ;
83
84 : set-scaffold-main-file ( vocab path -- )
85     [ main-file-string 1array ] dip utf8 set-file-lines ;
86
87 : scaffold-main ( vocab-root vocab -- )
88     [ ".factor" vocab-root/vocab/suffix>path ] keep swap scaffolding? [
89         set-scaffold-main-file
90     ] [
91         2drop
92     ] if ;
93
94 : scaffold-metadata ( vocab file contents -- )
95     [ ensure-vocab-exists ] 2dip
96     [
97         [ vocab/file>path ] dip 1array swap scaffolding? [
98             utf8 set-file-lines
99         ] [
100             2drop
101         ] if
102     ] [
103         2drop
104     ] if* ;
105
106 : lookup-type ( string -- object/string ? )
107     "/f" ?tail swap
108     "new" ?head drop [ { [ CHAR: ' = ] [ digit? ] } 1|| ] trim-tail
109     H{
110         { "object" object }
111         { "obj" object }
112         { "quot" quotation }
113         { "string" string }
114         { "str" string }
115         { "hash" hashtable }
116         { "hashtable" hashtable }
117         { "?" boolean }
118         { "ch" "a character" }
119         { "word" word }
120         { "array" array }
121         { "byte-array" byte-array }
122         { "timer" timer }
123         { "duration" duration }
124         { "path" "a pathname string" }
125         { "vocab" "a vocabulary specifier" }
126         { "vocab-root" "a vocabulary root string" }
127         { "c-ptr" c-ptr }
128         { "sequence" sequence }
129         { "slice" slice }
130         { "from" integer }
131         { "to" integer }
132         { "i" integer }
133         { "n" integer }
134         { "seq" sequence }
135         { "exemplar" object }
136         { "assoc" assoc }
137         { "alist" "an array of key/value pairs" }
138         { "keys" sequence }
139         { "values" sequence }
140         { "class" class }
141         { "tuple" tuple }
142         { "url" url }
143     } at* [ swap [ \ $maybe swap 2array ] when ] dip ;
144
145 GENERIC: add-using ( object -- )
146
147 M: array add-using [ add-using ] each ;
148
149 M: string add-using drop ;
150
151 M: object add-using
152     vocabulary>> using get [ adjoin ] [ drop ] if* ;
153
154 : ($values.) ( array -- )
155     [
156         "    " write
157         [ bl ] [
158             "{ " write
159             dup array? [ first ] when
160             dup lookup-type [
161                 [ unparse write bl ]
162                 [ [ pprint ] [ add-using ] bi ] bi*
163             ] [
164                 drop unparse write bl object pprint
165                 object add-using
166             ] if
167             " }" write
168         ] interleave
169     ] unless-empty ;
170
171 : ?print-nl ( seq1 seq2 -- )
172     [ empty? ] either? [ nl ] unless ;
173
174 : $values. ( word -- )
175     "declared-effect" word-prop [
176         [ in>> ] [ out>> ] bi
177         2dup [ empty? ] both? [
178             2drop
179         ] [
180             [ members ] dip over diff
181             "{ $values" print
182             [ drop ($values.) ]
183             [ ?print-nl ]
184             [ nip ($values.) ] 2tri
185             nl "}" print
186         ] if
187     ] when* ;
188
189 : error-description. ( word -- )
190     [ $values. ] [
191         "{ $description \"Throws " write
192         name>> dup a/an write " \" { $link " write
193         write " } \" error.\" }" print
194     ] bi "{ $error-description \"\" } ;" print ;
195
196 : class-description. ( word -- )
197     drop "{ $class-description \"\" } ;" print ;
198
199 : symbol-description. ( word -- )
200     drop "{ $var-description \"\" } ;" print ;
201
202 : $description. ( word -- )
203     drop "{ $description \"\" } ;" print ;
204
205 : docs-body. ( word/symbol -- )
206     {
207         { [ dup error-class? ] [ error-description. ] }
208         { [ dup class? ] [ class-description. ] }
209         { [ dup symbol? ] [ symbol-description. ] }
210         [ [ $values. ] [ $description. ] bi ]
211     } cond ;
212
213 : docs-header. ( word -- )
214     "HELP: " write name>> print ;
215
216 : interesting-words ( vocab -- array )
217     vocab-words
218     [ { [ "help" word-prop ] [ predicate? ] } 1|| ] reject
219     sort ;
220
221 PRIVATE>
222
223 : scaffold-word-docs ( word -- )
224     [ docs-header. ] [ docs-body. ] bi ;
225
226 <PRIVATE
227
228 : interesting-words. ( vocab -- )
229     interesting-words [ scaffold-word-docs nl ] each ;
230
231 : docs-file-string ( vocab -- str2 )
232     [
233         {
234             [ "IN: " write print nl ]
235             [ interesting-words. ]
236             [
237                 [ "ARTICLE: " write unparse dup write bl print ]
238                 [ "{ $vocab-link " write pprint " }" print ] bi
239                 ";" print nl
240             ]
241             [ "ABOUT: " write unparse print ]
242         } cleave
243     ] with-string-writer ;
244
245 : write-using ( vocab -- )
246     "USING:" write
247     using get members
248     { "help.markup" "help.syntax" } append sort remove
249     [ bl write ] each
250     " ;" print ;
251
252 : set-scaffold-docs-file ( vocab path -- )
253     utf8 <file-writer> [
254         scaffold-copyright
255         [ docs-file-string ] [ write-using ] bi
256         write
257     ] with-output-stream ;
258
259 : with-scaffold ( quot -- )
260     [ HS{ } clone using ] dip with-variable ; inline
261
262 : link-vocab ( vocab -- )
263     ".private" ?tail drop
264     check-vocab
265     "Edit documentation: " write
266     "-docs.factor" vocab/suffix>path <pathname> . ;
267
268 PRIVATE>
269
270 : help. ( word -- )
271     [ scaffold-word-docs ] [ nl vocabulary>> link-vocab ] bi ;
272
273 GENERIC: scaffold-docs ( obj -- )
274
275 M: string scaffold-docs ( vocab -- )
276     ensure-vocab-exists
277     [
278         dup "-docs.factor" vocab/suffix>path scaffolding? [
279             set-scaffold-docs-file
280         ] [
281             2drop
282         ] if
283     ] with-scaffold ;
284
285 M: sequence scaffold-docs [ scaffold-word-docs nl ] each ;
286 M: word scaffold-docs scaffold-word-docs ;
287
288 : scaffold-undocumented ( string -- )
289     [ interesting-words. ] [ link-vocab ] bi ;
290
291 : scaffold-authors ( vocab -- )
292     "authors.txt" developer-name get scaffold-metadata ;
293
294 : scaffold-tags ( vocab tags -- )
295     [ "tags.txt" ] dip scaffold-metadata ;
296
297 : scaffold-summary ( vocab summary -- )
298     [ "summary.txt" ] dip scaffold-metadata ;
299
300 : scaffold-platforms ( vocab platforms -- )
301     [ "platforms.txt" ] dip scaffold-metadata ;
302
303 : delete-from-root-cache ( string -- )
304     root-cache get delete-at ;
305
306 : scaffold-vocab-in ( vocab-root string -- )
307     dup delete-from-root-cache
308     {
309         [ scaffold-directory ]
310         [ scaffold-main ]
311         [ nip require ]
312         [ nip scaffold-authors ]
313     } 2cleave ;
314
315 : scaffold-core ( string -- )
316     "resource:core" swap scaffold-vocab-in ;
317
318 : scaffold-basis ( string -- )
319     "resource:basis" swap scaffold-vocab-in ;
320
321 : scaffold-extra ( string -- )
322     "resource:extra" swap scaffold-vocab-in ;
323
324 : scaffold-work ( string -- )
325     "resource:work" swap scaffold-vocab-in  ;
326
327 : scaffold-vocab ( string -- )
328     "Choose a vocabulary root:" vocab-roots get
329     '[ [ "Use " prepend ] keep ] { } map>assoc throw-restarts
330     swap scaffold-vocab-in ;
331
332 <PRIVATE
333
334 : tests-file-string ( vocab -- string )
335     [
336         scaffold-copyright
337         "USING: tools.test " write dup write " ;" print
338         "IN: " write write ".tests" print
339     ] with-string-writer ;
340
341 : set-scaffold-tests-file ( vocab path -- )
342     [ tests-file-string ] dip utf8 set-file-contents ;
343
344 : vocab>test-path ( vocab -- string )
345     "-tests.factor" vocab/suffix>path ;
346
347 PRIVATE>
348
349 : scaffold-tests ( vocab -- )
350     ensure-vocab-exists dup vocab>test-path
351     scaffolding? [
352         set-scaffold-tests-file
353     ] [
354         2drop
355     ] if ;
356
357 SYMBOL: nested-examples
358
359 : example-using ( using -- )
360     join-words "example-using" [
361         nested-examples get 4 0 ? CHAR: \s <string> "example-indent" [
362             "${example-indent}\"Example:\"
363 ${example-indent}{ $example \"USING: ${example-using} ;\"
364 ${example-indent}    \"\"
365 ${example-indent}    \"\"
366 ${example-indent}}
367 "
368             interpolate
369         ] with-variable
370     ] with-variable ;
371
372 : n-examples-using ( n using -- )
373     '[ _ example-using ] times ;
374
375 : scaffold-n-examples ( n word -- )
376     vocabulary>> "prettyprint" 2array
377     [ t nested-examples ] 2dip
378     '[
379         "{ $examples" print
380         _ _ n-examples-using
381         "}" print
382     ] with-variable ;
383
384 : scaffold-examples ( word -- )
385     2 swap scaffold-n-examples ;
386
387 : scaffold-file ( path -- )
388     [ touch-file ]
389     [ "Click to edit: " write >pathname . ] bi ;
390
391 : scaffold-rc ( path -- )
392     home-path scaffold-file ;
393
394 : scaffold-factor-boot-rc ( -- )
395     ".factor-boot-rc" scaffold-rc ;
396
397 : scaffold-factor-rc ( -- )
398     ".factor-rc" scaffold-rc ;
399
400 : scaffold-mason-rc ( -- )
401     ".factor-mason-rc" scaffold-rc ;
402
403 : scaffold-factor-roots ( -- )
404     ".factor-roots" scaffold-rc ;
405
406 : make-unit-test ( answer code -- str )
407     split-lines [ "    " prepend ] map "\n" join
408     "[\n" "\n] unit-test\n" surround
409     " " glue ;
410
411 : run-string ( string -- datastack )
412     [ parse-string ] with-file-vocabs V{ } clone swap with-datastack ;
413
414 : read-unit-test ( -- str/f )
415     read-contents [ f ] [
416         [ run-string [ unparse ] without-limits ] keep
417         make-unit-test
418     ] if-empty ;
419
420 : read-unit-tests ( -- str )
421     [ read-unit-test dup ] [ ] produce nip "\n\n" join ;
422
423 : scaffold-unit-tests ( vocab -- )
424     [ scaffold-tests read-unit-tests ]
425     [ vocab>test-path utf8 [ write ] with-file-appender ] bi ;
426
427 HOOK: scaffold-emacs os ( -- )
428
429 M: unix scaffold-emacs ".emacs" scaffold-rc ;