#lang scribble/manual
@(require (planet cce/scheme:6:0/scribble)
scribble/eval
(for-label scheme
(this-package-in defs-parser)))
@(define make-my-eval (make-eval-factory '(scheme
(planet orseau/lazy-doc:1:4/defs-parser))))
@(require (planet cce/scheme:6:0/planet)
(this-package-in defs-parser)
(for-label (this-package-in package)))
@title[#:tag "defs-parser"]{Scribble Definition Parser}
@(defmodule/this-package defs-parser)
@(define (comm . txt) (litchar (apply string-append ";: " txt)))
@(define (ccom . txt) (litchar (string-append ";[:" (apply string-append txt) "]")))
@(define scrbl @filepath{.scrbl})
@(define (my-prog . str) (apply verbatim #:indent 5 str))
This module provides tools to easily write documentation for planet packages.
It builds on the Simple Parser (see @secref{simple-parser}).
The Scribble Definition Parser reads scheme plain text files
and generates a corresponding documentation.
It currently lacks many features and is certainly not perfect
to build fully reliable documentations,
but it can be used at least as a helper to semi-automate the process.
This parser is meant to be used by either lazy people
who don't like documenting sources, or think it takes too much time,
or those that want to document their sources incrementally (i.e.,
do some doc now, do the rest later).
Consider using the built-in inline source documentation of Scribble
if your are not as lazy as me.
Contracts and descriptions of functions and forms
are added as comments in the (plain text) source files.
Most of the job is done automatically by the parser, like writing
function and form names, argument names, keywords and default values,
and even some of the contracts.
It allows for incremental documenting, ranging from writing nothing
to writing restrictive contracts and text.
When contracts are not provided,
the parser tries to use some default conventions (e.g., @scheme[l] is given the contract @scheme[list?]),
and if that fails too, then the most general ones are used.
It is always possible to fall-back to the default Scribble documentation
by using @ccom{skip} before a given definition and then documenting
it as Scribble code inside @comm{} comments.
This parser does not yet use the real contracts used in Scheme sources
and the one used are written inside comments and are
for documentation purposes only (i.e., they are not added to Scheme code).
@section{In-Source Documenting}
The parser provides some comment-commands to document source code
inside the source-code.
@subsection{Documenting Modules}
To write a line of text that will be added to the @scrbl file,
just write a comment starting with @comm{} followed by the text,
which can of course contain scribble commands that will be interpreted
and PLaneT will compile the @scrbl files.
To add a title to the module, just use the command @ccom{title My Title}.
To add a section, use @ccom{section My Section}. Same for subsection.
If you want to use @(litchar "; my text") instead of @comm{my text}
for several lines, surround
the paragraph with the lines @ccom{text} and @ccom{end-text}.
@subsection{Documenting Definitions}
An important part of documenting is to describe definitions (of functions, forms, etc.)
and to give contracts to the arguments.
This parser provides tool to make it simpler in many cases.
It automatically recognizes functions with keywords and default arguments,
some forms (when the head of the form provides information
on how it works), and parameters.
Furthermore, it only parses definitions that the module provides.
It also parses @scheme[require] to correctly output relative paths in the @scrbl file.
See @secref{package} for functions that augment the
@scrbl file with useful information.
If the parser does not (yet) recognize a definition, you can still
document it with scribble functions, preceded by @comm{}.
If the parser fails to properly recognize a definition, you can precede it with the
@ccom{skip} command, and then document it like if the definition is not recognized.
To document a given function, text must be added after the head of the function and before
its body, and must be preceded by @comm{}.
In such text, if the parser reads a $ followed by a scheme identifier (but with no dot in it),
say @(litchar (string-append "$" "foo")),
it is translated into @(litchar "@scheme[foo]").
More complex expressions can of course use directly @(litchar "@scheme[]").
Here is an example on how to write the description text of a function:
@(define prog1
(string-append
"(define (foo x [name 'me])
;: Returns the string \"foo\" followed by $" "x
;: and the $" "name.
( .... ))"))
@(my-prog prog1)
@subsection{Contracts}
It is possible to write contracts for the function arguments
and for the return value:
@(define prog2
(string-append
"(define (foo x [name 'me]) ;:-> string?
;: [x number?]
;: [name symbol?]
;: Returns the string \"foo\" followed by $" "x
;: and the $" "name.
( .... ))"))
@(my-prog prog2)
The return value is preceded by the special comment @(litchar ";:->").
The parser creates only documentation contracts, which do not interfere
with actual contracts defined in Scheme for the module.
A more concise contract definition can be used, without repeating the argument ids:
@(define prog3
(string-append
" (define (foo x ;: number?
[name 'me] ;: symbol?
) ;:-> string?
;: Returns the string \"foo\" followed by $" "x
;: and the $" "name.
( .... ))"))
@(my-prog prog3)
This will be translated to:
@(my-prog (scrbl-parse-text prog3))
If a contract is not given, it defaults to @scheme[any] or @scheme[any/c], except
when a convention can be used.
@subsection{Conventions}
Sometimes the programmer uses untold conventions for
function argument ids, like @scheme[lst] for a list, @scheme[str] for a string, etc.
The parser can take advantage of such conventions to avoid writing such
obvious contracts.
For example:
@(define conv-example
(string-append
";[:convention x number?]
;[:convention z (listof string?)]
(define (foo x) ;:-> z
;: This is $" "foo.
(....))
(define (bar x) ;:-> z
;: This is $" "bar.
(....))"))
@(my-prog conv-example)
will be translated to:
@(my-prog (scrbl-parse-text conv-example))
The convention is applied to all remaining functions (but is not applied backwards).
Conventions added when parsing the source file do not persist
for future parsing of other source files.
@(remove-convention "x")
@(remove-convention "z")
There also exists the @ccom{remove-convention x} to remove a convention that was previously
bound to @scheme[x], and also @ccom{remove-all-conventions}.
Some default conventions are already defined:
@(tabular
(map (λ(row)(list (verbatim (car row)) (verbatim " : ") (verbatim " " (cdr row))))
(reverse (conventions))))
They have less priority than local conventions, which have less priority than
per-definition contracts.
Others may be added in future versions or upon request.
Conventions can also be managed programmatically using @scheme[add-convention],
@scheme[remove-convention], @scheme[remove-all-conventions], and the @scheme[conventions] parameter.
@subsection{Writing Examples}
To insert examples of interactions, surround your examples
with @ccom{examples} and @ccom{end-examples}. It uses the @scheme[@examples]
scribble function, but automatically creates an evaluator that requires the current module.
Examples must be preceded by @(litchar ";") and not @comm{}.
For example:
@(define example-example
";[:examples]
; (+ 2 7)
; (display \"plop\")
;[:end-examples]")
@(my-prog example-example)
will be translated to:
@(my-prog (scrbl-parse-text example-example))
where @scheme[(make-my-eval)] is defined in the generated
@scrbl file when using functions of the module @secref{package}.
@section{Definitions}
The following definitions are provided
to allow for possible extensions or modifications of the parser's default behavior
but are not necessary to generate scribble documentation.
To generate @scrbl files with this parser,
see the @secref{package} module.
@(require (for-label
(this-package-in simple-parser)
(this-package-in common)
))
@;NOT-PROVIDED[comm-re]
@defparam[conventions x any/c]{
A parameter that holds the current dictionary of conventions.
}
@defproc[(add-convention [ w string? ] [ con string? ]) void?]{
Adds a module-wise convention.
For example, if the parser reads @ccom{convention text string?}
then all following argument named @scheme[text] will be given the contract @scheme[string?] by default.
This behavior does not have the priority on per-definition contracts.
}
@defproc[(remove-convention [ w string? ]) void?]{
Removes a convention module-wise.
}
@defproc[(remove-all-conventions) void?]{
Removes all conventions module-wise.
}
@;NOT-PROVIDED[get-contract]
@;NOT-PROVIDED[get-out-contract]
@;NOT-PROVIDED[skipped]
@;NOT-PROVIDED[provided]
@;NOT-PROVIDED[provided?]
@;NOT-PROVIDED[not-provided]
@;NOT-PROVIDED[arg->string]
@;NOT-PROVIDED[modif-arg]
@defproc[(scrbl-parse-text [#:phase phase any/c 'start] [#:prov prov any/c #t] [ text string? ] ...) string?]{
Parses @scheme[text] with the scribble definition parser.
A list of provided definitions can be given to @scheme[prov] so that
only them are parsed.
}
@;NOT-PROVIDED[this-filename]
@defproc[(scrbl-parse-file [ filename string? ] [ ext string? ] [ prov any/c #t]) string?]{
Parses the scheme plain text source file @scheme[filename].@scheme[ext] and returns its documentation string.
The parsed-file should be in the @scheme[current-directory].
By default, all definitions are parsed, but only a subset is currently supported,
like functions, parameters, and forms of the type @scheme[(id . arg)].
Like for @scheme[scrbl-parse-text], a list of provided definitions can be supplied.
}