]> gitweb.factorcode.org Git - factor.git/blob - basis/help/lint/checks/checks.factor
help.lint.checks: adding linux and windows ui disposables.
[factor.git] / basis / help / lint / checks / checks.factor
1 ! Copyright (C) 2009 Slava Pestov.
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: accessors arrays assocs classes classes.struct
4 classes.tuple combinators combinators.short-circuit debugger
5 definitions effects eval formatting fry grouping help
6 help.markup help.topics io io.streams.string kernel macros math
7 namespaces sequences sequences.deep sets splitting strings
8 summary tools.destructors unicode vocabs vocabs.loader words
9 words.constant words.symbol ;
10 IN: help.lint.checks
11
12 ERROR: simple-lint-error message ;
13
14 M: simple-lint-error summary message>> ;
15
16 M: simple-lint-error error. summary print ;
17
18 SYMBOL: vocabs-quot
19 SYMBOL: vocab-articles
20
21 : no-ui-disposables ( seq -- seq' )
22     [
23         class-of name>> {
24             "single-texture" "multi-texture" ! opengl.textures
25             "line" ! core-text
26             "layout" ! ui.text.pango
27             "script-string" ! windows.uniscribe
28         } member?
29     ] reject ;
30
31 : check-example ( element -- )
32     [
33         '[
34             _ rest [
35                 but-last "\n" join
36                 [ (eval>string) ] call( code -- output )
37                 "\n" ?tail drop
38             ] keep
39             last assert=
40         ] vocabs-quot get call( quot -- )
41     ] leaks members no-ui-disposables length [
42         "%d disposable(s) leaked in example" sprintf simple-lint-error
43     ] unless-zero ;
44
45 : check-examples ( element -- )
46     \ $example swap elements [ check-example ] each ;
47
48 : extract-values ( element -- seq )
49     \ $values swap elements
50     [ f ] [ first rest keys ] if-empty ;
51
52 : extract-value-effects ( element -- seq )
53     \ $values swap elements [ f ] [
54         first rest [
55             \ $quotation swap elements [ f ] [
56                 first second dup effect? [ effect>string ] when
57             ] if-empty
58         ] map
59     ] if-empty ;
60
61 : effect-values ( word -- seq )
62     stack-effect
63     [ in>> ] [ out>> ] bi append
64     [ dup pair? [ first ] when effect>string ] map members ;
65
66 : effect-effects ( word -- seq )
67     stack-effect in>> [
68         dup pair?
69         [ second dup effect? [ effect>string ] [ drop f ] if ]
70         [ drop f ] if
71     ] map ;
72
73 : contains-funky-elements? ( element -- ? )
74     {
75         $shuffle
76         $complex-shuffle
77         $values-x/y
78         $predicate
79         $class-description
80         $error-description
81     } swap '[ _ elements empty? not ] any? ;
82
83 : don't-check-word? ( word -- ? )
84     {
85         [ macro? ]
86         [ symbol? ]
87         [ parsing-word? ]
88         [ "declared-effect" word-prop not ]
89         [ constant? ]
90         [ "word-help" word-prop not ]
91     } 1|| ;
92
93 : skip-check-values? ( word element -- ? )
94     [ don't-check-word? ] [ contains-funky-elements? ] bi* or ;
95
96 : check-values ( word element -- )
97     2dup skip-check-values? [ 2drop ] [
98         [ effect-values ] [ extract-values ] bi* 2dup
99         sequence= [ 2drop ] [
100             "$values don't match stack effect; expected %u, got %u" sprintf
101             simple-lint-error
102         ] if
103     ] if ;
104
105 : check-value-effects ( word element -- )
106     [ effect-effects ] [ extract-value-effects ] bi*
107     [ 2dup and [ = ] [ 2drop t ] if ] 2all? [
108         "$quotation stack effects in $values don't match"
109         simple-lint-error
110     ] unless ;
111
112 : check-nulls ( element -- )
113     \ $values swap elements
114     null swap deep-member?
115     [ "$values should not contain null" simple-lint-error ] when ;
116
117 : check-see-also ( element -- )
118     \ $see-also swap elements [ rest all-unique? ] all?
119     [ "$see-also are not unique" simple-lint-error ] unless ;
120
121 : check-modules ( element -- )
122     \ $vocab-link swap elements [
123         second
124         vocab-exists? [
125             "$vocab-link to non-existent vocabulary"
126             simple-lint-error
127         ] unless
128     ] each ;
129
130 : check-rendering ( element -- )
131     [ print-content ] with-string-writer drop ;
132
133 : check-strings ( str -- )
134     [
135         "\n\t" intersects? [
136             "Paragraph text should not contain \\n or \\t"
137             simple-lint-error
138         ] when
139     ] [
140         "  " swap subseq? [
141             "Paragraph text should not contain double spaces"
142             simple-lint-error
143         ] when
144     ] bi ;
145
146 : check-whitespace ( str1 str2 -- )
147     [ " " tail? ] [ " " head? ] bi* or
148     [ "Missing whitespace between strings" simple-lint-error ] unless ;
149
150 : check-bogus-nl ( element -- )
151     { { $nl } { { $nl } } } [ head? ] with any? [
152         "Simple element should not begin with a paragraph break"
153         simple-lint-error
154     ] when ;
155
156 : extract-slots ( elements -- seq )
157     [ dup pair? [ first \ $slot = ] [ drop f ] if ] deep-filter
158     [ second ] map ;
159
160 : check-class-description ( word element -- )
161     \ $class-description swap elements over class? [
162         [
163             dup struct-class? [ struct-slots ] [ all-slots ] if
164             [ name>> ] map
165         ] [ extract-slots ] bi*
166         [ swap member? ] with reject [
167             ", " join "Described $slot does not exist: " prepend
168             simple-lint-error
169         ] unless-empty
170     ] [
171         nip empty? not [
172             "A word that is not a class has a $class-description"
173             simple-lint-error
174         ] when
175     ] if ;
176
177 : check-article-title ( article -- )
178     article-title first LETTER?
179     [ "Article title must begin with a capital letter" simple-lint-error ] unless ;
180
181 : check-elements ( element -- )
182     {
183         [ check-bogus-nl ]
184         [ [ string? ] filter [ check-strings ] each ]
185         [ [ simple-element? ] filter [ check-elements ] each ]
186         [ 2 <clumps> [ [ string? ] all? ] filter [ first2 check-whitespace ] each ]
187     } cleave ;
188
189 : check-descriptions ( element -- )
190     { $description $class-description $var-description }
191     swap '[
192         _ elements [
193             rest { { } { "" } } member?
194             [ "Empty $description" simple-lint-error ] when
195         ] each
196     ] each ;
197
198 : check-markup ( element -- )
199     {
200         [ check-elements ]
201         [ check-rendering ]
202         [ check-examples ]
203         [ check-modules ]
204         [ check-descriptions ]
205     } cleave ;
206
207 : files>vocabs ( -- assoc )
208     loaded-vocab-names
209     [ [ [ vocab-docs-path ] keep ] H{ } map>assoc ]
210     [ [ [ vocab-source-path ] keep ] H{ } map>assoc ]
211     bi assoc-union ;
212
213 : group-articles ( -- assoc )
214     articles get keys
215     files>vocabs
216     H{ } clone [
217         '[
218             dup >link where dup
219             [ first _ at _ push-at ] [ 2drop ] if
220         ] each
221     ] keep ;
222
223 : all-word-help ( words -- seq )
224     [ word-help ] filter ;