1 | # (C) Copyright Rene Rivera, 2002-2003. |
---|
2 | # |
---|
3 | # See accompanying license for terms and conditions of use. |
---|
4 | # |
---|
5 | |
---|
6 | # Documentation system, handles --help requests. |
---|
7 | # It defines rules that attach documentation to modules, rules, and variables. |
---|
8 | # Collects and generates documentation for the various parts of the build system. |
---|
9 | # The documentation is collected from comments integrated into the code. |
---|
10 | |
---|
11 | import modules ; |
---|
12 | import print ; |
---|
13 | import set ; |
---|
14 | import container ; |
---|
15 | import "class" ; |
---|
16 | import sequence ; |
---|
17 | |
---|
18 | # The type of output to generate. |
---|
19 | # "console" is formated text echoed to the console (the default); |
---|
20 | # "text" is formated text appended to the output file; |
---|
21 | # "html" is HTML output to the file. |
---|
22 | # |
---|
23 | help-output = console ; |
---|
24 | |
---|
25 | # The file to output documentation to when generating "text" or "html" |
---|
26 | # help. This is without extension as the extension is determined by the |
---|
27 | # type of output. |
---|
28 | # |
---|
29 | help-output-file = help ; |
---|
30 | |
---|
31 | # Whether to include local rules in help output. |
---|
32 | # |
---|
33 | .option.show-locals ?= ; |
---|
34 | |
---|
35 | # When showing documentation for a module, whether to also generate |
---|
36 | # automatically the detailed docs for each item in the module. |
---|
37 | # |
---|
38 | .option.detailed ?= ; |
---|
39 | |
---|
40 | # Generate debug output as the help is generated and modules |
---|
41 | # are parsed. |
---|
42 | # |
---|
43 | .option.debug ?= ; |
---|
44 | |
---|
45 | # Enable or disable a documentation option. |
---|
46 | # |
---|
47 | local rule set-option ( |
---|
48 | option # The option name. |
---|
49 | : value ? # Enabled (non-empty), or disabled (empty) |
---|
50 | ) |
---|
51 | { |
---|
52 | .option.$(option) = $(value) ; |
---|
53 | } |
---|
54 | |
---|
55 | # Set the type of output. |
---|
56 | # |
---|
57 | local rule set-output ( |
---|
58 | type |
---|
59 | ) |
---|
60 | { |
---|
61 | help-output = $(type) ; |
---|
62 | } |
---|
63 | |
---|
64 | # Set the output to a file. |
---|
65 | # |
---|
66 | local rule set-output-file ( |
---|
67 | file |
---|
68 | ) |
---|
69 | { |
---|
70 | help-output-file = $(file) ; |
---|
71 | } |
---|
72 | |
---|
73 | # Extracts the brief comment from a complete comment. The brief |
---|
74 | # comment is the first sentence. |
---|
75 | # |
---|
76 | local rule brief-comment ( |
---|
77 | docs * # The comment documentation. |
---|
78 | ) |
---|
79 | { |
---|
80 | local d = $(docs:J=" ") ; |
---|
81 | local p = [ MATCH ".*([.])$" : $(d) ] ; |
---|
82 | if ! $(p) { d = $(d)"." ; } |
---|
83 | d = $(d)" " ; |
---|
84 | local m = [ MATCH "^([^.]+[.])(.*)" : $(d) ] ; |
---|
85 | local brief = $(m[1]) ; |
---|
86 | while $(m[2]) && [ MATCH "^([^ ])" : $(m[2]) ] |
---|
87 | { |
---|
88 | m = [ MATCH "^([^.]+[.])(.*)" : $(m[2]) ] ; |
---|
89 | brief += $(m[1]) ; |
---|
90 | } |
---|
91 | return $(brief:J="") ; |
---|
92 | } |
---|
93 | |
---|
94 | # Specifies the documentation for the current module. |
---|
95 | # |
---|
96 | local rule set-module-doc ( |
---|
97 | module-name ? # The name of the module to document. |
---|
98 | : docs * # The documentation for the module. |
---|
99 | ) |
---|
100 | { |
---|
101 | module-name ?= * ; |
---|
102 | |
---|
103 | $(module-name).brief = [ brief-comment $(docs) ] ; |
---|
104 | $(module-name).docs = $(docs) ; |
---|
105 | |
---|
106 | if ! $(module-name) in $(documented-modules) |
---|
107 | { |
---|
108 | documented-modules += $(module-name) ; |
---|
109 | } |
---|
110 | } |
---|
111 | |
---|
112 | # Specifies the documentation for the current module. |
---|
113 | # |
---|
114 | local rule set-module-copyright ( |
---|
115 | module-name ? # The name of the module to document. |
---|
116 | : copyright * # The copyright for the module. |
---|
117 | ) |
---|
118 | { |
---|
119 | module-name ?= * ; |
---|
120 | |
---|
121 | $(module-name).copy-brief = [ brief-comment $(copyright) ] ; |
---|
122 | $(module-name).copy-docs = $(docs) ; |
---|
123 | |
---|
124 | if ! $(module-name) in $(documented-modules) |
---|
125 | { |
---|
126 | documented-modules += $(module-name) ; |
---|
127 | } |
---|
128 | } |
---|
129 | |
---|
130 | # Specifies the documentation for a rule in the current module. |
---|
131 | # If called in the global module, this documents a global rule. |
---|
132 | # |
---|
133 | local rule set-rule-doc ( |
---|
134 | name # The name of the rule. |
---|
135 | module-name ? # The name of the module to document. |
---|
136 | is-local ? # Whether the rule is local to the module. |
---|
137 | : docs * # The documentation for the rule. |
---|
138 | ) |
---|
139 | { |
---|
140 | module-name ?= * ; |
---|
141 | |
---|
142 | $(module-name).$(name).brief = [ brief-comment $(docs) ] ; |
---|
143 | $(module-name).$(name).docs = $(docs) ; |
---|
144 | $(module-name).$(name).is-local = $(is-local) ; |
---|
145 | |
---|
146 | if ! $(name) in $($(module-name).rules) |
---|
147 | { |
---|
148 | $(module-name).rules += $(name) ; |
---|
149 | } |
---|
150 | } |
---|
151 | |
---|
152 | # Specify a class, will turn a rule into a class. |
---|
153 | # |
---|
154 | local rule set-class-doc ( |
---|
155 | name # The name of the class. |
---|
156 | module-name ? # The name of the module to document. |
---|
157 | : super-name ? # The super class name. |
---|
158 | ) |
---|
159 | { |
---|
160 | module-name ?= * ; |
---|
161 | |
---|
162 | $(module-name).$(name).is-class = true ; |
---|
163 | $(module-name).$(name).super-name = $(super-name) ; |
---|
164 | $(module-name).$(name).class-rules = |
---|
165 | [ MATCH "^($(name)[.].*)" : $($(module-name).rules) ] ; |
---|
166 | $(module-name).$($(module-name).$(name).class-rules).is-class-rule = true ; |
---|
167 | |
---|
168 | $(module-name).classes += $(name) ; |
---|
169 | $(module-name).class-rules += $($(module-name).$(name).class-rules) ; |
---|
170 | $(module-name).rules = |
---|
171 | [ set.difference $($(module-name).rules) : |
---|
172 | $(name) $($(module-name).$(name).class-rules) ] ; |
---|
173 | } |
---|
174 | |
---|
175 | # Set the argument call signature of a rule. |
---|
176 | # |
---|
177 | local rule set-rule-arguments-signature ( |
---|
178 | name # The name of the rule. |
---|
179 | module-name ? # The name of the module to document. |
---|
180 | : signature * # The arguments signature. |
---|
181 | ) |
---|
182 | { |
---|
183 | module-name ?= * ; |
---|
184 | |
---|
185 | $(module-name).$(name).signature = $(signature) ; |
---|
186 | } |
---|
187 | |
---|
188 | # Specifies the documentation for an argument of a rule. |
---|
189 | # |
---|
190 | local rule set-argument-doc ( |
---|
191 | name # The name of the argument. |
---|
192 | qualifier # Argument syntax qualifier, "*", "+", etc. |
---|
193 | rule-name # The name of the rule. |
---|
194 | module-name ? # THe optional name of the module. |
---|
195 | : docs * # The documentation. |
---|
196 | ) |
---|
197 | { |
---|
198 | module-name ?= * ; |
---|
199 | |
---|
200 | $(module-name).$(rule-name).args.$(name).qualifier = $(qualifier) ; |
---|
201 | $(module-name).$(rule-name).args.$(name).docs = $(docs) ; |
---|
202 | |
---|
203 | if ! $(name) in $($(module-name).$(rule-name).args) |
---|
204 | { |
---|
205 | $(module-name).$(rule-name).args += $(name) ; |
---|
206 | } |
---|
207 | } |
---|
208 | |
---|
209 | # Specifies the documentation for a variable in the current module. |
---|
210 | # If called in the global module, the global variable is documented. |
---|
211 | # |
---|
212 | local rule set-variable-doc ( |
---|
213 | name # The name of the variable. |
---|
214 | default # The default value. |
---|
215 | initial # The initial value. |
---|
216 | module-name ? # The name of the module to document. |
---|
217 | : docs * # The documentation for the variable. |
---|
218 | ) |
---|
219 | { |
---|
220 | module-name ?= * ; |
---|
221 | |
---|
222 | $(module-name).$(name).brief = [ brief-comment $(docs) ] ; |
---|
223 | $(module-name).$(name).default = $(default) ; |
---|
224 | $(module-name).$(name).initial = $(initial) ; |
---|
225 | $(module-name).$(name).docs = $(docs) ; |
---|
226 | |
---|
227 | if ! $(name) in $($(module-name).variables) |
---|
228 | { |
---|
229 | $(module-name).variables += $(name) ; |
---|
230 | } |
---|
231 | } |
---|
232 | |
---|
233 | # Generates a general description of the documentation and help system. |
---|
234 | # |
---|
235 | local rule print-help-top ( ) |
---|
236 | { |
---|
237 | print.section "Available Help" |
---|
238 | These are the available options for obtaining documentation. |
---|
239 | Some options have additional instructions on how to get more |
---|
240 | detailed information. Multiple options are allowed and |
---|
241 | sometimes required. For example, the options that configure |
---|
242 | the help system still require a regular help request option |
---|
243 | for any output to be generated. |
---|
244 | ; |
---|
245 | print.list-start ; |
---|
246 | print.list-item --help; This help message. ; |
---|
247 | print.list-item --help-usage; How to invoke '"bjam".' ; |
---|
248 | print.list-item --help-all; Brief information on available modules. ; |
---|
249 | print.list-item --help <module-name>; Get information about a module. ; |
---|
250 | print.list-item --help-options; Options for controlling the help display. ; |
---|
251 | print.list-item --help-output <type>; The type of output to genetare. |
---|
252 | '"console" is formated text echoed to the console (the default);' |
---|
253 | '"text" is formated text appended to the output file;' |
---|
254 | '"html" is HTML output to the file.' ; |
---|
255 | print.list-item --help-output-file <file>; The file to output the documentation. ; |
---|
256 | print.list-end ; |
---|
257 | } |
---|
258 | |
---|
259 | # Generate Jam/Boost.Jam command usage information. |
---|
260 | # |
---|
261 | local rule print-help-usage ( ) |
---|
262 | { |
---|
263 | print.section "Boost.Jam Usage" |
---|
264 | "bjam [ options... ] targets..." |
---|
265 | ; |
---|
266 | print.list-start ; |
---|
267 | print.list-item -a; |
---|
268 | Build all targets, even if they are current. ; |
---|
269 | print.list-item -fx; |
---|
270 | Read '"x"' as the Jamfile for building instead of searching |
---|
271 | for the Boost.Build system. ; |
---|
272 | print.list-item -jx; |
---|
273 | Run up to '"x"' commands concurrently. ; |
---|
274 | print.list-item -n; |
---|
275 | Do not execute build commands. Instead print out the commands |
---|
276 | as they would be executed if building. ; |
---|
277 | print.list-item -ox; |
---|
278 | Write the build commands to the file '"x"'. ; |
---|
279 | print.list-item -q; |
---|
280 | Quit as soon as the build of a target fails. Specifying this prevents the |
---|
281 | attempt of building as many targets as possible regardless of failures. ; |
---|
282 | print.list-item -sx=y; |
---|
283 | Sets a Jam variable '"x"' to the value '"y"', overriding any value that |
---|
284 | variable would have from the environment. ; |
---|
285 | print.list-item -tx; |
---|
286 | Rebuild the target '"x"', even if it is up-to-date. ; |
---|
287 | print.list-item -v; |
---|
288 | Display the version of bjam. ; |
---|
289 | print.list-item --x; |
---|
290 | Option '"x"' is ignored but considered and option. The option is then |
---|
291 | available from the '"ARGV"' variable. ; |
---|
292 | print.list-item -dn; |
---|
293 | Enables output of diagnostic messages. The debug level '"n"' and all |
---|
294 | below it are enabled by this option. ; |
---|
295 | print.list-item -d+n; |
---|
296 | Enables output of diagnostic messages. Only the output for debug level '"n"' |
---|
297 | is enabled. ; |
---|
298 | print.list-end ; |
---|
299 | print.section "Debug Levels" |
---|
300 | Each debug level shows a different set of information. Usually with the higher |
---|
301 | levels producing more verbose information. The following levels are supported: |
---|
302 | ; |
---|
303 | print.list-start ; |
---|
304 | print.list-item 0; |
---|
305 | Turn off all diagnostic output. Only errors are reported. ; |
---|
306 | print.list-item 1; |
---|
307 | Show the actions taken for building targets, as they are executed. ; |
---|
308 | print.list-item 2; |
---|
309 | Show "quiet" actions and display all action text, as they are executed. ; |
---|
310 | print.list-item 3; |
---|
311 | Show dependency analysis, and target/source timestamps/paths. ; |
---|
312 | print.list-item 4; |
---|
313 | Show arguments of shell invocations. ; |
---|
314 | print.list-item 5; |
---|
315 | Show rule invocations and variable expansions. ; |
---|
316 | print.list-item 6; |
---|
317 | Show directory/header file/archive scans, and attempts at binding to targets. ; |
---|
318 | print.list-item 7; |
---|
319 | Show variable settings. ; |
---|
320 | print.list-item 8; |
---|
321 | Show variable fetches, variable expansions, and evaluation of '"if"' expressions. ; |
---|
322 | print.list-item 9; |
---|
323 | Show variable manipulation, scanner tokens, and memory usage. ; |
---|
324 | print.list-item 10; |
---|
325 | Show execution times for rules. ; |
---|
326 | print.list-item 11; |
---|
327 | Show parsing progress of Jamfiles. ; |
---|
328 | print.list-item 12; |
---|
329 | Show graph for target dependencies. ; |
---|
330 | print.list-item 13; |
---|
331 | Show changes in target status (fate). ; |
---|
332 | print.list-end ; |
---|
333 | } |
---|
334 | |
---|
335 | # Generates description of options controlling the help system. |
---|
336 | # This automatically reads the options as all variables in the doc |
---|
337 | # module of the form ".option.*". |
---|
338 | # |
---|
339 | local rule print-help-options ( |
---|
340 | module-name # The doc module. |
---|
341 | ) |
---|
342 | { |
---|
343 | print.section "Help Options" |
---|
344 | These are all the options available for enabling or disabling |
---|
345 | to control the help system in various ways. Options can be enabled |
---|
346 | or disabled with '"--help-enable-<option>"', and "'--help-disable-<option>'" |
---|
347 | respectively. |
---|
348 | ; |
---|
349 | local options-to-list = [ MATCH ^[.]option[.](.*) : $($(module-name).variables) ] ; |
---|
350 | if $(options-to-list) |
---|
351 | { |
---|
352 | print.list-start ; |
---|
353 | for local option in [ sequence.insertion-sort $(options-to-list) ] |
---|
354 | { |
---|
355 | local def = disabled ; |
---|
356 | if $($(module-name)..option.$(option).default) != "(empty)" |
---|
357 | { |
---|
358 | def = enabled ; |
---|
359 | } |
---|
360 | print.list-item $(option): $($(module-name)..option.$(option).docs) |
---|
361 | Default is $(def). ; |
---|
362 | } |
---|
363 | print.list-end ; |
---|
364 | } |
---|
365 | } |
---|
366 | |
---|
367 | # Generate brief documentation for all the known items in the section |
---|
368 | # for a module. Possible sections are: "rules", and "variables". |
---|
369 | # |
---|
370 | local rule print-help-module-section ( |
---|
371 | module # The module name. |
---|
372 | section # rules or variables. |
---|
373 | : section-head # The title of the section. |
---|
374 | section-description * # The detailed description of the section. |
---|
375 | ) |
---|
376 | { |
---|
377 | if $($(module).$(section)) |
---|
378 | { |
---|
379 | print.section $(section-head) $(section-description) ; |
---|
380 | print.list-start ; |
---|
381 | for local item in [ sequence.insertion-sort $($(module).$(section)) ] |
---|
382 | { |
---|
383 | local show = ; |
---|
384 | if ! $($(module).$(item).is-local) |
---|
385 | { |
---|
386 | show = yes ; |
---|
387 | } |
---|
388 | if $(.option.show-locals) |
---|
389 | { |
---|
390 | show = yes ; |
---|
391 | } |
---|
392 | if $(show) |
---|
393 | { |
---|
394 | print.list-item $(item): $($(module).$(item).brief) ; |
---|
395 | } |
---|
396 | } |
---|
397 | print.list-end ; |
---|
398 | } |
---|
399 | } |
---|
400 | |
---|
401 | # Generate documentation for possible modules. We attempt to list all known |
---|
402 | # modules, and a brief description of each. |
---|
403 | # |
---|
404 | local rule print-help-all ( |
---|
405 | ignored # Usually the module name, but is ignored here. |
---|
406 | ) |
---|
407 | { |
---|
408 | print.section "Modules" |
---|
409 | "These are all the known modules. Use --help <module> to get more" |
---|
410 | "detailed information." |
---|
411 | ; |
---|
412 | if $(documented-modules) |
---|
413 | { |
---|
414 | print.list-start ; |
---|
415 | for local module-name in [ sequence.insertion-sort $(documented-modules) ] |
---|
416 | { |
---|
417 | # The brief docs for each module. |
---|
418 | print.list-item $(module-name): $($(module-name).brief) ; |
---|
419 | } |
---|
420 | print.list-end ; |
---|
421 | } |
---|
422 | # The documentation for each module when details are requested. |
---|
423 | if $(documented-modules) && $(.option.detailed) |
---|
424 | { |
---|
425 | for local module-name in [ sequence.insertion-sort $(documented-modules) ] |
---|
426 | { |
---|
427 | # The brief docs for each module. |
---|
428 | print-help-module $(module-name) ; |
---|
429 | } |
---|
430 | } |
---|
431 | } |
---|
432 | |
---|
433 | # Generate documentation for a module. Basic information about |
---|
434 | # the module is generated. |
---|
435 | # |
---|
436 | local rule print-help-module ( |
---|
437 | module-name # The module to generate docs for. |
---|
438 | ) |
---|
439 | { |
---|
440 | # Print the docs. |
---|
441 | print.section "Module '$(module-name)'" $($(module-name).docs) ; |
---|
442 | |
---|
443 | # Print out the documented classes. |
---|
444 | print-help-module-section $(module-name) classes : "Module '$(module-name)' classes" |
---|
445 | Use --help $(module-name).<class-name> to get more information. ; |
---|
446 | |
---|
447 | # Print out the documented rules. |
---|
448 | print-help-module-section $(module-name) rules : "Module '$(module-name)' rules" |
---|
449 | Use --help $(module-name).<rule-name> to get more information. ; |
---|
450 | |
---|
451 | # Print out the documented variables. |
---|
452 | print-help-module-section $(module-name) variables : "Module '$(module-name)' variables" |
---|
453 | Use --help $(module-name).<variable-name> to get more information. ; |
---|
454 | |
---|
455 | # Print out all the same information but indetailed form. |
---|
456 | if $(.option.detailed) |
---|
457 | { |
---|
458 | print-help-classes $(module-name) ; |
---|
459 | print-help-rules $(module-name) ; |
---|
460 | print-help-variables $(module-name) ; |
---|
461 | } |
---|
462 | } |
---|
463 | |
---|
464 | # Generate documentation for a set of rules in a module. |
---|
465 | # |
---|
466 | local rule print-help-rules ( |
---|
467 | module-name # Module of the rules. |
---|
468 | : name * # Optional list of rules to describe. |
---|
469 | ) |
---|
470 | { |
---|
471 | name ?= $($(module-name).rules) ; |
---|
472 | if [ set.intersection $(name) : $($(module-name).rules) $($(module-name).class-rules) ] |
---|
473 | { |
---|
474 | # Print out the given rules. |
---|
475 | for local rule-name in [ sequence.insertion-sort $(name) ] |
---|
476 | { |
---|
477 | if $(.option.show-locals) || ! $($(module-name).$(rule-name).is-local) |
---|
478 | { |
---|
479 | local signature = $($(module-name).$(rule-name).signature:J=" ") ; |
---|
480 | signature ?= "" ; |
---|
481 | print.section "Rule '$(module-name).$(rule-name) ( $(signature) )'" |
---|
482 | $($(module-name).$(rule-name).docs) ; |
---|
483 | if $($(module-name).$(rule-name).args) |
---|
484 | { |
---|
485 | print.list-start ; |
---|
486 | for local arg-name in $($(module-name).$(rule-name).args) |
---|
487 | { |
---|
488 | print.list-item $(arg-name): $($(module-name).$(rule-name).args.$(arg-name).docs) ; |
---|
489 | } |
---|
490 | print.list-end ; |
---|
491 | } |
---|
492 | } |
---|
493 | } |
---|
494 | } |
---|
495 | } |
---|
496 | |
---|
497 | # Generate documentation for a set of classes in a module. |
---|
498 | # |
---|
499 | local rule print-help-classes ( |
---|
500 | module-name # Module of the classes. |
---|
501 | : name * # Optional list of classes to describe. |
---|
502 | ) |
---|
503 | { |
---|
504 | name ?= $($(module-name).classes) ; |
---|
505 | if [ set.intersection $(name) : $($(module-name).classes) ] |
---|
506 | { |
---|
507 | # Print out the given classes. |
---|
508 | for local class-name in [ sequence.insertion-sort $(name) ] |
---|
509 | { |
---|
510 | if $(.option.show-locals) || ! $($(module-name).$(class-name).is-local) |
---|
511 | { |
---|
512 | local signature = $($(module-name).$(class-name).signature:J=" ") ; |
---|
513 | signature ?= "" ; |
---|
514 | print.section "Class '$(module-name).$(class-name) ( $(signature) )'" |
---|
515 | $($(module-name).$(class-name).docs) |
---|
516 | "Inherits from '"$($(module-name).$(class-name).super-name)"'." ; |
---|
517 | if $($(module-name).$(class-name).args) |
---|
518 | { |
---|
519 | print.list-start ; |
---|
520 | for local arg-name in $($(module-name).$(class-name).args) |
---|
521 | { |
---|
522 | print.list-item $(arg-name): $($(module-name).$(class-name).args.$(arg-name).docs) ; |
---|
523 | } |
---|
524 | print.list-end ; |
---|
525 | } |
---|
526 | } |
---|
527 | |
---|
528 | # Print out the documented rules of the class. |
---|
529 | print-help-module-section $(module-name) $(class-name).class-rules : "Class '$(module-name).$(class-name)' rules" |
---|
530 | Use --help $(module-name).<rule-name> to get more information. ; |
---|
531 | |
---|
532 | # Print out all the rules if details are requested. |
---|
533 | if $(.option.detailed) |
---|
534 | { |
---|
535 | print-help-rules $(module-name) : $($(module-name).$(class-name).class-rules) ; |
---|
536 | } |
---|
537 | } |
---|
538 | } |
---|
539 | } |
---|
540 | |
---|
541 | # Generate documentation for a set of variables in a module. |
---|
542 | # |
---|
543 | local rule print-help-variables ( |
---|
544 | module-name ? # Module of the variables. |
---|
545 | : name * # Optional list of variables to describe. |
---|
546 | ) |
---|
547 | { |
---|
548 | name ?= $($(module-name).variables) ; |
---|
549 | if [ set.intersection $(name) : $($(module-name).variables) ] |
---|
550 | { |
---|
551 | # Print out the given variables. |
---|
552 | for local variable-name in [ sequence.insertion-sort $(name) ] |
---|
553 | { |
---|
554 | print.section "Variable '$(module-name).$(variable-name)'" $($(module-name).$(variable-name).docs) ; |
---|
555 | if $($(module-name).$(variable-name).default) || |
---|
556 | $($(module-name).$(variable-name).initial) |
---|
557 | { |
---|
558 | print.list-start ; |
---|
559 | if $($(module-name).$(variable-name).default) |
---|
560 | { |
---|
561 | print.list-item "default value:" '$($(module-name).$(variable-name).default:J=" ")' ; |
---|
562 | } |
---|
563 | if $($(module-name).$(variable-name).initial) |
---|
564 | { |
---|
565 | print.list-item "initial value:" '$($(module-name).$(variable-name).initial:J=" ")' ; |
---|
566 | } |
---|
567 | print.list-end ; |
---|
568 | } |
---|
569 | } |
---|
570 | } |
---|
571 | } |
---|
572 | |
---|
573 | local rule __test__ |
---|
574 | { |
---|
575 | } |
---|
576 | |
---|
577 | ws = " " ; |
---|
578 | |
---|
579 | # Extract the text from a block of comments. |
---|
580 | # |
---|
581 | local rule extract-comment ( |
---|
582 | var # The name of the variable to extract from. |
---|
583 | ) |
---|
584 | { |
---|
585 | local comment = ; |
---|
586 | local line = $($(var)[1]) ; |
---|
587 | local l = [ MATCH "^[$(ws)]*(#)(.*)$" : $(line) ] ; |
---|
588 | while $(l[1]) && $($(var)) |
---|
589 | { |
---|
590 | if $(l[2]) { comment += [ MATCH "^[$(ws)](.*)$" : $(l[2]) ] ; } |
---|
591 | else { comment += "" ; } |
---|
592 | $(var) = $($(var)[2-]) ; |
---|
593 | line = $($(var)[1]) ; |
---|
594 | l = [ MATCH "^[$(ws)]*(#)(.*)$" : $(line) ] ; |
---|
595 | } |
---|
596 | return $(comment) ; |
---|
597 | } |
---|
598 | |
---|
599 | # Extract s single line of Jam syntax, ignoring any comments. |
---|
600 | # |
---|
601 | local rule extract-syntax ( |
---|
602 | var # The name of the variable to extract from. |
---|
603 | ) |
---|
604 | { |
---|
605 | local syntax = ; |
---|
606 | local line = $($(var)[1]) ; |
---|
607 | while ! $(syntax) && ! [ MATCH "^[$(ws)]*(#)" : $(line) ] && $($(var)) |
---|
608 | { |
---|
609 | local m = [ MATCH "^[$(ws)]*(.*)$" : $(line) ] ; |
---|
610 | if $(m) && ! $(m) = "" |
---|
611 | { |
---|
612 | syntax = $(m) ; |
---|
613 | } |
---|
614 | $(var) = $($(var)[2-]) ; |
---|
615 | line = $($(var)[1]) ; |
---|
616 | } |
---|
617 | return $(syntax) ; |
---|
618 | } |
---|
619 | |
---|
620 | # Extract the next token, this is either a single Jam construct |
---|
621 | # or a comment as a single token. |
---|
622 | # |
---|
623 | local rule extract-token ( |
---|
624 | var # The name of the variable to extract from. |
---|
625 | ) |
---|
626 | { |
---|
627 | local parts = ; |
---|
628 | while ! $(parts) |
---|
629 | { |
---|
630 | parts = [ MATCH "^[$(ws)]*([^$(ws)]+)[$(ws)]*(.*)" : $($(var)[1]) ] ; |
---|
631 | if ! $(parts) |
---|
632 | { |
---|
633 | $(var) = $($(var)[2-]) ; |
---|
634 | } |
---|
635 | } |
---|
636 | local token = ; |
---|
637 | if [ MATCH "^(#)" : $(parts[1]) ] |
---|
638 | { |
---|
639 | token = $(parts:J=" ") ; |
---|
640 | $(var) = $($(var)[2-]) ; |
---|
641 | } |
---|
642 | else |
---|
643 | { |
---|
644 | token = $(parts[1]) ; |
---|
645 | $(var) = $(parts[2-]:J=" ") $($(var)[2-]) ; |
---|
646 | } |
---|
647 | return $(token) ; |
---|
648 | } |
---|
649 | |
---|
650 | # Scan for a rule declaration as the next item in the variable. |
---|
651 | # |
---|
652 | local rule scan-rule ( |
---|
653 | syntax ? # The first part of the text which contains the rule declaration. |
---|
654 | : var # The name of the variable to extract from. |
---|
655 | ) |
---|
656 | { |
---|
657 | local rule-parts = |
---|
658 | [ MATCH "^[$(ws)]*(rule|local[$(ws)]*rule)[$(ws)]+([^$(ws)]+)[$(ws)]*(.*)" : $(syntax:J=" ") ] ; |
---|
659 | if $(rule-parts[1]) |
---|
660 | { |
---|
661 | # mark as doc for rule. |
---|
662 | local rule-name = $(rule-parts[2]) ; |
---|
663 | if $(scope-name) |
---|
664 | { |
---|
665 | rule-name = $(scope-name).$(rule-name) ; |
---|
666 | } |
---|
667 | local is-local = [ MATCH "^(local).*" : $(rule-parts[1]) ] ; |
---|
668 | if $(comment-block) |
---|
669 | { |
---|
670 | set-rule-doc $(rule-name) $(module-name) $(is-local) : $(comment-block) ; |
---|
671 | } |
---|
672 | # parse args of rule. |
---|
673 | $(var) = $(rule-parts[3-]) $($(var)) ; |
---|
674 | set-rule-arguments-signature $(rule-name) $(module-name) : [ scan-rule-arguments $(var) ] ; |
---|
675 | # scan within this rules scope. |
---|
676 | local scope-level = [ extract-token $(var) ] ; |
---|
677 | local scope-name = $(rule-name) ; |
---|
678 | while $(scope-level) |
---|
679 | { |
---|
680 | local comment-block = [ extract-comment $(var) ] ; |
---|
681 | local syntax-block = [ extract-syntax $(var) ] ; |
---|
682 | if [ scan-rule $(syntax-block) : $(var) ] |
---|
683 | { |
---|
684 | } |
---|
685 | else if [ MATCH "^(\\{)" : $(syntax-block) ] |
---|
686 | { |
---|
687 | scope-level += "{" ; |
---|
688 | } |
---|
689 | else if [ MATCH "^[^\\}]*([\\}])[$(ws)]*$" : $(syntax-block) ] |
---|
690 | { |
---|
691 | scope-level = $(scope-level[2-]) ; |
---|
692 | } |
---|
693 | } |
---|
694 | |
---|
695 | return true ; |
---|
696 | } |
---|
697 | } |
---|
698 | |
---|
699 | # Scan the arguments of a rule. |
---|
700 | # |
---|
701 | local rule scan-rule-arguments ( |
---|
702 | var # The name of the variable to extract from. |
---|
703 | ) |
---|
704 | { |
---|
705 | local arg-syntax = ; |
---|
706 | local token = [ extract-token $(var) ] ; |
---|
707 | while $(token) != "(" && $(token) != "{" |
---|
708 | { |
---|
709 | token = [ extract-token $(var) ] ; |
---|
710 | } |
---|
711 | if $(token) != "{" |
---|
712 | { |
---|
713 | token = [ extract-token $(var) ] ; |
---|
714 | } |
---|
715 | local arg-signature = ; |
---|
716 | while $(token) != ")" && $(token) != "{" |
---|
717 | { |
---|
718 | local arg-name = ; |
---|
719 | local arg-qualifier = " " ; |
---|
720 | local arg-doc = ; |
---|
721 | if $(token) = ":" |
---|
722 | { |
---|
723 | arg-signature += $(token) ; |
---|
724 | token = [ extract-token $(var) ] ; |
---|
725 | } |
---|
726 | arg-name = $(token) ; |
---|
727 | arg-signature += $(token) ; |
---|
728 | token = [ extract-token $(var) ] ; |
---|
729 | if [ MATCH "^([\\*\\+\\?])" : $(token) ] |
---|
730 | { |
---|
731 | arg-qualifier = $(token) ; |
---|
732 | arg-signature += $(token) ; |
---|
733 | token = [ extract-token $(var) ] ; |
---|
734 | } |
---|
735 | if $(token) = ":" |
---|
736 | { |
---|
737 | arg-signature += $(token) ; |
---|
738 | token = [ extract-token $(var) ] ; |
---|
739 | } |
---|
740 | if [ MATCH "^(#)" : $(token) ] |
---|
741 | { |
---|
742 | $(var) = $(token) $($(var)) ; |
---|
743 | arg-doc = [ extract-comment $(var) ] ; |
---|
744 | token = [ extract-token $(var) ] ; |
---|
745 | } |
---|
746 | set-argument-doc $(arg-name) $(arg-qualifier) $(rule-name) $(module-name) : $(arg-doc) ; |
---|
747 | } |
---|
748 | while $(token) != "{" |
---|
749 | { |
---|
750 | token = [ extract-token $(var) ] ; |
---|
751 | } |
---|
752 | $(var) = "{" $($(var)) ; |
---|
753 | arg-signature ?= "" ; |
---|
754 | return $(arg-signature) ; |
---|
755 | } |
---|
756 | |
---|
757 | # Scan for a variable declaration. |
---|
758 | local rule scan-variable ( |
---|
759 | syntax ? # The first part of the text which contains the variable declaration. |
---|
760 | : var # The name of the variable to extract from. |
---|
761 | ) |
---|
762 | { |
---|
763 | # [1] = name, [2] = value(s) |
---|
764 | local var-parts = |
---|
765 | [ MATCH "^[$(ws)]*([^$(ws)]+)[$(ws)]+([\\?\\=]*)[$(ws)]+([^\\;]*)\\;" : $(syntax) ] ; |
---|
766 | if $(var-parts) |
---|
767 | { |
---|
768 | local value = [ MATCH "^(.*)[ ]$" : $(var-parts[3-]:J=" ") ] ; |
---|
769 | local default-value = "" ; |
---|
770 | local initial-valie = "" ; |
---|
771 | if $(var-parts[2]) = "?=" |
---|
772 | { |
---|
773 | default-value = $(value) ; |
---|
774 | default-value ?= "(empty)" ; |
---|
775 | } |
---|
776 | else |
---|
777 | { |
---|
778 | initial-value = $(value) ; |
---|
779 | initial-value ?= "(empty)" ; |
---|
780 | } |
---|
781 | if $(comment-block) |
---|
782 | { |
---|
783 | set-variable-doc $(var-parts[1]) $(default-value) $(initial-value) $(module-name) : $(comment-block) ; |
---|
784 | } |
---|
785 | return true ; |
---|
786 | } |
---|
787 | } |
---|
788 | |
---|
789 | # Scan a class declaration. |
---|
790 | local rule scan-class ( |
---|
791 | syntax ? # The syntax text for the class declaration. |
---|
792 | ) |
---|
793 | { |
---|
794 | # [1] = class?, [2] = name, [3] = superclass |
---|
795 | local class-parts = |
---|
796 | [ MATCH "^[$(ws)]*([^$(ws)]+)[$(ws)]+([^$(ws)]+)[$(ws)]+:*[$(ws)]*([^$(ws);]*)" : $(syntax) ] ; |
---|
797 | if $(class-parts[1]) = "class" || $(class-parts[1]) = "class.class" |
---|
798 | { |
---|
799 | set-class-doc $(class-parts[2]) $(module-name) : $(class-parts[3]) ; |
---|
800 | } |
---|
801 | } |
---|
802 | |
---|
803 | # Scan a module file for documentation comments. This also |
---|
804 | # invokes any actions assigned to the module. The actions |
---|
805 | # are the rules that do the actual output of the documentation. |
---|
806 | # This rue is invoked as the header scan rule for the module file. |
---|
807 | # |
---|
808 | rule scan-module ( |
---|
809 | target # The module file. |
---|
810 | : text * # The text in the file, one item per line. |
---|
811 | : binding |
---|
812 | ) |
---|
813 | { |
---|
814 | if $(.option.debug) { ECHO "HELP:" scanning module target '$(target)' ; } |
---|
815 | local module-name = $(.module<$(target)>.name) ; |
---|
816 | local module-documented = ; |
---|
817 | local comment-block = ; |
---|
818 | local syntax-block = ; |
---|
819 | # This is a hack because we can't get the line of a file if it |
---|
820 | # happens to not have a new-line termination. |
---|
821 | text += "}" ; |
---|
822 | while $(text) |
---|
823 | { |
---|
824 | comment-block = [ extract-comment text ] ; |
---|
825 | syntax-block = [ extract-syntax text ] ; |
---|
826 | if $(.option.debug) |
---|
827 | { |
---|
828 | ECHO "HELP:" comment block; '$(comment-block)' ; |
---|
829 | ECHO "HELP:" syntax block; '$(syntax-block)' ; |
---|
830 | } |
---|
831 | if [ scan-rule $(syntax-block) : text ] { } |
---|
832 | else if [ scan-variable $(syntax-block) : text ] { } |
---|
833 | else if [ scan-class $(syntax-block) ] { } |
---|
834 | else if [ MATCH .*([cC]opyright).* : $(comment-block:J=" ") ] |
---|
835 | { |
---|
836 | # mark as the copy for the module. |
---|
837 | set-module-copyright $(module-name) : $(comment-block) ; |
---|
838 | } |
---|
839 | else if ! $(module-documented) |
---|
840 | { |
---|
841 | # document the module. |
---|
842 | set-module-doc $(module-name) : $(comment-block) ; |
---|
843 | module-documented = true ; |
---|
844 | } |
---|
845 | } |
---|
846 | for local action in $(.module<$(target)>.actions) |
---|
847 | { |
---|
848 | local action-rule = [ $(action).front ] ; $(action).pop-front ; |
---|
849 | local action-args = [ $(action).get ] ; |
---|
850 | local ignored = [ $(action-rule) $(module-name) : $(action-args) ] ; |
---|
851 | } |
---|
852 | } |
---|
853 | |
---|
854 | # Import scan-module to global scope, so that it's available during |
---|
855 | # header scanning phase. |
---|
856 | IMPORT $(__name__) : scan-module : : doc.scan-module ; |
---|
857 | |
---|
858 | |
---|
859 | # Add a scan action to perform to generate the help documentation. |
---|
860 | # The action rule is passed the name of the module as the first argument. |
---|
861 | # The second argument(s) are optional and passed directly as specified |
---|
862 | # here. |
---|
863 | # |
---|
864 | local rule do-scan ( |
---|
865 | modules + # The modules to scan and perform the action on. |
---|
866 | : action * # The action rule, plus the secondary arguments to pass to the action rule. |
---|
867 | ) |
---|
868 | { |
---|
869 | local targets = ; |
---|
870 | for local module-file in $(modules) |
---|
871 | { |
---|
872 | local module-name = $(module-file:B) ; |
---|
873 | .module<$(module-file)>.name = $(module-name) ; |
---|
874 | if $(action) |
---|
875 | { |
---|
876 | .module<$(module-file)>.actions += [ class.new vector $(action) ] ; |
---|
877 | } |
---|
878 | HDRSCAN on $(module-file) = "^(.*).$" ; |
---|
879 | HDRRULE on $(module-file) = doc.scan-module ; |
---|
880 | NOTFILE $(module-name).scan ; |
---|
881 | ALWAYS $(module-name).scan ; |
---|
882 | INCLUDES $(module-name).scan : $(module-file) ; |
---|
883 | targets += $(module-name).scan ; |
---|
884 | } |
---|
885 | if $(help-output) = console |
---|
886 | { |
---|
887 | DEPENDS all : $(targets) ; |
---|
888 | } |
---|
889 | if $(help-output) = text |
---|
890 | { |
---|
891 | print.output $(help-output-file).txt plain ; |
---|
892 | ALWAYS $(help-output-file).txt ; |
---|
893 | DEPENDS $(help-output-file).txt : $(targets) ; |
---|
894 | DEPENDS all : $(help-output-file).txt ; |
---|
895 | } |
---|
896 | if $(help-output) = html |
---|
897 | { |
---|
898 | print.output $(help-output-file).html html ; |
---|
899 | ALWAYS $(help-output-file).html ; |
---|
900 | DEPENDS $(help-output-file).html : $(targets) ; |
---|
901 | DEPENDS all : $(help-output-file).html ; |
---|
902 | } |
---|
903 | } |
---|