wisp
 
(Arne Babenhauserheide)
2014-11-06: full featured wisp using the scheme (read) which passes the stable v0.8.0

full featured wisp using the scheme (read) which passes the testsuite. Requires curly infix now.

diff --git a/.bugs/bugs b/.bugs/bugs
--- a/.bugs/bugs
+++ b/.bugs/bugs
@@ -1,28 +1,34 @@
-testsuite: to pass, the tree-il has to match, not the emitted string. This allows for reader-only implementations. | owner:, open:True, id:00b74a730bbf076e73166e817ca7b0a273b376d4, time:1408224636.42
+testsuite: to pass, the tree-il has to match, not the emitted string. This allows for reader-only implementations. | owner:, open:False, id:00b74a730bbf076e73166e817ca7b0a273b376d4, time:1408224636.42
+wisp-scheme: unescape \_ and \:                              | owner:, open:False, id:086f61a06e16f1ef56e9917453bbd55b5879d15d, time:1415121255.99
 fails when I add stuff at the end of end of example.w        | owner:, open:False, id:08c68e1ce0c9798184c01806d2661a3220bff3cd, time:1363789693.79
 wisp-mode in quoted lists only the first item is colorized as data, but all words up to the last paren should be colorized. | owner:, open:True, id:1675ca3f894ed8470fa292149a476a2fa0d17140, time:1397196957.45
 add a testsuite for wisp parsers.                            | owner:, open:False, id:1c05d27ac916e1a823b8985a094947907c3c19af, time:1379064922.74
 wisp-mode: export wisp to html fails in org-mode: font-lock-fontify-keywords-region: Invalid regexp | owner:, open:False, id:1e46d8c05580c961c37a32d36c987a5dd1d34943, time:1389371020.39
 an empty line with : should start with double parens         | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:2e188ddf44d36e4605030d3c58607ebfa97d189e, time:1390328674.43
 wisp-in-wisp: remove the leading . for continuation lines after inferring the brackets. | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:2e42e5b64622f0cc383eb8acc3d510912e925bf0, time:1377476687.79
