]> gitweb.factorcode.org Git - factor.git/blob - basis/help/lint/checks/checks.factor
Merge branch 'new_gc' of git://factorcode.org/git/factor into new_gc
[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 combinators
4 combinators.short-circuit definitions effects eval fry grouping
5 help help.markup help.topics io.streams.string kernel macros
6 namespaces sequences sequences.deep sets sorting splitting
7 strings unicode.categories values vocabs vocabs.loader words
8 words.symbol summary debugger io ;
9 IN: help.lint.checks
10
11 ERROR: simple-lint-error message ;
12
13 M: simple-lint-error summary message>> ;
14
15 M: simple-lint-error error. summary print ;
16
17 SYMBOL: vocabs-quot
18 SYMBOL: all-vocabs
19 SYMBOL: vocab-articles
20
21 : check-example ( element -- )
22     '[
23         _ rest [
24             but-last "\n" join
25             [ (eval>string) ] call( code -- output )
26             "\n" ?tail drop
27         ] keep
28         last assert=
29     ] vocabs-quot get call( quot -- ) ;
30
31 : check-examples ( element -- )
32     \ $example swap elements [ check-example ] each ;
33
34 : extract-values ( element -- seq )
35     \ $values swap elements dup empty? [
36         first rest [ first ] map prune
37     ] unless ;
38
39 : effect-values ( word -- seq )
40     stack-effect
41     [ in>> ] [ out>> ] bi append
42     [ dup pair? [ first ] when effect>string ] map prune ;
43
44 : contains-funky-elements? ( element -- ? )
45     {
46         $shuffle
47         $values-x/y
48         $predicate
49         $class-description
50         $error-description
51     } swap '[ _ elements empty? not ] any? ;
52
53 : don't-check-word? ( word -- ? )
54     {
55         [ macro? ]
56         [ symbol? ]
57         [ value-word? ]
58         [ parsing-word? ]
59         [ "declared-effect" word-prop not ]
60     } 1|| ;
61
62 : check-values ( word element -- )
63     {
64         [
65             [ don't-check-word? ]
66             [ contains-funky-elements? ]
67             bi* or
68         ] [
69             [ effect-values ]
70             [ extract-values ]
71             bi* sequence=
72         ]
73     } 2|| [ "$values don't match stack effect" simple-lint-error ] unless ;
74
75 : check-nulls ( element -- )
76     \ $values swap elements
77     null swap deep-member?
78     [ "$values should not contain null" simple-lint-error ] when ;
79
80 : check-see-also ( element -- )
81     \ $see-also swap elements [
82         rest dup prune [ length ] bi@ assert=
83     ] each ;
84
85 : vocab-exists? ( name -- ? )
86     [ vocab ] [ all-vocabs get member? ] bi or ;
87
88 : check-modules ( element -- )
89     \ $vocab-link swap elements [
90         second
91         vocab-exists? [
92             "$vocab-link to non-existent vocabulary"
93             simple-lint-error
94         ] unless
95     ] each ;
96
97 : check-rendering ( element -- )
98     [ print-content ] with-string-writer drop ;
99
100 : check-strings ( str -- )
101     [
102         "\n\t" intersects? [
103             "Paragraph text should not contain \\n or \\t"
104             simple-lint-error
105         ] when
106     ] [
107         "  " swap subseq? [
108             "Paragraph text should not contain double spaces"
109             simple-lint-error
110         ] when
111     ] bi ;
112
113 : check-whitespace ( str1 str2 -- )
114     [ " " tail? ] [ " " head? ] bi* or
115     [ "Missing whitespace between strings" simple-lint-error ] unless ;
116
117 : check-bogus-nl ( element -- )
118     { { $nl } { { $nl } } } [ head? ] with any? [
119         "Simple element should not begin with a paragraph break"
120         simple-lint-error
121     ] when ;
122
123 : check-class-description ( word element -- )
124     [ class? not ]
125     [ { $class-description } swap elements empty? not ] bi* and
126     [ "A word that is not a class has a $class-description" simple-lint-error ] when ;
127
128 : check-article-title ( article -- )
129     article-title first LETTER?
130     [ "Article title must begin with a capital letter" simple-lint-error ] unless ;
131
132 : check-elements ( element -- )
133     {
134         [ check-bogus-nl ]
135         [ [ string? ] filter [ check-strings ] each ]
136         [ [ simple-element? ] filter [ check-elements ] each ]
137         [ 2 <clumps> [ [ string? ] all? ] filter [ first2 check-whitespace ] each ]
138     } cleave ;
139
140 : check-descriptions ( element -- )
141     { $description $class-description $var-description }
142     swap '[
143         _ elements [
144             rest { { } { "" } } member?
145             [ "Empty $description" simple-lint-error ] when
146         ] each
147     ] each ;
148
149 : check-markup ( element -- )
150     {
151         [ check-elements ]
152         [ check-rendering ]
153         [ check-examples ]
154         [ check-modules ]
155         [ check-descriptions ]
156     } cleave ;
157
158 : files>vocabs ( -- assoc )
159     vocabs
160     [ [ [ vocab-docs-path ] keep ] H{ } map>assoc ]
161     [ [ [ vocab-source-path ] keep ] H{ } map>assoc ]
162     bi assoc-union ;
163
164 : group-articles ( -- assoc )
165     articles get keys
166     files>vocabs
167     H{ } clone [
168         '[
169             dup >link where dup
170             [ first _ at _ push-at ] [ 2drop ] if
171         ] each
172     ] keep ;
173
174 : all-word-help ( words -- seq )
175     [ word-help ] filter ;