Writing code is fun, writing documentation is not. Since comments are obligatory in the code, it would be nice, if documentation could be generated automatically from these comments. This is exactly what this module does: It creates modules, documentation and tests from so called premodules, which differ from modules insofar, that there is
- no license
- no export-clause
- no documentation routine
Instead, those texts are inserted automatically into the final module (provided, a license file and a history file is supplied and referenced in a parameter) as well as into the final documentation, using special comment clauses
#|[ and ]|# each on a line by itself
Note, that #| and |# delimit multiline comments in Chicken, so the spezial clauses above are consistent with chicken syntax.
A standardized routine comment looks like this
#|[ (name . args) ... --- type --- doc ... ]|#
where type is one of
and is enclosed in at least three hyphens on each side.
If type is macro, it can be followed by symbols representing restricted exports of helpers only needed in that macro, e.g.
--- macro *foo* bar ---
This will create an export clause (name *foo* bar) instead of name.
Note, that this comment is placed immediately before the routine's implemenatation, so if the implementation changes signature, the documentation will probably change too. Hence the procedurally created documenation will always be up to date.
Note also, that only exported routines will be commented like this, so the export clause can be generated automatically.
Other standardized comments begin with at least three semicolons and end with at least three semicolons. For example, the body of a premodule starts with
- ;;;;;;;;;;; module loops ;;;;;;;;;;;
and ends with the start of the internal and exported tests
- ;;;;;;;;;;;;;;;;;;; tests ;;;;;;;;;;;;;;;;;;;;
Everything before the module-line is a global Scheme comment and should be encoded as a comment, it will be extended with a copyright notice.
Everything after the test-line with the closing parenthesis is test code, some of it internal, some exported.
Off course, the generated tests depend on the test suite used. It's obvious, that I use my own one, simple-tests. So, exported tests are implemented with define-tester from simple-tests and will be collected and executed by test-all in the generated code.
Internal tests are coded with one of pe, check or ppp and will be ignored in the generated code..
Exported tests go into the automatically generated run.scm and the documentation files. Internal tests are only invoked in the process of coding and ignored in the generated code.
Besides the documentation procedure, premodules, there are only three exported procedures, premodule->module, premodule->tests and premodule->docs and two parameters, history and license.
- premodules symprocedure
the former returns the list of the two exported symbols, and the latter documentation of such a symbol.
- premodule->module pre-file module-fileprocedure
writes the module file from the premodule file.
- premodule->tests pre-file test-fileprocedure
writes the test file from the premodule file.
- premodule->docs pre-file doc-fileprocedure
writes the documentation file from the premodule file.
Besides the premodules file there are three Scheme files
and a Makefile, which, when called, produces three shell routines encapsulating the three Scheme transformers of the premodules module. Copy them into a directory in your path and you can call, e.g.
- premodule2module loops.pre.scm loops.scm
The following is a premodule version of my simple-loops egg. It's called preloops.scm
#|[ some simple loop macros ]|# ;;;;;;;;;;;; module loops ;;;;;;;;;;; (import scheme (chicken base)) #|[ (do-times i upto xpr ....) --- macro --- loops a fixed number of times execute xpr .... for i from 0 to upto ]|# (define-syntax do-times (syntax-rules () ((_ i upto xpr0 xpr1 ...) (let ((n upto)) (let loop ((i 0)) (unless (>= i n) xpr0 xpr1 ... (loop (+ i 1)))))))) (define foo 'foo) ; example of restricted export #|[ (do-list i lst xpr ....) --- macro foo --- execute xpr .... for i in lst ]|# (define-syntax do-list (syntax-rules () ((_ i lst xpr xpr1 ...) (let loop ((sublst lst)) (if (not (null? sublst)) (let ((i (car sublst))) xpr xpr1 ... (loop (cdr sublst)))))))) #|[ (do-for var (start stop step) xpr ....) --- macro --- do xpr .... for var in [start stop[ with steps (default 1) ]|# (define-syntax do-for (syntax-rules () ((_ var (start stop step) xpr xpr1 ...) (let ((%stop stop)) (let loop ((var start)) (unless (>= var %stop) xpr xpr1 ... (loop (+ step var)))))) ((_ var (start stop) xpr . xprs) (do-for var (start stop 1) xpr . xprs)))) #|[ (do-while test? xpr ....) --- macro --- execute xpr .... while test? is true ]|# (define-syntax do-while (syntax-rules () ((_ test? xpr xpr1 ...) (let loop () (if test? (begin xpr xpr1 ... (loop))))))) #|[ (do-until test? xpr ....) --- macro --- execute xpr .... while test? is false ]|# (define-syntax do-until (syntax-rules () ((_ test? xpr xpr1 ...) (let loop () (if (not test?) (begin xpr xpr1 ... (loop))))))) #|[ (do-forever xpr ....) --- macro --- executes body xpr .... until exit is called. The macro is unhygienic on purpose, it exports the exit symbol behind the scene. So it can not be defined with syntax-rules ]|# (define-syntax do-forever (ir-macro-transformer (lambda (form inject compare?) (let ((xpr (cadr form)) (xprs (cddr form))) `(call-with-current-continuation (lambda (,(inject 'exit)) (let loop () ,xpr ,@xprs (loop)))))))) ;;;;;;;;;;;;;;;;;;;; tests ;;;;;;;;;;;;;;;;;;;; ;; to be exported (import simple-tests) ;; to be skipped (ppp (car '(0 1 2 3)) ) ;; to be skipped (check ((lst '(0 1 2 3))) lst '(0 1 2 3) (car lst) 0 (cadr lst) 1 (cddr lst) '(2 3) ) ;; to be exported (define-tester (dos?) (let ((lst '())) (do-for i (1 65 i) (set! lst (cons i lst))) (reverse lst)) '(1 2 4 8 16 32 64) (let ((n 3) (lst '())) (do-forever (if (zero? n) (exit lst)) (set! lst (cons 'a lst)) (set! n (- n 1)))) '(a a a) (let ((lst '())) (do-list i '(1 2 3) (set! lst (cons i lst))) lst) '(3 2 1) (let ((lst '())) (do-times i (+ 2 3) (set! lst (cons i lst))) lst) '(4 3 2 1 0) (let ((n 4) (lst '())) (do-until (> 0 n) (set! lst (cons n lst)) (set! n (- n 1))) lst) '(0 1 2 3 4) (let ((n 4) (lst '())) (do-while (<= 0 n) (set! lst (cons n lst)) (set! n (- n 1))) lst) '(0 1 2 3 4) )
Note, that this is a normal Scheme file, you can run it and look at the result of the internal and exported tests.
The following three calls will write the desired files, loops.scm, run.scm and loops. The only thing you have to do is to copy the files to the appropriate positions. Of course, you can edit these files, if the need arises.
(import premodules) (premodule->module "preloops.scm" "loops.scm") (premodule->tests "preloops.scm" "run.scm") (premodule->docs "preloops.scm" "loops")
But it's much easyer to compile the three new files premodule2module.scm, premodule2tests.scm and premodule2docs.scm with csc, run them with
premoudle2module preloops.scm loops.scm premoudle2tests preloops.scm run.scm premoudle2docs preloops.scm loops
Feb 06, 2021
This egg is hosted on the CHICKEN Subversion repository:
If you want to check out the source code repository of this egg and you are not familiar with Subversion, see this page.
Copyright (c) 2020-2021 , Juergen Lorenz, ju (at) jugilo (dot) de All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. Neither the name of the author nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- support for restricted exports of macro helpers added
- support for define-tester and test-all added
- history, license and local docu updated, Makefile added
- history text outsourced
- premoudle2module, premoudle2docs and premoudle2tests added, license file as parameter
- line in test-file added
- Initial check in