+'() gives REPR-QUOTE-...                                     | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:30c42de75c137f483245898e2a62af1e65cf19a6, time:1415060388.34
 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
 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:True, id:4d4e76343fe09f0ec72a3e5eb0077bd16e12f9d5, time:1415127234.43
 implement wisp in wisp                                       | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:6299306916706410702029289bf32edab1e7f17c, time:1367113341.49
 support other types of brackets, like square brackets.       | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:6749f3abcb9455eac9271efd8265797bce114239, time:1389134151.98
 linebreaks in parens still break                             | owner:, open:False, id:6797987c7834a53358fb4ebbd8b9b36c2c4a8f01, time:1379004764.14
 wisp-guile.w does not yet remove the leading . which signifies a continuation. | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:7075096a323933493f42a3751da5f75a45d5d699, time:1377381700.17
 inline ' : should be '(                                      | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:72d534a8b23b4cb168017f1bb7d8816f0ea170c4, time:1366497335.26
 failing test tests/shebang.w                                 | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:74a851f83af8996465a7b24d8453161beb0f0fd5, time:1379106761.57
-non-nested multiline comments with #! !#. Requires restructuring. | owner:, open:True, id:7a57614fa920b2ddad002d044b144d0bb7c34f84, time:1389364108.01
-support nested multi-line comments with #| ... |#: multiline comments (srfi-30). Requires restructuring. | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:8cf6202873d4454f57813dd17cf60432059f7c62, time:1389569421.6
-the repl does not require 3 returns when you use a single char as function, or rather only does so every second time | owner:, open:True, id:9cedd0bdbf4a3b17add4bfe86ad5a23e500cfc6c, time:1379064870.78
+non-nested multiline comments with #! !#. Requires restructuring. | owner:, open:False, id:7a57614fa920b2ddad002d044b144d0bb7c34f84, time:1389364108.01
+wisp-guile: support nested multi-line comments with #| ... |#: multiline comments (srfi-30). Requires restructuring. | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:8cf6202873d4454f57813dd17cf60432059f7c62, time:1389569421.6
+wisp-guile: the repl does not require 3 returns when you use a single char as function, or rather only does so every second time | owner:, open:True, id:9cedd0bdbf4a3b17add4bfe86ad5a23e500cfc6c, time:1379064870.78
 wisp-guile.w breaks on ";" and complex brackets with bracket char literals. See wisp-guile.w::91 | owner:, open:False, id:9d8b6f87fa5365733fc8655614dbf2a9ba5bd054, time:1377533321.27
+wisp-scheme: treat quote quasiquote syntax quasisyntax and so on similar to the dot. | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:9e587f38115099c0825c13a2159605e5f560aeec, time:1413623986.49
 FIX regression: empty line with only : does not remove the :. It transforms to (:, it should transform to ( | owner:, open:False, id:a2323d347612425bc5af577c939916c8b60ec1c9, time:1389631450.78
 wisp-mode: handle lines starting with underscores: currently sees the underscores as function call. | owner:Arne Babenhauserheide <bab@draketo.de>, open:True, id:b2c3755e1deb8355655a334d569679e2e62d2836, time:1376612093.55
-parens in comments can throw off the parser.                 | owner:, open:True, id:ce28d6c0d1f9894c9b946e56b17934473800edfe, time:1408224406.79
+wisp-scheme: curly braces should use read.                   | owner:, open:False, id:c0e62db4dcfdf4f1cf84f1871e439d055dacbefa, time:1415121781.25
+wisp-guile: parens in strings can throw off the parser       | owner:, open:True, id:ce28d6c0d1f9894c9b946e56b17934473800edfe, time:1408224406.79
 make this work: let : : origfile ( open-file : nth 1 : command-line ) r | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:d6de2074a5017f1f29f34d142ce797981ed270a0, time:1366529287.67
 wisp.py breaks on \ - quote, escaped backslash, quote. Ignored, because wisp.py is only needed for bootstrapping. | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:d75a93ca58ade5b3e3e51f1e7ee9782e743ac131, time:1377424552.02
 comments containing a closing parenthesis can break the parser. | owner:, open:False, id:d9147504868960e5fbc2648474d48ce5c9bd1a02, time:1374838747.22
 breaks on empty files                                        | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:e40fa7a93eb2c497dca1af7eed22ad5ed5cfbe7f, time:1390325470.91
+wisp-scheme: breaks on lines with only underscores. These should be treated as empty lines. | owner:, open:False, id:e464b5ce49deb14a80f67d50c6d70043ca9bde25, time:1415124488.16
 quote as only char in a line gets parenthized instead of becoming a paren-prefix. | owner:Arne Babenhauserheide <bab@draketo.de>, open:False, id:eb7468387e90bb5d13f5a5d81c6f4a704f2ca0fb, time:1390326369.6
diff --git a/.bugs/details/4d4e76343fe09f0ec72a3e5eb0077bd16e12f9d5.txt b/.bugs/details/4d4e76343fe09f0ec72a3e5eb0077bd16e12f9d5.txt
new file mode 100644
--- /dev/null
+++ b/.bugs/details/4d4e76343fe09f0ec72a3e5eb0077bd16e12f9d5.txt
@@ -0,0 +1,28 @@
+# 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
+after the fix:
+wisp-scheme now passes the testsuite, tested by a testrunner which checks the code-tree, not the string-representation.
+
+
+[expected]
+# The expected result
+
+
+[actual]
+# What happened instead
+
+
+[reproduce]
+# Reproduction steps
+
+
+[comments]
+# Comments and updates - leave your name
diff --git a/Makefile.am b/Makefile.am
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,8 +1,8 @@
-wisp = wisp.scm language/wisp/spec.scm
+wisp = wisp.scm wisp-scheme.scm language/wisp/spec.scm
 wisp_SOURCES = wisp-guile.w wisp-reader.w wisp-scheme.w
-EXTRA_DIST = $(wisp_SOURCES) $(wisp_DATA) bootstrap.sh wisp.py examples tests runtests.sh wisp-repl-guile.sh
+EXTRA_DIST = $(wisp_SOURCES) $(wisp_DATA) bootstrap.sh wisp.py examples tests wisp-repl-guile.sh testrunner.w
 CLEANFILES = ${wisp} ChangeLog
-DISTCLEANFILES = ${CLEANFILES} @abs_top_builddir@/1 @abs_top_builddir@/2 @abs_top_builddir@/syntaxtests.sh
+DISTCLEANFILES = ${CLEANFILES} @abs_top_builddir@/1 @abs_top_builddir@/2 @abs_top_builddir@/syntaxtests.sh @abs_top_builddir@/syntaxtestsreader.sh
 # don't spout out lots of stuff at each distcheck. Disable for debugging.
 AM_DISTCHECK_CONFIGURE_FLAGS="--quiet"
 
@@ -20,9 +20,15 @@ input.in.intermediate: ${wisp_SOURCES}
 	@abs_top_srcdir@/bootstrap.sh @abs_top_srcdir@ @guile@ @python3@ 2>&1 | sed "s/^;;;.*//" 2>&1 | grep . 1>&2 ; test ! $$? -eq 0 # grep did not find anything
 
 .PHONY: syntaxtests.sh
-syntaxtests.sh : wisp.scm runtests.sh
-	echo '#!/bin/bash' > @abs_top_builddir@/syntaxtests.sh
-	echo @abs_top_srcdir@/runtests.sh @abs_top_srcdir@ @abs_top_builddir@ >> @abs_top_builddir@/syntaxtests.sh
-	chmod +x @abs_top_builddir@/syntaxtests.sh
+syntaxtests.sh : wisp.scm tests/runtests-scheme-preprocessor.sh
+	echo '#!/bin/bash' > @abs_top_builddir@/$@
+	echo @abs_top_srcdir@/tests/runtests-scheme-preprocessor.sh @abs_top_srcdir@ @abs_top_builddir@ >> @abs_top_builddir@/$@
+	chmod +x @abs_top_builddir@/$@
 
-TESTS=syntaxtests.sh
+.PHONY: syntaxtestsreader.sh
+syntaxtestsreader.sh : wisp.scm tests/runtests-scheme-reader.sh
+	echo '#!/bin/bash' > @abs_top_builddir@/$@
+	echo @abs_top_srcdir@/tests/runtests-scheme-reader.sh @abs_top_srcdir@ @abs_top_builddir@ >> @abs_top_builddir@/$@
+	chmod +x @abs_top_builddir@/$@
+
+TESTS=syntaxtests.sh syntaxtestsreader.sh
diff --git a/NEWS b/NEWS
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,11 @@
+wisp 0.8.0 (2014-11-03):
+- the testsuite is defined in terms of the code-tree, not in terms of
+  the readable file. Implemented in testrunner.w
+- wisp-scheme passes the wisp testsuite
+- wisp uses curly-infix by default (srfi-105)
+- this is the first full featured release of wisp-scheme: wisp which
+  defers all complex parsing to the scheme reader (and match).
+
 wisp 0.6.6 (2014-10-16):
 - fix boostrap.
 
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.6.6],
+AC_INIT([wisp], [0.8.0],
         [arne_bab@web.de])
 # Check for programs I need for my build
 AC_CANONICAL_TARGET
diff --git a/testrunner.w b/testrunner.w
new file mode 100755
--- /dev/null
+++ b/testrunner.w
@@ -0,0 +1,36 @@
+#!/bin/bash
+exec guile -L . --language=wisp -s "$0" "$@"
+!#
+
+when : not : = 3 : length : command-line
+   format #t "Usage: ~A <wisp file> <scheme file>\n" : list-ref (command-line) 0
+   exit
+
+define wisp-file : list-ref (command-line) 1
+define scheme-file : list-ref (command-line) 2
+
+use-modules 
+  srfi srfi-1
+  wisp-scheme
+
+
+define : read-all port
+  let readloop : : res : '
+    let : : next : read port
+      if : eof-object? next
+          . res 
+          readloop : append res : list next
+
+let
+   :
+     read-scheme
+       with-input-from-file scheme-file 
+         λ ()
+           read-all : current-input-port
+     parsed-wisp
+       with-input-from-file wisp-file
+         λ () 
+           wisp-scheme-read-all : current-input-port
+   if : equal? parsed-wisp read-scheme
+        format #t "Files ~A and ~A have equivalent content.\n" scheme-file wisp-file
+        format #t "Files ~A and ~A are different!\n\nwisp:   ~A\n\nscheme: ~A\n\n\n" scheme-file wisp-file parsed-wisp read-scheme
diff --git a/tests/emacs-customization.scm b/tests/emacs-customization.scm
--- a/tests/emacs-customization.scm
+++ b/tests/emacs-customization.scm
@@ -1,7 +1,8 @@
 (if (file-directory-p "~/.emacs.d/private/journal/")
      (setq-default journal-dir "~/.emacs.d/private/journal/"))
 
-(global-set-key [(control meta .)] 'goto-last-change-reverse)
+; the following line is not valid scheme and as such would break the scheme tests.
+; global-set-key [(control meta .)] 'goto-last-change-reverse
 
 (require 'org-latex)
 (add-to-list 'org-export-latex-packages-alist 
diff --git a/tests/emacs-customization.w b/tests/emacs-customization.w
--- a/tests/emacs-customization.w
+++ b/tests/emacs-customization.w
@@ -1,7 +1,8 @@
 if : file-directory-p "~/.emacs.d/private/journal/"
      setq-default journal-dir "~/.emacs.d/private/journal/"
 
-global-set-key [(control meta .)] 'goto-last-change-reverse
+; the following line is not valid scheme and as such would break the scheme tests.
+; global-set-key [(control meta .)] 'goto-last-change-reverse
 
 require 'org-latex
 add-to-list 'org-export-latex-packages-alist 
@@ -55,4 +56,4 @@ custom-set-variables
 
 setq a "x"
    . b "y"
-   . c "z"
\ No newline at end of file
+   . c "z"
diff --git a/tests/example.scm b/tests/example.scm
--- a/tests/example.scm
+++ b/tests/example.scm
@@ -12,7 +12,7 @@ do not break me!")
         (h (I am in brackets:
            do not : change "me"))
         i)))
-  ,(' j k)
+  ,('j k)
 
   l
 
diff --git a/tests/example.w b/tests/example.w
--- a/tests/example.w
+++ b/tests/example.w
@@ -12,7 +12,7 @@ do not break me!"
         h (I am in brackets:
            do not : change "me")
         . i
-  , ' j k
+  , 'j k
 
   . l
 
diff --git a/tests/hello.scm b/tests/hello.scm
--- a/tests/hello.scm
+++ b/tests/hello.scm
@@ -1,5 +1,5 @@
 (define (hello who)
   (format #t "~A ~A!\n"
           "Hello" who))
+(hello "Wisp")
 
-
diff --git a/tests/hello.w b/tests/hello.w
--- a/tests/hello.w
+++ b/tests/hello.w
@@ -1,3 +1,4 @@
 define : hello who
   format #t "~A ~A!\n"
           . "Hello" who
+hello "Wisp"
diff --git a/runtests.sh b/tests/runtests-scheme-preprocessor.sh
rename from runtests.sh
rename to tests/runtests-scheme-preprocessor.sh
--- a/runtests.sh
+++ b/tests/runtests-scheme-preprocessor.sh
@@ -17,6 +17,8 @@ fi
 failed=0
 cd ${srcdir}/tests
 for i in *.w; do
+    # skip strangecomments
+    if test x"${i}" = x"strangecomments.w"; then continue; fi
     d=$(guile ${builddir}/wisp.scm "$i" > ${builddir}/testtempfoo.scm; diff -wuB ${builddir}/testtempfoo.scm "$(basename "$i" .w)".scm; rm ${builddir}/testtempfoo.scm)
     if test x"$d" = x""; then
         continue
diff --git a/tests/runtests-scheme-reader.sh b/tests/runtests-scheme-reader.sh
new file mode 100755
--- /dev/null
+++ b/tests/runtests-scheme-reader.sh
@@ -0,0 +1,32 @@
+#!/bin/bash
+
+# Simple test runner for wisp, mainly intended to be run by autotools.
+
+if [[ x"$1" == x"" || x"$1" == x"." ]]; then
+    srcdir="$(realpath "$(pwd)")"
+else
+    srcdir="$(realpath "$1")"
+fi
+
+if [[ x"$2" == x"" || x"$2" == x"."  ]]; then
+    builddir="$(realpath $(pwd))"
+else
+    builddir="$(realpath "$2")"
+fi
+
+failed=0
+cd ${builddir}
+for i in ${srcdir}/tests/*.w; do
+    d=$(guile -L . --language=wisp ${srcdir}/testrunner.w "${i}" "${srcdir}/tests/$(basename "${i}" .w).scm")
+    if test $? -eq 0; then
+        continue
+    else
+        echo test "$i" failed. Diff: "$d"
+        failed=$((failed + 1))
+    fi
+done
+cd - >/dev/null # undo dir change
+# if test $failed -eq 0; then echo "Tests succeeded"; 
+# else echo "tests failed: ${failed}";
+# fi
+exit $failed
diff --git a/tests/strangecomments.scm b/tests/strangecomments.scm
--- a/tests/strangecomments.scm
+++ b/tests/strangecomments.scm
@@ -1,17 +1,18 @@
+(use-modules (wisp-scheme))
 ; works
 (display  
-  (call-with-input-string  "  foo ; bar\n  ; nop \n\n; nup\n; nup \n  \n\n\n  foo : moo \"\n\" \n___ . goo . hoo" wisp-scheme-read-chunk))
+  (call-with-input-string  "foo ; bar\n  ; nop \n\n; nup\n; nup \n  \n\n\n  foo : moo \"\n\" \n___ . goo . hoo" wisp-scheme-read-chunk))
 (newline)
 (display
-  (call-with-input-string  "  foo \n___. goo . hoo" wisp-scheme-read-chunk))
+  (call-with-input-string  "foo \n___ . goo . hoo" wisp-scheme-read-chunk))
 (newline)
 
 ; broken
 ; expected:
 (display  
-  (call-with-input-string  "  (foo) ; bar\n  ; nop \n\n; nup\n; nup \n  \n\n\n  foo : moo \"\n\" \n___ . [goo . hoo]" wisp-scheme-read-chunk))
+  (call-with-input-string  "(foo) ; bar\n  ; nop \n\n; nup\n; nup \n  \n\n\n  foo : moo \"\n\" \n___ . [goo . hoo]" wisp-scheme-read-chunk))
 (newline)
 (display
-  (call-with-input-string  "  foo \n___. [goo . hoo]" wisp-scheme-read-chunk))
+  (call-with-input-string  "foo \n___ . [goo . hoo]" wisp-scheme-read-chunk))
 (newline)
 
diff --git a/tests/strangecomments.w b/tests/strangecomments.w
--- a/tests/strangecomments.w
+++ b/tests/strangecomments.w
@@ -1,16 +1,17 @@
+use-modules : wisp-scheme
 ; works
 display  
-  call-with-input-string  "  foo ; bar\n  ; nop \n\n; nup\n; nup \n  \n\n\n  foo : moo \"\n\" \n___ . goo . hoo" wisp-scheme-read-chunk
+  call-with-input-string  "foo ; bar\n  ; nop \n\n; nup\n; nup \n  \n\n\n  foo : moo \"\n\" \n___ . goo . hoo" wisp-scheme-read-chunk
 newline
 display
-  call-with-input-string  "  foo \n___. goo . hoo" wisp-scheme-read-chunk
+  call-with-input-string  "foo \n___ . goo . hoo" wisp-scheme-read-chunk
 newline
 
 ; broken
 ; expected:
 display  
-  call-with-input-string  "  (foo) ; bar\n  ; nop \n\n; nup\n; nup \n  \n\n\n  foo : moo \"\n\" \n___ . [goo . hoo]" wisp-scheme-read-chunk
+  call-with-input-string  "(foo) ; bar\n  ; nop \n\n; nup\n; nup \n  \n\n\n  foo : moo \"\n\" \n___ . [goo . hoo]" wisp-scheme-read-chunk
 newline
 display
-  call-with-input-string  "  foo \n___. [goo . hoo]" wisp-scheme-read-chunk
+  call-with-input-string  "foo \n___ . [goo . hoo]" wisp-scheme-read-chunk
 newline
diff --git a/wisp-guile.w b/wisp-guile.w
--- a/wisp-guile.w
+++ b/wisp-guile.w
@@ -8,12 +8,13 @@
 
 ; we need to be able to replace end-of-line characters in brackets and strings
 
-;; nostringandbracketbreaks INPORT
-;; 
-;; Replace linebreaks within brackets and strings in the INPORT by the
-;; placeholders \LINE_BREAK_N and \LINE_BREAK_R. Also identify
-;; real comments as ;\REALCOMMENTHERE
-;; 
+;; TODO: Check whether I can offload the string processing to the
+;; read-function. That’s a source of endless complications. Required:
+;; A kind of unrolling step which appends the string-representation of
+;; the read strings back into the code. I would have to process a list
+;; of strings instead of one big string. Or rather, each line would be
+;; a list of strings.
+
 ;; bootstrap via python3 wisp.py wisp-guile.w > 1 && guile 1 wisp-guile.w > 2 && guile 2 wisp-guile.w > 3 && diff 2 3
 ;; 
 ;; -Author: Arne Babenhauserheide
diff --git a/wisp-reader.w b/wisp-reader.w
--- a/wisp-reader.w
+++ b/wisp-reader.w
@@ -51,7 +51,9 @@ define : read-one-wisp-sexp port env
   try-pending
 
 define : wisp-scheme-read-chunk-env port env
-       cons 'begin : wisp-scheme-read-chunk port
+         if : eof-object? : peek-char port
+              read-char port ; return eof: we’re done
+              cons 'begin : wisp-scheme-read-chunk port
 
 define-language wisp
   . #:title "Wisp Scheme Syntax THIS IS EXPERIMENTAL, USE AT YOUR OWN RISK"
diff --git a/wisp-scheme.w b/wisp-scheme.w
--- a/wisp-scheme.w
+++ b/wisp-scheme.w
@@ -25,6 +25,9 @@ define-module : wisp-scheme
                wisp-scheme-read-file-chunk wisp-scheme-read-file
                wisp-scheme-read-string)
 
+; use curly-infix by default
+read-enable 'curly-infix
+
 use-modules 
   srfi srfi-1
   srfi srfi-11 ; for let-values
@@ -49,13 +52,88 @@ define : line-code line
 define readcolon 
        string->symbol ":"
 
+define wisp-uuid "e749c73d-c826-47e2-a798-c16c13cb89dd"
 ; define an intermediate dot replacement with UUID to avoid clashes.
-define dotrepr 
-       string->symbol "DOTREPR-e749c73d-c826-47e2-a798-c16c13cb89dd"
+define repr-dot ; .
+       string->symbol : string-append "REPR-DOT-" wisp-uuid
+
+; allow using reader additions as the first element on a line to prefix the list
+define repr-quote ; '
+       string->symbol : string-append "REPR-QUOTE-" wisp-uuid
+define repr-unquote ; ,
+       string->symbol : string-append "REPR-UNQUOTE-" wisp-uuid
+define repr-quasiquote ; `
+       string->symbol : string-append "REPR-QUASIQUOTE-" wisp-uuid
+define repr-unquote-splicing ; ,@
+       string->symbol : string-append "REPR-UNQUOTESPLICING-" wisp-uuid
+
+define repr-syntax ; #'
+       string->symbol : string-append "REPR-SYNTAX-" wisp-uuid
+define repr-unsyntax ; #,
+       string->symbol : string-append "REPR-UNSYNTAX-" wisp-uuid
+define repr-quasisyntax ; #`
+       string->symbol : string-append "REPR-QUASISYNTAX-" wisp-uuid
+define repr-unsyntax-splicing ; #,@
+       string->symbol : string-append "REPR-UNSYNTAXSPLICING-" wisp-uuid
+
+; TODO: wrap the reader to return the repr of the syntax reader
+; additions 
+
+define : match-charlist-to-repr charlist
+         let 
+           : chlist : reverse charlist
+           cond
+             : equal? chlist : list #\.
+               . repr-dot
+             : equal? chlist : list #\'
+               . repr-quote
+             : equal? chlist : list #\,
+               . repr-unquote
+             : equal? chlist : list #\`
+               . repr-quasiquote
+             : equal? chlist : list #\, #\@ 
+               . repr-unquote-splicing
+             : equal? chlist : list #\# #\' 
+               . repr-syntax
+             : equal? chlist : list #\# #\, 
+               . repr-unsyntax
+             : equal? chlist : list #\# #\` 
+               . repr-quasisyntax
+             : equal? chlist : list #\# #\, #\@ 
+               . repr-unsyntax-splicing
+             else
+               . #f
+
+define : wisp-read port
+       . "wrap read to catch list prefixes."
+       let : : prefix-maxlen 4
+         let longpeek 
+           : peeked '()
+             repr-symbol #f
+           cond
+             : or (< prefix-maxlen (length peeked)) (eof-object? (peek-char port)) (equal? #\space (peek-char port)) (equal? #\newline (peek-char port)) 
+               if repr-symbol ; found a special symbol, return it.
+                  . repr-symbol
+                  let unpeek
+                    : remaining peeked
+                    cond
+                      : equal? '() remaining 
+                        read port ; let read to the work
+                      else
+                        unread-char (car remaining) port
+                        unpeek : cdr remaining
+             else
+               let* 
+                 : next-char : read-char port
+                   peeked : cons next-char peeked
+                 longpeek
+                   . peeked
+                   match-charlist-to-repr peeked
+                 
 
 
 define : line-continues? line
-         equal? dotrepr : car : line-code line
+         equal? repr-dot : car : line-code line
 
 define : line-only-colon? line
          and
@@ -153,10 +231,11 @@ define : wisp-scheme-read-chunk-lines po
                  ; any char but whitespace *after* underscoreindent is
                  ; an error. This is stricter than the current wisp
                  ; syntax definition. TODO: Fix the definition. Better
-                 ; start too strict.
-                 : and inunderscoreindent : not : equal? #\space next-char
+                 ; start too strict. FIXME: breaks on lines with only
+                 ; underscores which should 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
-                 : or (equal? #\newline next-char) ; (equal? #\return next-char)
+                 : equal? #\newline next-char
                    read-char port ; remove the newline
                    ; The following two lines would break the REPL by requiring one char too many.
                    ; if : and (equal? #\newline next-char) : equal? #\return : peek-char port
@@ -190,7 +269,7 @@ define : wisp-scheme-read-chunk-lines po
                        . #t ; inindent
                        if : <= 2 emptylines
                          . #f ; chunk ends here
-                         equal? #\_ : peek-char port
+                         equal? #\_ : peek-char port ; are we in underscore indent?
                        . #f ; incomment
                        . 0
                        . '()
@@ -227,32 +306,6 @@ define : wisp-scheme-read-chunk-lines po
                      . currentindent
                      . currentsymbols
                      . emptylines
-                 : equal? (string-ref "." 0) next-char
-                   ; TODO: special case for the dot using the dotrepr as
-                   ; intermediate representation
-                   read-char port ; remove next-char
-                   let : : next-next-char : peek-char port
-                     ; if we don’t need the special handling, add the
-                     ; next char to the port again
-                     if : not : or (equal? #\space next-next-char) (equal? #\newline next-next-char) (eof-object? next-next-char) (equal? #\return next-next-char) 
-                       unread-char next-char port
-                     loop 
-                       . indent-and-symbols
-                       . #f ; inindent
-                       . #f ; inunderscoreindent
-                       . #f ; incomment
-                       . currentindent
-                       ; this also takes care of the hashbang and leading comments.
-                       append currentsymbols 
-                         ; if we don’t need the special handling, just
-                         ; use the reader. Otherwise append the special
-                         ; representation of the dot to avoid triggering
-                         ; this for the dot escaped as |.| or #{.}#
-                         if : not : or (equal? #\space next-next-char) (equal? #\newline next-next-char) (eof-object? next-next-char) (equal? #\return next-next-char)
-                           list : read port
-                           list dotrepr
-                       . emptylines
-                       ; TODO: finish 
                  else ; use the reader
                    loop 
                      . indent-and-symbols
@@ -262,7 +315,7 @@ define : wisp-scheme-read-chunk-lines po
                      . currentindent
                      ; this also takes care of the hashbang and leading comments.
                      ; TODO: If used from Guile, activate curly infix via read-options.
-                     append currentsymbols : list : read port
+                     append currentsymbols : list : wisp-read port
                      . emptylines
 
 
@@ -453,6 +506,57 @@ define : wisp-scheme-strip-indentation-m
                   append processed : cdr : car unprocessed
                   cdr unprocessed
 
+define : wisp-unescape-underscore-and-colon code
+         . "replace \\_ and \\: by _ and :"
+         match code
+             : a ...
+               map wisp-unescape-underscore-and-colon a
+             '\_
+               . '_
+             '\:
+               . ':
+             a
+               . a
+
+
+define : wisp-replace-empty-eof code
+         . "replace ((#<eof>)) by ()"
+         ; FIXME: Actually this is a hack which fixes a bug when the
+         ; parser hits files with only hashbang and comments.
+         if : and (pair? (car code)) (eof-object? (car (car code))) (null? (cdr code)) (null? (cdr (car code)))
+              list
+              . code
+
+
+define : wisp-replace-paren-quotation-repr code
+         . "Replace lists starting with a quotation symbol by
+         quoted lists."
+         match code
+             : 'REPR-QUOTE-e749c73d-c826-47e2-a798-c16c13cb89dd a ...
+                list 'quote : map wisp-replace-paren-quotation-repr a
+             : a ... 'REPR-QUOTE-e749c73d-c826-47e2-a798-c16c13cb89dd b ; this is the quoted empty list 
+                append
+                        map wisp-replace-paren-quotation-repr a
+                        list : list 'quote : map wisp-replace-paren-quotation-repr b
+             : 'REPR-UNQUOTE-e749c73d-c826-47e2-a798-c16c13cb89dd a ...
+                list 'unquote : map wisp-replace-paren-quotation-repr a
+             : 'REPR-QUASIQUOTE-e749c73d-c826-47e2-a798-c16c13cb89dd a ...
+                list 'quasiquote : map wisp-replace-paren-quotation-repr a
+             : 'REPR-UNQUOTESPLICING-e749c73d-c826-47e2-a798-c16c13cb89dd a ...
+                list 'unquote-splicing : map wisp-replace-paren-quotation-repr a
+             : 'REPR-SYNTAX-e749c73d-c826-47e2-a798-c16c13cb89dd a ...
+                list 'syntax : map wisp-replace-paren-quotation-repr a
+             : 'REPR-UNSYNTAX-e749c73d-c826-47e2-a798-c16c13cb89dd a ...
+                list 'unsyntax : map wisp-replace-paren-quotation-repr a
+             : 'REPR-QUASISYNTAX-e749c73d-c826-47e2-a798-c16c13cb89dd a ...
+                list 'quasisyntax : map wisp-replace-paren-quotation-repr a
+             : 'REPR-UNSYNTAXSPLICING-e749c73d-c826-47e2-a798-c16c13cb89dd a ...
+                list 'unsyntax-splicing : map wisp-replace-paren-quotation-repr a
+             : a ...
+               map wisp-replace-paren-quotation-repr a
+             a
+               . a
+
 define : wisp-make-improper code
          . "Turn (a #{.}# b) into the correct (a . b).
 
@@ -467,7 +571,7 @@ Match is awesome!"
            : 
              improper
                match code
-                  : a ... b 'DOTREPR-e749c73d-c826-47e2-a798-c16c13cb89dd c
+                  : a ... b 'REPR-DOT-e749c73d-c826-47e2-a798-c16c13cb89dd c
                     append (map wisp-make-improper a) 
                       cons (wisp-make-improper b) (wisp-make-improper c)
                   : a ...
@@ -480,18 +584,18 @@ Match is awesome!"
              : tocheck improper
              match tocheck
                ; lists with only one member
-               : 'DOTREPR-e749c73d-c826-47e2-a798-c16c13cb89dd
+               : 'REPR-DOT-e749c73d-c826-47e2-a798-c16c13cb89dd
                  syntax-error tocheck
                ; list with remaining dot.
                : a ...
-                 if : member dotrepr a
+                 if : member repr-dot a
                       syntax-error tocheck
                       map check a
                ; simple pair
-               : 'DOTREPR-e749c73d-c826-47e2-a798-c16c13cb89dd . c
+               : 'REPR-DOT-e749c73d-c826-47e2-a798-c16c13cb89dd . c
                  syntax-error tocheck
                ; simple pair, other way round
-               : a . 'DOTREPR-e749c73d-c826-47e2-a798-c16c13cb89dd
+               : a . 'REPR-DOT-e749c73d-c826-47e2-a798-c16c13cb89dd
                  syntax-error tocheck
                ; more complex pairs
                : ? pair? a
@@ -499,11 +603,11 @@ Match is awesome!"
                    : head : drop-right a 1
                      tail : last-pair a
                    cond
-                    : equal? dotrepr : car tail
+                    : equal? repr-dot : car tail
                       syntax-error tocheck
-                    : equal? dotrepr : cdr tail
+                    : equal? repr-dot : cdr tail
                       syntax-error tocheck
-                    : member dotrepr head
+                    : member repr-dot head
                       syntax-error tocheck
                     else
                       . a
@@ -515,7 +619,10 @@ define : wisp-scheme-read-chunk port
          . "Read and parse one chunk of wisp-code"
          let : :  lines : wisp-scheme-read-chunk-lines port
               wisp-make-improper
-                wisp-scheme-indentation-to-parens lines
+                wisp-replace-empty-eof
+                  wisp-unescape-underscore-and-colon
+                    wisp-replace-paren-quotation-repr
+                      wisp-scheme-indentation-to-parens lines
 
 define : wisp-scheme-read-all port
          . "Read all chunks from the given port"
@@ -541,6 +648,36 @@ define : wisp-scheme-read-string-chunk s
          call-with-input-string str wisp-scheme-read-chunk
 
 
+;;;; Test special syntax
+; ;; quote the list
+; write
+;   wisp-scheme-read-string  "moo
+;   foo
+;     ' bar
+; baz waz"
+; newline 
+; ;; quote the symbol - in wisp, whitespace after quote is not allowed!
+; write
+;   wisp-scheme-read-string  "moo
+;   foo
+;     'bar
+; baz waz"
+; newline 
+; ; ;; quote the list with colon
+; write
+;   wisp-scheme-read-string  "moo : ' foo
+;   foo
+;     ' bar bah
+; baz waz"
+; newline 
+; ; ;; syntax the list
+; write
+;   wisp-scheme-read-string  "moo : #' foo
+;   foo
+;     #' bar bah
+; baz waz"
+; newline 
+; 
 ;;;; Test improper lists
 ;;;; Good cases
 ; write