wisp
 
(Arne Babenhauserheide)
2017-10-17: install language/wisp.scm + debugging stable v0.9.7

install language/wisp.scm + debugging

diff --git a/.bugs/bugs b/.bugs/bugs
--- a/.bugs/bugs
+++ b/.bugs/bugs
@@ -14,6 +14,7 @@ multiple escaped initial underscores mus
 wisp: handle general paren prefixes like quote, quasiquote, etc. | owner:, open:False, id:323ff94b5be635742619467e1cb44f4c0d96f63f, time:1379047798.47
 throw an exception when reducing indentation to an unknown indentation level. | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:424186bd85f186b7279c5c59e2bd42f847284719, time:1376003568.91
 LANG=C breaks bootstrap: python encoding error: it uses ascii. | owner:, open:True, id:43c7461bfb6f35a90ff3f4497c8232e2457ce1c7, time:1427819877.7
+bootstrapping does not pre-compile correctly anymore         | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:499afb16915b64d56aff710d292b46ddaa060869, time:1507501352.6
 wisp-in-wisp: only parses the first 272 lines, for some reason. | owner:, open:False, id:4cb6c556d7136609e2da9ab3fc045a39847f1ef3, time:1377014682.98
 adjust runtests.sh to use testrunner.w                       | owner:, open:False, id:4d4e76343fe09f0ec72a3e5eb0077bd16e12f9d5, time:1415127234.43
 wisp-scheme: REPL: sometimes the output of a command is only shown after typing the next non-empty line. | owner:, open:False, id:56d2f81e9c89accb0b0bc668ddc8feed3b60e9b2, time:1416584789.23
diff --git a/.bugs/details/499afb16915b64d56aff710d292b46ddaa060869.txt b/.bugs/details/499afb16915b64d56aff710d292b46ddaa060869.txt
new file mode 100644
--- /dev/null
+++ b/.bugs/details/499afb16915b64d56aff710d292b46ddaa060869.txt
@@ -0,0 +1,31 @@
+# Lines starting with '#' and sections without content
+# are not displayed by a call to 'details'
+#
+[paths]
+# Paths related to this bug.
+# suggested format: REPO_PATH:LINENUMBERS
+
+
+[details]
+# Additional details
+
+
+[expected]
+# The expected result
+
+
+[actual]
+# What happened instead
+
+
+[reproduce]
+# Reproduction steps
+wget https://bitbucket.org/ArneBab/wisp/downloads/wisp-0.9.6.tar.gz;
+tar xf wisp-0.9.6.tar.gz ; cd wisp-0.9.6/;
+./configure; make check;
+examples/newbase60.w 123
+
+^ shows compilation errors which go away after a short guile ... -c '(import (language wisp spec))'
+
+[comments]
+# Comments and updates - leave your name
diff --git a/Makefile.am b/Makefile.am
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
 SUFFIXES = .w .scm .sh
 
 sitedir = $(GUILE_SITE)
-site_DATA = wisp-scheme.scm
+site_DATA = language/wisp.scm
 
 langdir = ${datarootdir}/guile/site/$(GUILE_EFFECTIVE_VERSION)/language/wisp
 lang_DATA = language/wisp/spec.scm language/wisp.scm
diff --git a/NEWS b/NEWS
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,8 @@
 wisp ():
 
+wisp 0.9.7:
+- FIX: install language/wisp.scm instead of wisp-scheme.scm
+
 wisp 0.9.6:
 - Add a warning with undefined indentation levels: they can
   produce surprising behaviour when changing existing code.
diff --git a/configure.ac b/configure.ac
--- a/configure.ac
+++ b/configure.ac
@@ -1,7 +1,7 @@
 dnl run `autoreconf -i` to generate a configure script. 
 dnl Then run ./configure to generate a Makefile.
 dnl Finally run make to generate the project.
