1. Rationale
    1. API
      1. premodules
      2. premodule->module
      3. premodule->tests
      4. premodule->docs
    2. Example
  2. Requirements
  3. Last update
  4. Author
  5. License
  6. Version history

Rationale

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, 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 procedure, macro or parameter and is enclosed in at least three hyphens on each side

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.

Exported tests are implemented with define-checks, internal tests with one of the ppp macros or check frome the simple-tests egg. The former go into the automatically generated run.scm and the documentation files, the latter are only invoked in the process of coding and ignored in the generated code.

API

Besides the documentation procedure, premodules, there are only three exported procedures, premodule->module, premodule->tests and premodule->docs.

premodules

[procedure] (premodules)
[procedure] (premodules sym)

the former returns the list of the two exported symbols, and the latter documentation of such a symbol.

premodule->module

[procedure] (premodule->module pre-file module-file)

writes the module file from the premodule file.

premodule->tests

[procedure] (premodule->tests pre-file test-file)

writes the test file from the premodule file.

premodule->docs

[procedure] (premodule->docs pre-file doc-file)

writes the documentation file from the premodule file.

Example

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))))))))

#|[
(do-list i lst xpr ....)
--- macro ---
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-checks (dos verbose?)

  (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.


(premodule->module "preloops.scm" "loops.scm")
(premodule->tests "preloops.scm" "run.scm")
(premodule->docs "preloops.scm" "loops")

Requirements

simple-tests

Last update

May 26, 2020

Author

Juergen Lorenz

License

Copyright (c) 2020 , 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.

Version history

0.1
Initial check in