-AC_INIT([wisp], [0.9.6],
+AC_INIT([wisp], [0.9.7],
         [arne_bab@web.de])
 # Add macros in m4/ to ensure that wisp builds without having Guile in the aclocal path
 AC_CONFIG_MACRO_DIR([m4])
diff --git a/examples/benchmark.w b/examples/benchmark.w
--- a/examples/benchmark.w
+++ b/examples/benchmark.w
@@ -76,10 +76,10 @@ define* : benchmark-run fun
           : res : list-ec (: i sampling-steps) : benchmark-run-single fun #:min-seconds min-seconds
             std : stddev-unbiased-normal res
             mean : / (apply + res) sampling-steps
-           ;; pretty-print : list mean '± std min-seconds sampling-steps
-           if : or {sampling-steps > max-iterations} : and {std < {mean * max-relative-uncertainty}} {std < max-absolute-uncertainty-seconds}
-              . mean
-              lp (* 2 min-seconds) (* 2 sampling-steps) ;; should decrease σ by factor 2 or √2 (for slow functions)
+          ;; pretty-print : list mean '± std min-seconds sampling-steps
+          if : or {sampling-steps > max-iterations} : and {std < {mean * max-relative-uncertainty}} {std < max-absolute-uncertainty-seconds}
+             . mean
+             lp (* 2 min-seconds) (* 2 sampling-steps) ;; should decrease σ by factor 2 or √2 (for slow functions)
 
 define loopcost
   benchmark-run (λ() #f)
diff --git a/examples/doctests-test.scm b/examples/doctests-test.scm
--- a/examples/doctests-test.scm
+++ b/examples/doctests-test.scm
@@ -1,4 +1,5 @@
 #!/usr/bin/env sh
+# -*- scheme -*-
 exec guile -L $(dirname $(dirname $(realpath "$0"))) -e '(@@ (examples doctests-test) main)' -s "$0" "$@"
 ; !#
 
@@ -7,18 +8,17 @@ exec guile -L $(dirname $(dirname $(real
 (import (examples doctests))
 
 (define (foo)
-    "(test 'foo
-        (test-equal \"bar\" (foo)))
-    "
+    #((tests
+      ('foo
+        (test-equal "bar" (foo)))))
     "bar")
 
 (define %this-module (current-module))
 (define (main args)
-       " Testing doctests
-   (test 'mytest
-       (test-assert #t)
-       (test-assert #f))
-"
+       " Testing doctests"
+       #((tests ('mytest
+              (test-assert #t)
+              (test-assert #f))))
        (doctests-testmod %this-module))
 
 
diff --git a/examples/doctests-test.w b/examples/doctests-test.w
--- a/examples/doctests-test.w
+++ b/examples/doctests-test.w
@@ -1,7 +1,7 @@
 #!/usr/bin/env sh
 # -*- wisp -*-
-guile -L $(dirname $(dirname $(realpath "$0"))) -c '(import (wisp-scheme) (language wisp spec))'
-exec guile -L $(dirname $(dirname $(realpath "$0"))) --language=wisp -e '(@@ (examples doctests-test) main)' -s "$0" "$@"
+guile -L $(dirname $(dirname $(realpath "$0"))) -c '(import (language wisp spec))'
+exec guile -L $(dirname $(dirname $(realpath "$0"))) -x .w --language=wisp -e '(@@ (examples doctests-test) main)' -s "$0" "$@"
 ; !#
 
 define-module : examples doctests-test
@@ -9,17 +9,16 @@ define-module : examples doctests-test
 import : examples doctests
 
 define : foo
-    . "(test 'foo
-        (test-equal \"bar\" (foo)))
-    "
+    . #((tests 
+      ('foo
+        (test-equal "bar" (foo)))))
     . "bar"
 
 define %this-module : current-module
 define : main args
-       . " Testing doctests
-   (test 'mytest
-       (test-assert #t)
-       (test-assert #f))
-"
+       . " Testing doctests"
+       . #((tests ('mytest
+              (test-assert #t)
+              (test-assert #f))))
        doctests-testmod %this-module
 
diff --git a/examples/doctests-testone.scm b/examples/doctests-testone.scm
--- a/examples/doctests-testone.scm
+++ b/examples/doctests-testone.scm
@@ -1,13 +1,14 @@
 #!/usr/bin/env sh
+# -*- scheme -*-
 exec guile -L $(dirname $(dirname $(realpath "$0"))) -s "$0" "$@"
 ; !#
 
 (import (examples doctests))
 
 (define (foo)
-    "(test 'foo
-        (test-equal \"bar\" (foo)))
-    "
+    #((tests 
+      ('foo
+        (test-equal "bar" (foo)))))
     "bar")
 
 (doctests-testmod (current-module))
diff --git a/examples/doctests.scm b/examples/doctests.scm
--- a/examples/doctests.scm
+++ b/examples/doctests.scm
@@ -1,13 +1,55 @@
 #!/usr/bin/env sh
+# -*- scheme -*-
 exec guile -L $(dirname $(dirname $(realpath "$0"))) -e '(@@ (examples doctests) main)' -s "$0" "$@"
 ; !#
 
+;;; doctests --- simple testing by adding procedure-properties with tests.
+
+;;; Usage
+
+;; Add a tests property to a procedure to have simple unit tests.
+
+;; Simple tests:
+;;
+;; (define (A)
+;;     #((tests (test-eqv 'A (A))
+;;              (test-assert #t)))
+;;     'A)
+;;
+;; Named tests:
+;;
+;; (define (A)
+;;     #((tests ('test1 (test-eqv 'A (A))
+;;                      (test-assert #t))
+;;              ('test2 (test-assert #t))))
+;;     'A)
+;;
+;; Allows for docstrings:
+;;
+;; (define (A)
+;;     "returns 'A"
+;;     #((tests (test-eqv 'A (A))
+;;              (test-assert #t)))
+;;     'A)
+
+;; For writing the test before the implementation, start with the test and #f:
+
+;; (define (A)
+;;     #((tests (test-eqv 'A (A))))
+;;     #f)
+
+;; With wisp, you currently need to use the literal #((tests (...)))
+;; TODO: add array parsing to wisp following quoting with ':
+;;       # a b → #(a b) and # : a b c → #((a b))
+
+
 (define-module (examples doctests)
               #:export (doctests-testmod))
 
 (import (ice-9 optargs)
          (ice-9 rdelim)
          (ice-9 match)
+         (ice-9 pretty-print)
          (oop goops)
          (texinfo reflection))
 
@@ -35,19 +77,7 @@ exec guile -L $(dirname $(dirname $(real
                  (loop (string-drop s 1) (+ i 1))))))
 
 (define (doctests-extract-from-string s)
-       "Extract all test calls from a given string.
-
-          This is an example test:
-
-          (test 'mytest
-              (define v (make-vector 5 99))
-              (test-assert (vector? v))
-              (test-eqv 99 (vector-ref v 2))
-              (vector-set! v 2 7)
-              (test-eqv 7 (vector-ref v 2)))
-          (test 'mytest2
-              (test-assert #t))
-"
+       "Extract all test calls from a given string."
        (let lp
            ((str s)
              (tests (list)))
@@ -65,50 +95,85 @@ exec guile -L $(dirname $(dirname $(real
                                      (λ () (read)))
                                  tests))))))))
 
+(define (subtract a b)
+    "Subtract B from A."
+    #((tests (test-eqv 3 (subtract 5 2))))
+    (- a b))
+
 (define (doctests-testmod mod)
-       "Execute all doctests in the current module"
+       "Execute all doctests in the current module
+
+          This procedure provides an example test:"
+       #((tests 
+            ('mytest
+              (define v (make-vector 5 99))
+              (test-assert (vector? v))
+              (test-eqv 99 (vector-ref v 2))
+              (vector-set! v 2 7)
+              (test-eqv 7 (vector-ref v 2)))
+            ('mytest2
+              (test-assert #t))))
+       ;; thanks to Vítor De Araújo: https://lists.gnu.org/archive/html/guile-user/2017-08/msg00003.html
        (let*
            ((names (module-map (λ (sym var) sym) mod))
              (filename
-                 (if (module-filename mod) (string-join (string-split (module-filename mod) #\/) "-")
+                 (if (module-filename mod) (string-join (string-split (module-filename mod) #\/ ) "-")
                      (string-join (cons "._" (map symbol->string (module-name mod))) "-")))
-             (docstrings
-                 (map (λ (x) (if (procedure? x) (procedure-documentation x)))
+             (doctests
+                 (map (λ (x) (if (procedure? x) (procedure-property x 'tests)))
                      (map (λ (x) (module-ref mod x)) names))))
            (let loop
                ((names names)
-                 (docstrings docstrings))
-               (when (not (null? docstrings))
-                   (when (string? (car docstrings))
-                       (let*
-                           ((name (car names))
-                             (docstring (car docstrings)))
-                           (let loop-tests
-                              ((doctests (doctests-extract-from-string (car docstrings))))
-                              (when (and (list? doctests) (not (null? doctests)))
-                                 (let*
-                                   ((doctest (car doctests))
-                                     (testid
-                                        (if (not (list? doctest))
-                                             #f
-                                             (string-join (list filename (symbol->string name) (symbol->string (primitive-eval (car (cdr doctest)))))
-                                                         "--")))
-                                     (cleaned
-                                         (if (not (list? doctest))
-                                           '#f
-                                           (append
-                                               (cons 'begin
-                                                   (cons '(import (srfi srfi-64))
-                                                       (cons
-                                                           (list 'test-begin testid)
-                                                           (cdr (cdr doctest)))))
-                                               (list (list 'test-end testid))))))
-                                   (when cleaned
-                                       (let ()
-                                           (eval cleaned mod))
-                                       (newline))
-                                   (loop-tests (cdr doctests)))))))
-                   (loop (cdr names) (cdr docstrings))))))
+                 (doctests doctests))
+               ;; pretty-print doctests
+               ;; newline
+               (when (pair? doctests)
+                   (let*
+                       ((name (car names))
+                         (doctest (car doctests)))
+                       (let loop-tests
+                          ((doctest doctest))
+                          (when (and (pair? doctest) (car doctest) (pair? (car doctest)))
+                             ;; pretty-print : car doctest
+                             ;; newline
+                             (let*
+                               (
+                                 (testid
+                                    (match doctest
+                                      (((('quote id) tests ...) moretests ...)
+                                        (string-join (list filename (symbol->string name) (symbol->string id))
+                                                     "--"))
+                                      ((tests ...)
+                                        (string-join (list filename (symbol->string name))
+                                                     "--"))))
+                                 (body
+                                     (match doctest
+                                      (((('quote id) test tests ...) moretests ...)
+                                        (cons test tests))
+                                      ((tests ...)
+                                        tests)))
+                                 (cleaned
+                                        (cons 'begin
+                                            (cons '(import (srfi srfi-64)) 
+                                                (cons 
+                                                    (list 'test-begin (or testid ""))
+                                                    (append
+                                                        body
+                                                        (list (list 'test-end (or testid "")))))))))
+                               ;; pretty-print testid
+                               ;; pretty-print body
+                               ;; pretty-print cleaned
+                               ;; newline
+                               (when cleaned
+                                   (let ()
+                                       (eval cleaned mod))
+                                   (newline))
+                               (match doctest
+                                      (((('quote id) tests ...) moretests ...)
+                                        (loop-tests moretests))
+                                      ((tests ...)
+                                        #t))))))
+                   (loop (cdr names) (cdr doctests))))))
 
 (define %this-module (current-module))
 (define (main args)
diff --git a/examples/doctests.w b/examples/doctests.w
--- a/examples/doctests.w
+++ b/examples/doctests.w
@@ -1,15 +1,56 @@
 #!/usr/bin/env sh
 # -*- wisp -*-
-guile -L $(dirname $(dirname $(realpath "$0"))) -c '(import (wisp-scheme) (language wisp spec))'
+guile -L $(dirname $(dirname $(realpath "$0"))) -c '(import (language wisp spec))'
 exec guile -L $(dirname $(dirname $(realpath "$0"))) --language=wisp -e '(@@ (examples doctests) main)' -s "$0" "$@"
 ; !#
 
+;;; doctests --- simple testing by adding procedure-properties with tests.
+
+;;; Usage
+
+;; Add a tests property to a procedure to have simple unit tests.
+
+;; Simple tests:
+;;
+;; (define (A)
+;;     #((tests (test-eqv 'A (A))
+;;              (test-assert #t)))
+;;     'A)
+;;
+;; Named tests:
+;;
+;; (define (A)
+;;     #((tests ('test1 (test-eqv 'A (A))
+;;                      (test-assert #t))
+;;              ('test2 (test-assert #t))))
+;;     'A)
+;;
+;; Allows for docstrings:
+;;
+;; (define (A)
+;;     "returns 'A"
+;;     #((tests (test-eqv 'A (A))
+;;              (test-assert #t)))
+;;     'A)
+
+;; For writing the test before the implementation, start with the test and #f:
+
+;; (define (A)
+;;     #((tests (test-eqv 'A (A))))
+;;     #f)
+
+;; With wisp, you currently need to use the literal #((tests (...)))
+;; TODO: add array parsing to wisp following quoting with ':
+;;       # a b → #(a b) and # : a b c → #((a b))
+
+
 define-module : examples doctests
               . #:export : doctests-testmod
 
 import : ice-9 optargs
          ice-9 rdelim
          ice-9 match
+         ice-9 pretty-print
          oop goops
          texinfo reflection
 
@@ -37,19 +78,7 @@ define : string-index s fragment
                  loop (string-drop s 1) (+ i 1)
 
 define : doctests-extract-from-string s
-       . "Extract all test calls from a given string.
-
-          This is an example test:
-
-          (test 'mytest
-              (define v (make-vector 5 99))
-              (test-assert (vector? v))
-              (test-eqv 99 (vector-ref v 2))
-              (vector-set! v 2 7)
-              (test-eqv 7 (vector-ref v 2)))
-          (test 'mytest2
-              (test-assert #t))
-"
+       . "Extract all test calls from a given string."
        let lp
            : str s
              tests : list
@@ -67,50 +96,85 @@ define : doctests-extract-from-string s
                                      λ () : read
                                  . tests
 
+define : subtract a b
+    . "Subtract B from A."
+    . #((tests (test-eqv 3 (subtract 5 2))))
+    - a b
+
 define : doctests-testmod mod
-       . "Execute all doctests in the current module"
+       . "Execute all doctests in the current module
+
+          This procedure provides an example test:"
+       . #((tests 
+            ('mytest
+              (define v (make-vector 5 99))
+              (test-assert (vector? v))
+              (test-eqv 99 (vector-ref v 2))
+              (vector-set! v 2 7)
+              (test-eqv 7 (vector-ref v 2)))
+            ('mytest2
+              (test-assert #t))))
+       ;; thanks to Vítor De Araújo: https://lists.gnu.org/archive/html/guile-user/2017-08/msg00003.html
        let*
            : names : module-map (λ (sym var) sym) mod
              filename
                  if (module-filename mod) (string-join (string-split (module-filename mod) #\/ ) "-")
                      string-join (cons "._" (map symbol->string (module-name mod))) "-"
-             docstrings
-                 map (λ (x) (if (procedure? x) (procedure-documentation x)))
+             doctests
+                 map (λ (x) (if (procedure? x) (procedure-property x 'tests)))
                      map (λ (x) (module-ref mod x)) names
            let loop
                : names names
-                 docstrings docstrings
-               when : not : null? docstrings
-                   when : string? : car docstrings
-                       let*
-                           : name : car names
-                             docstring : car docstrings
-                           let loop-tests
-                              : doctests : doctests-extract-from-string : car docstrings
-                              when : and (list? doctests) : not : null? doctests
-                                 let*
-                                   : doctest : car doctests
-                                     testid
-                                        if : not : list? doctest
-                                             . #f
-                                             string-join : list filename (symbol->string name) : symbol->string : primitive-eval : car : cdr doctest
-                                                         . "--"
-                                     cleaned
-                                         if : not : list? doctest
-                                           . '#f
-                                           append
-                                               cons 'begin
-                                                   cons '(import (srfi srfi-64))
-                                                       cons
-                                                           list 'test-begin testid
-                                                           cdr : cdr doctest
-                                               list : list 'test-end testid
-                                   when cleaned
-                                       let :
-                                           eval cleaned mod
-                                       newline
-                                   loop-tests : cdr doctests
-                   loop (cdr names) (cdr docstrings)
+                 doctests doctests
+               ;; pretty-print doctests
+               ;; newline
+               when : pair? doctests
+                   let*
+                       : name : car names
+                         doctest : car doctests
+                       let loop-tests
+                          : doctest doctest
+                          when : and (pair? doctest) (car doctest) : pair? : car doctest
+                             ;; pretty-print : car doctest
+                             ;; newline
+                             let*
+                               :
+                                 testid
+                                    match doctest
+                                      : (('quote id) tests ...) moretests ...
+                                        string-join : list filename (symbol->string name) : symbol->string id
+                                                     . "--"
+                                      : tests ...
+                                        string-join : list filename (symbol->string name)
+                                                     . "--"
+                                 body
+                                     match doctest
+                                      : (('quote id) test tests ...) moretests ...
+                                        cons test tests
+                                      : tests ...
+                                        . tests
+                                 cleaned
+                                        cons 'begin
+                                            cons '(import (srfi srfi-64)) 
+                                                cons 
+                                                    list 'test-begin : or testid ""
+                                                    append
+                                                        . body
+                                                        list : list 'test-end : or testid ""
+                               ;; pretty-print testid
+                               ;; pretty-print body
+                               ;; pretty-print cleaned
+                               ;; newline
+                               when cleaned
+                                   let :
+                                       eval cleaned mod
+                                   newline
+                               match doctest
+                                      : (('quote id) tests ...) moretests ...
+                                        loop-tests moretests
+                                      : tests ...
+                                        . #t
+                   loop (cdr names) (cdr doctests)
 
 define %this-module : current-module
 define : main args
diff --git a/examples/newbase60.w b/examples/newbase60.w
--- a/examples/newbase60.w
+++ b/examples/newbase60.w
@@ -1,5 +1,6 @@
 #!/usr/bin/env sh
 # -*- wisp -*-
+guile -L $(dirname $(dirname $(realpath "$0"))) -c '(import (language wisp spec))'
 exec guile -L $(dirname $(dirname $(realpath "$0"))) --language=wisp -e '(@@ (examples newbase60) main)' -s "$0" "$@"
 ; !#
 
diff --git a/wisp-scheme.w b/wisp-scheme.w
--- a/wisp-scheme.w
+++ b/wisp-scheme.w
@@ -276,7 +276,7 @@ define : wisp-scheme-read-chunk-lines po
                  ; an error. This is stricter than the current wisp
                  ; syntax definition. TODO: Fix the definition. Better
                  ; start too strict. FIXME: breaks on lines with only
-                 ; underscores which should empty lines.
+                 ; underscores which should be empty lines.
                  : and inunderscoreindent : and (not (equal? #\space next-char)) (not (equal? #\newline next-char))
                    throw 'wisp-syntax-error "initial underscores without following whitespace at beginning of the line after" : last indent-and-symbols
                  : equal? #\newline next-char
@@ -343,8 +343,8 @@ define : wisp-scheme-read-chunk-lines po
                      . currentsymbols
                      . emptylines
                           ; | cludge to appease the former wisp parser
-                          ; | which had a problem with the literal comment
-                          ; v char.
+                          ; | used for bootstrapping which has a
+                          ; v problem with the literal comment char
                  : equal? (string-ref ";" 0) next-char
                    loop 
                      . indent-and-symbols
@@ -457,7 +457,7 @@ define : wisp-propagate-source-propertie
                  append processed : list : wisp-propagate-source-properties line
                  cdr unprocessed
 
-define : wisp-scheme-indentation-to-parens lines
+define* : wisp-scheme-indentation-to-parens lines
          . "Add parentheses to lines and remove the indentation markers"
          when 
            and 
@@ -532,7 +532,7 @@ define : wisp-scheme-indentation-to-pare
                             values processed unprocessed
                             begin ;; not yet used level! TODO: maybe throw an error here instead of a warning.
                                 let : : linenumber : - (length lines) (length unprocessed)
-                                    format (current-error-port) ";;; WARNING:~A: used lower but undefined indentation level (line ~A of the current chunk: ~S). This makes refactoring much more error-prone, therefore it might become an error in a later version of Wisp.\n" linenumber linenumber (cdr current-line)
+                                    format (current-error-port) ";;; WARNING:~A: used lower but undefined indentation level (line ~A of the current chunk: ~S). This makes refactoring much more error-prone, therefore it might become an error in a later version of Wisp.\n" (source-property current-line 'line) linenumber (cdr current-line)
                                 loop
                                   . processed
                                   . unprocessed