unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
From: "Dr. Arne Babenhauserheide" <arne_bab@web.de>
To: "Dr. Arne Babenhauserheide" <arne_bab@web.de>
Cc: "Maxime Devos" <maximedevos@telenet.be>,
	"Ludovic Courtès" <ludo@gnu.org>,
	guile-devel@gnu.org
Subject: Re: [PATCH] add SRFI-119 / language/wisp to Guile? (new patch, squashed)
Date: Mon, 14 Aug 2023 22:11:55 +0200	[thread overview]
Message-ID: <875y5h8j04.fsf@web.de> (raw)
In-Reply-To: <87o7jf2slw.fsf@web.de>


[-- Attachment #1.1: Type: text/plain, Size: 7661 bytes --]

Hi,

I did the changes for the review. It took a while (sorry for that) but
it got cleaner as a result (thank you!)

Firstoff: I’d like to assign my copyright to the FSF. I’ll sign the
papers once I receive them. Also I have an Employer disclaimer of rights
on paper for Emacs already, so that should not cause trouble.

Attached is a new squashed patch. I’ll send another email with only the
commits for the individual changes on top of the original squashed patch
to avoid tripping up tools that extract diffs.

Changes:

- [X] LGPL
- [X] Please add the new files to the relevant ‘Makefile.am’ files.
- [X] Note the changes in Makefiles in the commit
- [X] Please capitalize “Scheme” and “Wisp” (in general we like to pay attention to typography, spelling, and language in the manual.)
- [X] s/(wisp)/, also referred to as @dfn{Wisp} (for ``Whitespace …'')/
- [X] Two spaces after end-of-sentence periods, to facilitate navigation in Emacs.
- [X] indent “the usual way”
- [X] comments always with ;; except for margin comments
- [X] (read-enable 'curly-infix)
  This needs to be:
    (eval-when (expand load eval)
      (read-enable 'curly-infix))
- [X] Please make them #:use-module clauses in the ‘define-module’ form
- [X] I’d encourage following the usual naming convention, so
  ‘in-indent?’, ‘in-comment?’, etc.
- [X] use exception objects or SRFI-35 error conditions instead of throw with symbols
- [X] add a test for source location info


A change I did not do:

- [ ] +Use record-types for the lines+. Reason: I decided not to do
  this because it currently needs to propagate the source properties
  when retrieving the code, so this is not a good match for a record
  type (it may become one with an annotated reader, but I’d like to
  shift that to a later change:

> implementing the “annotated read” interface (info "(guile)
> Annotated Scheme Read").  That can come in a subsequent patch, though.


Ludovic Courtès <ludo@gnu.org> writes:

> Overall I’m confident the code has been battle-tested (I suppose there
> are minimal changes compared to Wisp, right?), so I’ll comment mostly on
> cosmetic issues.

Yes, the code comes directly from Wisp. The original was simply
auto-translated. Naturally that’s no guarantee that there are no bugs,
but there should be few enough that this can be used in production.

>> From c7a50f632293cf88f241d45d1fd52fa2f58ce772 Mon Sep 17 00:00:00 2001
>> From: Arne Babenhauserheide <arne_bab@web.de>
>> Date: Fri, 3 Feb 2023 22:20:04 +0100
>> Subject: [PATCH] Add language/wisp, wisp tests, and srfi-119 documentation
>>
>> * doc/ref/srfi-modules.texi (srfi-119): add node
>> * module/language/wisp.scm: New file.
>> * module/language/wisp/spec.scm: New file.
>> * test-suite/tests/srfi-119.test: New file.
>
> Please add the new files to the relevant ‘Makefile.am’ files.

Added.

>> +* SRFI-119::                    Wisp: simpler indentation-sensitive scheme.
>
> Please capitalize “Scheme” (in general we like to pay attention to
> typography, spelling, and language in the manual.)
>
>> +The languages shipped in Guile include SRFI-119 (wisp), an encoding of
>
> s/(wisp)/, also referred to as @dfn{Wisp} (for ``Whitespace …'')/
>
>> +Scheme that allows replacing parentheses with equivalent indentation and
>> +inline colons. See
>
> Two spaces after end-of-sentence periods, to facilitate navigation in
> Emacs.

Adjusted.

>> +(define-module (language wisp)
>> +   #:export (wisp-scheme-read-chunk wisp-scheme-read-all 
>> +               wisp-scheme-read-file-chunk wisp-scheme-read-file
>> +               wisp-scheme-read-string))
>
> Please remove tabs from this file and indent it “the usual way”.  You
> can do that by passing it through Emacs and using ‘M-x indent-region’,
> or possibly using ‘guix style -f’.

I used M-x indent-region.

> Use two leading colons for comments, except for margin comments.

👍

>> +(read-enable 'curly-infix)
>
> This needs to be:
>
>   (eval-when (expand load eval)
>     (read-enable 'curly-infix))

Adjusted — thank you (when to use eval-when was always a bit of a
mystery to me …).

> Please make them #:use-module clauses in the ‘define-module’ form above.

Done.

> Instead of using lists or pairs for “lines”, I suggest defining a proper
> record type, like:
> …
> This will make the code easier to read and type-clear.

Instead of this, I created a make-line procedure to make this easy to
refactor later when the code no longer needs adaptions when retrieving
the code part.

> I’d encourage following the usual naming convention, so ‘in-indent?’,
> ‘in-comment?’, etc.

Done.

>> + ((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)))
>
> I suggest using exception objects or SRFI-35 error conditions (they’re
> interchangeable) carrying information about the king of parsing error
> and its location.  That way, the user interface, such as the compiler,
> can produce helpful error messages (and internationalized, too).

Done: I used the convenience transformation, i.e.

    (raise-exception (make-exception-from-throw
      'wisp-syntax-error
       (list
        (format #f
          "Level ~A not found in the indentation-levels ~A."
          level indentation-levels))))



>> +++ b/module/language/wisp/spec.scm
> Can you make it LGPLv3+?  It’s a small file anyway.

I investigated and found that it actually was LGPLv3+ in the beginning
and I got permission to relicense to MIT for the SRFI, so with
permission of Maxime (who did later changes) this is now LGPLv3+ again.

>> +    (let ((m (make-fresh-user-module)))
>> +      ;; Provide a separate `current-reader' fluid so that
>> +      ;; compile-time changes to `current-reader' are
>> +      ;; limited to the current compilation unit.
>> +      (module-define! m 'current-reader (make-fluid))
>> +      ;; Default to `simple-format', as is the case until
>> +      ;; (ice-9 format) is loaded. This allows
>> +      ;; compile-time warnings to be emitted when using
>> +      ;; unsupported options.
>> +      (module-set! m 'format simple-format)
>
> I’d remove this last statement, I think we should avoid fiddling with
> bindings here.

Removed it now.

>> +(define-module (test-srfi-119)
>> +  #:use-module (test-suite lib)
>> +  #:use-module (srfi srfi-1)
>> +  #:use-module (language wisp))
>
> The test suite looks rather short; it would be nice if it would cover
> more code.

I have a pretty extensive test-suite in wisp itself but I didn’t think
it proper to just paste it into Guile. If you’d prefer that, I can still
add it all, though.

> In particular, I think source location info is important for front-ends
> like this, because it determines the quality of error messages and thus
> its ease of use.  Perhaps you could add test in that direction?

I added a test and found shortcomings thanks to it. After fixing these,
the current code has more robust source-property handling (that hadn’t
yet been tested further than ensuring that error messages give proper
source positions — which they did).

> Overall I feel we should be able to merge this rather soon.  Do ping me
> or Andy when needed!

Thank you!

The following is the complete squashed patch.


[-- Attachment #1.2: squashed patch --]
[-- Type: text/x-patch, Size: 43501 bytes --]

From 5857f8b961562d1ad2ae201401d5343233422eff Mon Sep 17 00:00:00 2001
From: Arne Babenhauserheide <arne_bab@web.de>
Date: Fri, 3 Feb 2023 22:20:04 +0100
Subject: [PATCH] Add language/wisp, wisp tests, and srfi-119 documentation

* doc/ref/srfi-modules.texi (srfi-119): add node
* module/language/wisp.scm: New file.
* module/language/wisp/spec.scm: New file.
* test-suite/tests/srfi-119.test: New file.
* am/bootstrap.am (SOURCES): add language/wisp.scm and language/wisp/spec.scm
* test-suite/Makefile.am (SCM_TESTS): add tests/srfi-119.test
---
 am/bootstrap.am                |   3 +
 doc/ref/srfi-modules.texi      |  31 ++
 module/language/wisp.scm       | 784 +++++++++++++++++++++++++++++++++
 module/language/wisp/spec.scm  |  73 +++
 test-suite/Makefile.am         |   3 +-
 test-suite/tests/srfi-119.test |  89 ++++
 6 files changed, 982 insertions(+), 1 deletion(-)
 create mode 100644 module/language/wisp.scm
 create mode 100644 module/language/wisp/spec.scm
 create mode 100644 test-suite/tests/srfi-119.test

diff --git a/am/bootstrap.am b/am/bootstrap.am
index ff0d1799e..80a8dcdde 100644
--- a/am/bootstrap.am
+++ b/am/bootstrap.am
@@ -393,6 +393,9 @@ SOURCES =					\
 						\
   system/syntax.scm				\
 						\
+  language/wisp.scm				\
+  language/wisp/spec.scm			\
+						\
   system/xref.scm				\
 						\
   sxml/apply-templates.scm			\
diff --git a/doc/ref/srfi-modules.texi b/doc/ref/srfi-modules.texi
index 0cdf56923..5b82f8070 100644
--- a/doc/ref/srfi-modules.texi
+++ b/doc/ref/srfi-modules.texi
@@ -64,6 +64,7 @@ get the relevant SRFI documents from the SRFI home page
 * SRFI-98::                     Accessing environment variables.
 * SRFI-105::                    Curly-infix expressions.
 * SRFI-111::                    Boxes.
+* SRFI-119::                    Wisp: simpler indentation-sensitive Scheme.
 * SRFI-171::                    Transducers
 @end menu
 
@@ -5662,6 +5663,35 @@ Return the current contents of @var{box}.
 Set the contents of @var{box} to @var{value}.
 @end deffn
 
+@node SRFI-119
+@subsection SRFI-119 Wisp: simpler indentation-sensitive Scheme.
+@cindex SRFI-119
+@cindex wisp
+
+The languages shipped in Guile include SRFI-119, also referred to as
+@dfn{Wisp} (for ``Whitespace to Lisp''), an encoding of Scheme that
+allows replacing parentheses with equivalent indentation and inline
+colons.  See
+@uref{http://srfi.schemers.org/srfi-119/srfi-119.html, the specification
+of SRFI-119}.  Some examples:
+
+@example
+display "Hello World!"         @result{}  (display "Hello World!")
+@end example
+
+@example
+define : factorial n           @result{}  (define (factorial n)
+    if : zero? n               @result{}      (if (zero? n)
+       . 1                     @result{}          1
+       * n : factorial @{n - 1@} @result{}    (* n (factorial @{n - 1@}))))
+@end example
+
+To execute a file with wisp code, select the language and filename
+extension @code{.w} vie @code{guile --language=wisp -x .w}.
+
+In files using Wisp, @xref{SRFI-105} (Curly Infix) is always activated.
+
+
 @node SRFI-171
 @subsection Transducers
 @cindex SRFI-171
@@ -5705,6 +5735,7 @@ left-to-right, due to how transducers are initiated.
 * SRFI-171 Helpers::                  Utilities for writing your own transducers
 @end menu
 
+
 @node SRFI-171 General Discussion
 @subsubsection SRFI-171 General Discussion
 @cindex transducers discussion
diff --git a/module/language/wisp.scm b/module/language/wisp.scm
new file mode 100644
index 000000000..b4e885eec
--- /dev/null
+++ b/module/language/wisp.scm
@@ -0,0 +1,784 @@
+;;; Wisp
+
+;; Copyright (C) 2013, 2017, 2018, 2020 Free Software Foundation, Inc.
+;; Copyright (C) 2014--2023 Arne Babenhauserheide.
+;; Copyright (C) 2023 Maxime Devos <maximedevos@telenet.be>
+
+;;;; This library is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU Lesser General Public
+;;;; License as published by the Free Software Foundation; either
+;;;; version 3 of the License, or (at your option) any later version.
+;;;;
+;;;; This library is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;;; Lesser General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU Lesser General Public
+;;;; License along with this library; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+;;; Commentary:
+
+;; Scheme-only implementation of a wisp-preprocessor which output a
+;; scheme code tree to feed to a scheme interpreter instead of a
+;; preprocessed file.
+
+;; Limitations:
+;; - in some cases the source line information is missing in backtraces.
+;;   check for set-source-property!
+
+;;; Code:
+
+(define-module (language wisp)
+  #:export (wisp-scheme-read-chunk wisp-scheme-read-all
+                                   wisp-scheme-read-file-chunk wisp-scheme-read-file
+                                   wisp-scheme-read-string)
+  #:use-module (srfi srfi-1)
+  #:use-module (srfi srfi-11); for let-values
+  #:use-module (srfi srfi-9); for records
+  #:use-module (ice-9 rw); for write-string/partial
+  #:use-module (ice-9 match))
+
+;; use curly-infix by default
+(eval-when (expand load eval)
+  (read-enable 'curly-infix))
+
+
+;; Helper functions for the indent-and-symbols data structure: '((indent token token ...) ...)
+(define make-line list)
+
+(define (line-indent line)
+  (car line))
+
+(define (line-real-indent line)
+  "Get the indentation without the comment-marker for unindented lines (-1 is treated as 0)."
+  (let ((indent (line-indent line)))
+    (if (= -1 indent)
+        0
+        indent)))
+
+(define (line-code line)
+  "Strip the indentation markers from the beginning of the line and preserve source-properties"
+  (let ((code (cdr line)))
+    ;; propagate source properties
+    (when (not (null? code))
+      (set-source-properties! code (source-properties line)))
+    code))
+
+;; literal values I need
+(define readcolon
+  (string->symbol ":"))
+
+(define wisp-uuid "e749c73d-c826-47e2-a798-c16c13cb89dd")
+;; define an intermediate dot replacement with UUID to avoid clashes.
+(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? repr-dot (car (line-code line))))
+
+(define (line-only-colon? line)
+  (and
+   (equal? ":" (car (line-code line)))
+   (null? (cdr (line-code line)))))
+
+(define (line-empty-code? line)
+  (null? (line-code line)))
+
+(define (line-empty? line)
+  (and
+   ;; if indent is -1, we stripped a comment, so the line was not really empty.
+   (= 0 (line-indent line))
+   (line-empty-code? line)))
+
+(define (line-strip-continuation line)
+  (if (line-continues? line)
+      (apply make-line
+             (line-indent line)
+             (cdr (line-code line)))
+      line))
+
+(define (line-strip-indentation-marker line)
+  "Strip the indentation markers from the beginning of the line for line-finalize without propagating source-properties (those are propagated in a second step)"
+  (cdr line))
+
+(define (indent-level-reduction indentation-levels level select-fun)
+  "Reduce the INDENTATION-LEVELS to the given LEVEL and return the value selected by SELECT-FUN"
+  (let loop
+      ((newlevels indentation-levels)
+       (diff 0))
+    (cond
+     ((= level (car newlevels))
+      (select-fun (list diff indentation-levels)))
+     ((< level (car newlevels))
+      (loop
+       (cdr newlevels)
+       (1+ diff)))
+     (else
+      (raise-exception (make-exception-from-throw 'wisp-syntax-error (list (format #f "Level ~A not found in the indentation-levels ~A." level indentation-levels))))))))
+
+(define (indent-level-difference indentation-levels level)
+  "Find how many indentation levels need to be popped off to find the given level."
+  (indent-level-reduction indentation-levels level
+                          (lambda (x); get the count
+                            (car x))))
+
+(define (indent-reduce-to-level indentation-levels level)
+  "Find how many indentation levels need to be popped off to find the given level."
+  (indent-level-reduction indentation-levels level
+                          (lambda (x); get the levels
+                            (car (cdr x)))))
+
+(define (chunk-ends-with-period currentsymbols next-char)
+  "Check whether indent-and-symbols ends with a period, indicating the end of a chunk."
+  (and (not (null? currentsymbols))
+       (equal? #\newline next-char)
+       (equal? repr-dot
+               (list-ref currentsymbols (- (length currentsymbols) 1)))))
+
+
+(define (wisp-scheme-read-chunk-lines port)
+  (let loop
+      ((indent-and-symbols (list)); '((5 "(foobar)" "\"yobble\"")(3 "#t"))
+       (in-indent? #t)
+       (in-underscoreindent? (equal? #\_ (peek-char port)))
+       (in-comment? #f)
+       (currentindent 0)
+       (currentsymbols '())
+       (emptylines 0))
+    (cond
+     ((>= emptylines 2)
+      ;; the chunk end has to be checked
+      ;; before we look for new chars in the
+      ;; port to make execution in the REPL
+      ;; after two empty lines work
+      ;; (otherwise it shows one more line).
+      indent-and-symbols)
+     (else
+      (let ((next-char (peek-char port)))
+        (cond
+         ((eof-object? next-char)
+          (let ((line (apply make-line currentindent currentsymbols)))
+            (set-source-property! line 'filename (port-filename port))
+            (set-source-property! line 'line (port-line port))
+            (append indent-and-symbols (list line))))
+         ((and in-indent? (zero? currentindent) (not in-comment?) (not (null? indent-and-symbols)) (not in-underscoreindent?) (not (or (equal? #\space next-char) (equal? #\newline next-char) (equal? (string-ref ";" 0) next-char))))
+          (append indent-and-symbols)); top-level form ends chunk
+         ((chunk-ends-with-period currentsymbols next-char)
+          ;; the line ends with a period. This is forbidden in
+          ;; SRFI-119. Use it to end the line in the REPL without
+          ;; showing continuation dots (...).
+          (append indent-and-symbols (list (apply make-line currentindent (drop-right currentsymbols 1)))))
+         ((and in-indent? (equal? #\space next-char))
+          (read-char port); remove char
+          (loop
+           indent-and-symbols
+           #t ; in-indent?
+           #f ; in-underscoreindent?
+           #f ; in-comment?
+           (1+ currentindent)
+           currentsymbols
+           emptylines))
+         ((and in-underscoreindent? (equal? #\_ next-char))
+          (read-char port); remove char
+          (loop
+           indent-and-symbols
+           #t ; in-indent?
+           #t ; in-underscoreindent?
+           #f ; in-comment?
+           (1+ currentindent)
+           currentsymbols
+           emptylines))
+         ;; 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. FIXME: breaks on lines with only
+         ;; underscores which should be empty lines.
+         ((and in-underscoreindent? (and (not (equal? #\space next-char)) (not (equal? #\newline next-char))))
+          (raise-exception (make-exception-from-throw 'wisp-syntax-error (list "initial underscores without following whitespace at beginning of the line after" (last indent-and-symbols)))))
+         ((equal? #\newline next-char)
+          (read-char port); remove the newline
+          (let*
+              ;; distinguish pure whitespace lines and lines
+              ;; with comment by giving the former zero
+              ;; indent. Lines with a comment at zero indent
+              ;; get indent -1 for the same reason - meaning
+              ;; not actually empty.
+              ((indent
+                (cond
+                 (in-comment?
+                  (if (= 0 currentindent); specialcase
+                      -1
+                      currentindent))
+                 ((not (null? currentsymbols)); pure whitespace
+                  currentindent)
+                 (else
+                  0)))
+               (parsedline (apply make-line indent currentsymbols))
+               (emptylines
+                (if (not (line-empty? parsedline))
+                    0
+                    (1+ emptylines))))
+            (when (not (= 0 (length (line-code parsedline))))
+              ;; set the source properties to parsedline so we can try to add them later.
+              (set-source-property! parsedline 'filename (port-filename port))
+              (set-source-property! parsedline 'line (port-line port)))
+            ;; TODO: If the line is empty. Either do it here and do not add it, just
+            ;; increment the empty line counter, or strip it later. Replace indent
+            ;; -1 by indent 0 afterwards.
+            (loop
+             (append indent-and-symbols (list parsedline))
+             #t ; in-indent?
+             (if (<= 2 emptylines)
+                 #f ; chunk ends here
+                 (equal? #\_ (peek-char port))); are we in underscore indent?
+             #f ; in-comment?
+             0
+             '()
+             emptylines)))
+         ((equal? #t in-comment?)
+          (read-char port); remove one comment character
+          (loop
+           indent-and-symbols
+           #f ; in-indent?
+           #f ; in-underscoreindent?
+           #t ; in-comment?
+           currentindent
+           currentsymbols
+           emptylines))
+         ((or (equal? #\space next-char) (equal? #\tab next-char) (equal? #\return next-char)); remove whitespace when not in indent
+          (read-char port); remove char
+          (loop
+           indent-and-symbols
+           #f ; in-indent?
+           #f ; in-underscoreindent?
+           #f ; in-comment?
+           currentindent
+           currentsymbols
+           emptylines))
+         ;; | cludge to appease the former wisp parser
+         ;; | used for bootstrapping which has a
+         ;; v problem with the literal comment char
+         ((equal? (string-ref ";" 0) next-char)
+          (loop
+           indent-and-symbols
+           #f ; in-indent?
+           #f ; in-underscoreindent?
+           #t ; in-comment?
+           currentindent
+           currentsymbols
+           emptylines))
+         (else ; use the reader
+          (loop
+           indent-and-symbols
+           #f ; in-indent?
+           #f ; in-underscoreindent?
+           #f ; in-comment?
+           currentindent
+           ;; this also takes care of the hashbang and leading comments.
+           (append currentsymbols (list (wisp-read port)))
+           emptylines))))))))
+
+
+(define (line-code-replace-inline-colons line)
+  "Replace inline colons by opening parens which close at the end of the line"
+  ;; format #t "replace inline colons for line ~A\n" line
+  (let loop
+      ((processed '())
+       (unprocessed line))
+    (cond
+     ((null? unprocessed)
+      ;; format #t "inline-colons processed line: ~A\n" processed
+      processed)
+     ;; replace : . with nothing
+     ((and (<= 2 (length unprocessed)) (equal? readcolon (car unprocessed)) (equal? repr-dot (car (cdr unprocessed))))
+      (loop
+       (append processed
+               (loop '() (cdr (cdr unprocessed))))
+       '()))
+     ((equal? readcolon (car unprocessed))
+      (loop
+       (append processed
+               (list (loop '() (cdr unprocessed))))
+       '()))
+     (else
+      (loop
+       (append processed
+               (list (car unprocessed)))
+       (cdr unprocessed))))))
+
+(define (line-replace-inline-colons line)
+  (cons
+   (line-indent line)
+   (line-code-replace-inline-colons (line-code line))))
+
+(define (line-strip-lone-colon line)
+  "A line consisting only of a colon is just a marked indentation level. We need to kill the colon before replacing inline colons."
+  (if (equal? (line-code line) (list readcolon))
+      (make-line (line-indent line))
+      line))
+
+(define (line-finalize line)
+  "Process all wisp-specific information in a line and strip it"
+  (let ((l (line-code-replace-inline-colons
+            (line-strip-indentation-marker
+             (line-strip-lone-colon
+              (line-strip-continuation line))))))
+    (when (not (null? (source-properties line)))
+      (catch #t
+        (lambda ()
+          (set-source-properties! l (source-properties line)))
+        (lambda (key . arguments)
+          #f)))
+    l))
+
+(define (wisp-add-source-properties-from source target)
+  "Copy the source properties from source into the target and return the target."
+  (catch #t
+    (lambda ()
+      (set-source-properties! target (source-properties source)))
+    (lambda (key . arguments)
+      #f))
+  target)
+
+(define (wisp-add-source-properties-from/when-required source target)
+  "Copy the source properties if target has none."
+  (if (null? (source-properties target))
+      (wisp-add-source-properties-from source target)
+      target))
+
+(define (wisp-propagate-source-properties code)
+  "Propagate the source properties from the sourrounding list into every part of the code."
+  (let loop
+      ((processed '())
+       (unprocessed code))
+    (cond
+     ((and (null? processed) (not (pair? unprocessed)) (not (list? unprocessed)))
+      unprocessed)
+     ((and (pair? unprocessed) (not (list? unprocessed)))
+      (cons
+       (wisp-propagate-source-properties (car unprocessed))
+       (wisp-propagate-source-properties (cdr unprocessed))))
+     ((null? unprocessed)
+      processed)
+     (else
+      (let ((line (car unprocessed)))
+        (wisp-add-source-properties-from/when-required line unprocessed)
+        (wisp-add-source-properties-from/when-required code unprocessed)
+        (wisp-add-source-properties-from/when-required unprocessed line)
+        (wisp-add-source-properties-from/when-required unprocessed code)
+        (let ((processed (append processed (list (wisp-propagate-source-properties line)))))
+          ;; must propagate from line, because unprocessed and code can be null, then they cannot keep source-properties.
+          (wisp-add-source-properties-from/when-required line processed)
+          (loop processed
+                (cdr unprocessed))))))))
+
+(define* (wisp-scheme-indentation-to-parens lines)
+  "Add parentheses to lines and remove the indentation markers"
+  (when
+      (and
+       (not (null? lines))
+       (not (line-empty-code? (car lines)))
+       (not (= 0 (line-real-indent (car lines))))); -1 is a line with a comment
+    (if (= 1 (line-real-indent (car lines)))
+        ;; accept a single space as indentation of the first line (and ignore the indentation) to support meta commands
+        (set! lines
+              (cons
+               (cons 0 (cdr (car lines)))
+               (cdr lines)))
+        (raise-exception
+         (make-exception-from-throw
+          'wisp-syntax-error
+          (list
+           (format #f "The first symbol in a chunk must start at zero indentation. Indentation and line: ~A"
+                   (car lines)))))))
+  (let loop
+      ((processed '())
+       (unprocessed lines)
+       (indentation-levels '(0)))
+    (let*
+        ((current-line
+          (if (<= 1 (length unprocessed))
+              (car unprocessed)
+              (make-line 0))); empty code
+         (next-line
+          (if (<= 2 (length unprocessed))
+              (car (cdr unprocessed))
+              (make-line 0))); empty code
+         (current-indentation
+          (car indentation-levels))
+         (current-line-indentation (line-real-indent current-line)))
+      ;; format #t "processed: ~A\ncurrent-line: ~A\nnext-line: ~A\nunprocessed: ~A\nindentation-levels: ~A\ncurrent-indentation: ~A\n\n"
+      ;;     . processed current-line next-line unprocessed indentation-levels current-indentation
+      (cond
+       ;; the real end: this is reported to the outside world.
+       ((and (null? unprocessed) (not (null? indentation-levels)) (null? (cdr indentation-levels)))
+        ;; reverse the processed lines, because I use cons.
+        processed)
+       ;; the recursion end-condition
+       ((and (null? unprocessed))
+        ;; this is the last step. Nothing more to do except
+        ;; for rolling up the indentation levels.  return the
+        ;; new processed and unprocessed lists: this is a
+        ;; side-recursion
+        (values processed unprocessed))
+       ((null? indentation-levels)
+        (raise-exception
+         (make-exception-from-throw
+          'wisp-programming-error
+          (list
+           "The indentation-levels are null but the current-line is null: Something killed the indentation-levels."))))
+       (else ; now we come to the line-comparisons and indentation-counting.
+        (cond
+         ((line-empty-code? current-line)
+          ;; We cannot process indentation without
+          ;; code. Just switch to the next line. This should
+          ;; only happen at the start of the recursion.
+          (loop
+           processed
+           (cdr unprocessed)
+           indentation-levels))
+         ((and (line-empty-code? next-line) (<= 2 (length unprocessed)))
+          ;; take out the next-line from unprocessed.
+          (loop
+           processed
+           (cons current-line
+                 (cdr (cdr unprocessed)))
+           indentation-levels))
+         ((> current-indentation current-line-indentation)
+          ;; this just steps back one level via the side-recursion.
+          (let ((previous-indentation (car (cdr indentation-levels))))
+            (if (<= current-line-indentation previous-indentation)
+                (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" (source-property current-line 'line) linenumber (cdr current-line)))
+                  (loop
+                   processed
+                   unprocessed
+                   (cons ; recursion via the indentation-levels
+                    current-line-indentation
+                    (cdr indentation-levels)))))))
+         ((= current-indentation current-line-indentation)
+          (let
+              ((line (line-finalize current-line))
+               (next-line-indentation (line-real-indent next-line)))
+            (cond
+             ((>= current-line-indentation next-line-indentation)
+              ;; simple recursiive step to the next line
+              (loop
+               (append processed
+                       (if (line-continues? current-line)
+                           line
+                           (wisp-add-source-properties-from line (list line))))
+               (cdr unprocessed); recursion here
+               indentation-levels))
+             ((< current-line-indentation next-line-indentation)
+              ;; side-recursion via a sublist
+              (let-values
+                  (((sub-processed sub-unprocessed)
+                    (loop
+                     line
+                     (cdr unprocessed); recursion here
+                     indentation-levels)))
+                (loop
+                 (append processed (list sub-processed))
+                 sub-unprocessed ; simply use the recursion from the sub-recursion
+                 indentation-levels))))))
+         ((< current-indentation current-line-indentation)
+          (loop
+           processed
+           unprocessed
+           (cons ; recursion via the indentation-levels
+            current-line-indentation
+            indentation-levels)))
+         (else
+          (raise-exception
+           (make-exception-from-throw
+            'wisp-not-implemented
+            (list
+             (format #f "Need to implement further line comparison: current: ~A, next: ~A, processed: ~A."
+                     current-line next-line processed)))))))))))
+
+
+(define (wisp-scheme-replace-inline-colons lines)
+  "Replace inline colons by opening parens which close at the end of the line"
+  (let loop
+      ((processed '())
+       (unprocessed lines))
+    (if (null? unprocessed)
+        processed
+        (loop
+         (append processed (list (line-replace-inline-colons (car unprocessed))))
+         (cdr unprocessed)))))
+
+
+(define (wisp-scheme-strip-indentation-markers lines)
+  "Strip the indentation markers from the beginning of the lines"
+  (let loop
+      ((processed '())
+       (unprocessed lines))
+    (if (null? unprocessed)
+        processed
+        (loop
+         (append processed (cdr (car unprocessed)))
+         (cdr unprocessed)))))
+
+(define (wisp-unescape-underscore-and-colon code)
+  "replace \\_ and \\: by _ and :"
+  (wisp-add-source-properties-from/when-required
+   code
+   (cond ((list? code) (map wisp-unescape-underscore-and-colon code))
+         ((eq? code '\:) ':)
+         ;; Look for symbols like \____ and remove the \.
+         ((symbol? code)
+          (let ((as-string (symbol->string code)))
+            (if (and (>= (string-length as-string) 2) ; at least a single underscore
+                     (char=? (string-ref as-string 0) #\\)
+                     (string-every #\_ (substring as-string 1)))
+                (string->symbol (substring as-string 1))
+                code)))
+         (#t code))))
+
+
+(define (wisp-replace-empty-eof code)
+  "replace ((#<eof>)) by ()"
+  ;; This is a hack which fixes a bug when the
+  ;; parser hits files with only hashbang and comments.
+  (if (and (not (null? code)) (pair? (car code)) (eof-object? (car (car code))) (null? (cdr code)) (null? (cdr (car code))))
+      (wisp-add-source-properties-from code (list))
+      code))
+
+
+(define (wisp-replace-paren-quotation-repr code)
+  "Replace lists starting with a quotation symbol by
+         quoted lists."
+  (wisp-add-source-properties-from/when-required
+   code
+   (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-QUASIQUOTE-e749c73d-c826-47e2-a798-c16c13cb89dd 'REPR-UNQUOTE-e749c73d-c826-47e2-a798-c16c13cb89dd a ...)
+      (list 'quasiquote (list 'unquote (map wisp-replace-paren-quotation-repr a))))
+     (('REPR-UNQUOTE-e749c73d-c826-47e2-a798-c16c13cb89dd a ...)
+      (list 'unquote (map wisp-replace-paren-quotation-repr a)))
+     ((a ... 'REPR-UNQUOTE-e749c73d-c826-47e2-a798-c16c13cb89dd b)
+      (append
+       (map wisp-replace-paren-quotation-repr a)
+       (list (list 'unquote (map wisp-replace-paren-quotation-repr b)))))
+     (('REPR-QUASIQUOTE-e749c73d-c826-47e2-a798-c16c13cb89dd a ...)
+      (list 'quasiquote (map wisp-replace-paren-quotation-repr a)))
+     ((a ... 'REPR-QUASIQUOTE-e749c73d-c826-47e2-a798-c16c13cb89dd b); this is the quoted empty list
+      (append
+       (map wisp-replace-paren-quotation-repr a)
+       (list (list 'quasiquote (map wisp-replace-paren-quotation-repr b)))))
+     (('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)))
+     ;; literal array as start of a line: # (a b) c -> (#(a b) c)
+     ((#\# a ...)
+      (with-input-from-string ;; hack to defer to read
+          (string-append "#"
+                         (with-output-to-string
+                           (λ ()
+                             (write (map wisp-replace-paren-quotation-repr a)
+                                    (current-output-port)))))
+        read))
+     ((a ...)
+      (map wisp-replace-paren-quotation-repr a))
+     (a
+      a))))
+
+(define (wisp-make-improper code)
+  "Turn (a #{.}# b) into the correct (a . b).
+
+read called on a single dot creates a variable named #{.}# (|.|
+in r7rs). Due to parsing the indentation before the list
+structure is known, the reader cannot create improper lists
+when it reads a dot. So we have to take another pass over the
+code to recreate the improper lists.
+
+Match is awesome!"
+  (define is-proper? #t)
+  ;; local alias
+  (define (add-prop/req form)
+    (wisp-add-source-properties-from/when-required code form))
+  (wisp-add-source-properties-from/when-required
+   code
+   (let
+       ((improper
+         (match code
+           ((a ... b 'REPR-DOT-e749c73d-c826-47e2-a798-c16c13cb89dd c)
+            (set! is-proper? #f)
+            (wisp-add-source-properties-from/when-required
+             code
+             (append (map wisp-make-improper (map add-prop/req a))
+                     (cons (wisp-make-improper (add-prop/req b))
+                           (wisp-make-improper (add-prop/req c))))))
+           ((a ...)
+            (add-prop/req
+             (map wisp-make-improper (map add-prop/req a))))
+           (a
+            a))))
+     (define (syntax-error li msg)
+       (raise-exception
+        (make-exception-from-throw
+         'wisp-syntax-error
+         (list (format #f "incorrect dot-syntax #{.}# in code: ~A: ~A" msg li)))))
+     (if is-proper?
+         improper
+         (let check
+             ((tocheck improper))
+           (match tocheck
+             ;; lists with only one member
+             (('REPR-DOT-e749c73d-c826-47e2-a798-c16c13cb89dd)
+              (syntax-error tocheck "list with the period as only member"))
+             ;; list with remaining dot.
+             ((a ...)
+              (if (and (member repr-dot a))
+                  (syntax-error tocheck "leftover period in list")
+                  (map check a)))
+             ;; simple pair - this and the next do not work when parsed from wisp-scheme itself. Why?
+             (('REPR-DOT-e749c73d-c826-47e2-a798-c16c13cb89dd . c)
+              (syntax-error tocheck "dot as first element in already improper pair"))
+             ;; simple pair, other way round
+             ((a . 'REPR-DOT-e749c73d-c826-47e2-a798-c16c13cb89dd)
+              (syntax-error tocheck "dot as last element in already improper pair"))
+             ;; more complex pairs
+             ((? pair? a)
+              (let
+                  ((head (drop-right a 1))
+                   (tail (last-pair a)))
+                (cond
+                 ((equal? repr-dot (car tail))
+                  (syntax-error tocheck "equal? repr-dot : car tail"))
+                 ((equal? repr-dot (cdr tail))
+                  (syntax-error tocheck "equal? repr-dot : cdr tail"))
+                 ((member repr-dot head)
+                  (syntax-error tocheck "member repr-dot head"))
+                 (else
+                  a))))
+             (a
+              a)))))))
+
+(define (wisp-scheme-read-chunk port)
+  "Read and parse one chunk of wisp-code"
+  (with-fluids ((%read-hash-procedures (fluid-ref %read-hash-procedures)))
+    (read-hash-extend #\# (lambda args #\#))
+    (let ((lines (wisp-scheme-read-chunk-lines port)))
+      (wisp-make-improper
+       (wisp-replace-empty-eof
+        (wisp-unescape-underscore-and-colon
+         (wisp-replace-paren-quotation-repr
+          (wisp-propagate-source-properties
+           (wisp-scheme-indentation-to-parens lines)))))))))
+
+(define (wisp-scheme-read-all port)
+  "Read all chunks from the given port"
+  (let loop
+      ((tokens '()))
+    (cond
+     ((eof-object? (peek-char port))
+      tokens)
+     (else
+      (loop
+       (append tokens (wisp-scheme-read-chunk port)))))))
+
+(define (wisp-scheme-read-file path)
+  (call-with-input-file path wisp-scheme-read-all))
+
+(define (wisp-scheme-read-file-chunk path)
+  (call-with-input-file path wisp-scheme-read-chunk))
+
+(define (wisp-scheme-read-string str)
+  (call-with-input-string str wisp-scheme-read-all))
+
+(define (wisp-scheme-read-string-chunk str)
+  (call-with-input-string str wisp-scheme-read-chunk))
diff --git a/module/language/wisp/spec.scm b/module/language/wisp/spec.scm
new file mode 100644
index 000000000..1efd3e8b2
--- /dev/null
+++ b/module/language/wisp/spec.scm
@@ -0,0 +1,73 @@
+;;; Language interface for Wisp in Guile
+
+;; Copyright (C) 2005--2014 by David A. Wheeler and Alan Manuel K. Gloria
+;; Copyright (C) 2014--2023 Arne Babenhauserheide.
+;; Copyright (C) 2023 Maxime Devos <maximedevos@telenet.be>
+
+;;;; This library is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU Lesser General Public
+;;;; License as published by the Free Software Foundation; either
+;;;; version 3 of the License, or (at your option) any later version.
+;;;;
+;;;; This library is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;;; Lesser General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU Lesser General Public
+;;;; License along with this library; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+;; adapted from spec.scm: https://gitorious.org/nacre/guile-sweet/?p=nacre:guile-sweet.git;a=blob;f=sweet/spec.scm;hb=ae306867e371cb4b56e00bb60a50d9a0b8353109
+
+(define-module (language wisp spec)
+  #:use-module (language wisp)
+  #:use-module (system base compile)
+  #:use-module (system base language)
+  #:use-module (language scheme compile-tree-il)
+  #:use-module (language scheme decompile-tree-il)
+  #:export (wisp))
+
+;;;
+;;; Language definition
+;;;
+
+
+(define (read-one-wisp-sexp port env)
+  ;; Allow using "# foo" as #(foo).
+  ;; Don't use the globally-acting read-hash-extend, because this
+  ;; doesn't make much sense in parenthese-y (non-Wisp) Scheme.
+  ;; Instead, use fluids to temporarily add the extension.
+  (with-fluids ((%read-hash-procedures (fluid-ref %read-hash-procedures)))
+    (read-hash-extend #\# (lambda args #\# ))
+    ;; Read Wisp files as UTF-8, to support non-ASCII characters.
+    ;; TODO: would be nice to support ';; coding: whatever' lines
+    ;; like in parenthese-y Scheme.
+    (set-port-encoding! port "UTF-8")
+    (if (eof-object? (peek-char port))
+        (read-char port) ; return eof: we’re done
+        (let ((chunk (wisp-scheme-read-chunk port)))
+          (and (not (null? chunk)) ; <---- XXX: maybe (pair? chunk)
+               (car chunk))))))
+
+(define-language wisp
+  #:title "Wisp Scheme Syntax. See SRFI-119 for details"
+  ; . #:reader read-one-wisp-sexp
+  #:reader read-one-wisp-sexp ; : lambda (port env) : let ((x (read-one-wisp-sexp port env))) (display x)(newline) x ;
+  #:compilers `((tree-il . ,compile-tree-il))
+  #:decompilers `((tree-il . ,decompile-tree-il))
+  #:evaluator (lambda (x module) (primitive-eval x))
+  #:printer write ; TODO: backtransform to wisp? Use source-properties?
+  #:make-default-environment
+  (lambda ()
+    ;; Ideally we'd duplicate the whole module hierarchy so that `set!',
+    ;; `fluid-set!', etc. don't have any effect in the current environment.
+    (let ((m (make-fresh-user-module)))
+      ;; Provide a separate `current-reader' fluid so that
+      ;; compile-time changes to `current-reader' are
+      ;; limited to the current compilation unit.
+      (module-define! m 'current-reader (make-fluid))
+      m)))
+
+
+
diff --git a/test-suite/Makefile.am b/test-suite/Makefile.am
index 81e63bce2..247d97746 100644
--- a/test-suite/Makefile.am
+++ b/test-suite/Makefile.am
@@ -162,7 +162,8 @@ SCM_TESTS = tests/00-initial-env.test		\
 	    tests/srfi-98.test			\
 	    tests/srfi-105.test			\
 	    tests/srfi-111.test			\
-            tests/srfi-171.test                 \
+	    tests/srfi-119.test			\
+	    tests/srfi-171.test			\
 	    tests/srfi-4.test			\
 	    tests/srfi-9.test			\
 	    tests/statprof.test			\
diff --git a/test-suite/tests/srfi-119.test b/test-suite/tests/srfi-119.test
new file mode 100644
index 000000000..f4a19a0a7
--- /dev/null
+++ b/test-suite/tests/srfi-119.test
@@ -0,0 +1,89 @@
+;;;; srfi-119.test --- Test suite for Guile's SRFI-119 reader. -*- scheme -*-
+;;;;
+;;;; Copyright (C) 2023 Free Software Foundation, Inc.
+;;;;
+;;;; This library is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU Lesser General Public
+;;;; License as published by the Free Software Foundation; either
+;;;; version 3 of the License, or (at your option) any later version.
+;;;;
+;;;; This library is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;;;; Lesser General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU Lesser General Public
+;;;; License along with this library; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+(define-module (test-srfi-119)
+  #:use-module (test-suite lib)
+  #:use-module (srfi srfi-1)
+  #:use-module (language wisp))
+
+(define (read-string s)
+  (with-input-from-string s read))
+
+(define (with-read-options opts thunk)
+  (let ((saved-options (read-options)))
+    (dynamic-wind
+        (lambda ()
+          (read-options opts))
+        thunk
+        (lambda ()
+          (read-options saved-options)))))
+
+(define (wisp->list str)
+        (wisp-scheme-read-string str))
+
+(with-test-prefix "wisp-read-simple"
+  (pass-if (equal? (wisp->list "<= n 5")    '((<= n 5))))
+  (pass-if (equal? (wisp->list ". 5") '(5)))
+  (pass-if (equal? (wisp->list "+ 1 : * 2 3") '((+ 1 (* 2 3))))))
+(with-test-prefix "wisp-read-complex"
+  (pass-if (equal? (wisp->list "
+a b c d e
+  . f g h
+  . i j k
+
+concat \"I want \"
+    getwish from me
+    . \" - \" username
+") '(
+(a b c d e
+  f g h
+  i j k)
+
+(concat "I want "
+    (getwish from me)
+    " - " username))))
+
+  (pass-if (equal? (wisp->list "
+define : a b c
+_ d e
+___ f
+___ g h
+__  . i
+
+define : _
+_  display \"hello\n\"
+
+\\_") '(
+(define (a b c)
+  (d e
+    (f)
+    (g h)
+    i))
+
+(define (_)
+   (display "hello\n"))
+
+(_))))
+
+  ;; nesting with pairs
+  (pass-if (equal? (wisp->list "1 . 2\n3 4\n   5 . 6")
+                   '((1 . 2)(3 4 (5 . 6))))))
+
+(with-test-prefix "wisp-source-properties"
+  (pass-if (not (find null? (map source-properties (wisp->list "1 . 2\n3 4\n   5 . 6")))))
+  (pass-if (not (find null? (map source-properties (wisp->list "1 2\n3 4\n   5 6"))))))
-- 
2.41.0


[-- Attachment #1.3: Type: text/plain, Size: 101 bytes --]


Best wishes,
Arne
-- 
Unpolitisch sein
heißt politisch sein,
ohne es zu merken.
draketo.de

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 1125 bytes --]

  reply	other threads:[~2023-08-14 20:11 UTC|newest]

Thread overview: 77+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-02-03 21:26 [PATCH] add language/wisp to Guile? Dr. Arne Babenhauserheide
2023-02-04 15:08 ` Maxime Devos
2023-02-04 15:46   ` Dr. Arne Babenhauserheide
2023-02-04 19:09     ` Maxime Devos
2023-02-04 21:35       ` Dr. Arne Babenhauserheide
2023-02-05 15:08         ` Maxime Devos
2023-02-14  8:32           ` Dr. Arne Babenhauserheide
2023-02-14 21:24             ` Dr. Arne Babenhauserheide
2023-02-14 23:01               ` Maxime Devos
2023-02-15  1:46                 ` Matt Wette
2023-02-16 21:38                   ` Dr. Arne Babenhauserheide
2023-02-17  1:26                     ` Matt Wette
2023-02-23 11:36                       ` Ludovic Courtès
2023-02-23 17:48                         ` Dr. Arne Babenhauserheide
2023-02-23 18:42                         ` Maxime Devos
2023-02-24 15:45                           ` Ludovic Courtès
2023-02-24 16:34                             ` Dr. Arne Babenhauserheide
2023-03-08 10:34                               ` Dr. Arne Babenhauserheide
2023-05-01  9:54                                 ` [PATCH] add SRFI-119 / language/wisp to Guile? (new patch, squashed) Dr. Arne Babenhauserheide
2023-06-10 16:40                                   ` Ludovic Courtès
2023-06-12 10:22                                     ` Maxime Devos
2023-08-10  6:28                                       ` Dr. Arne Babenhauserheide
2023-08-14 20:11                                         ` Dr. Arne Babenhauserheide [this message]
2023-08-14 20:30                                           ` Dr. Arne Babenhauserheide
2023-08-14 22:43                                           ` Dr. Arne Babenhauserheide
2023-08-18 10:29                                           ` Ludovic Courtès
2023-08-18 12:16                                             ` Dr. Arne Babenhauserheide
2023-08-18 17:50                                               ` Dr. Arne Babenhauserheide
2023-09-08 17:46                                               ` Dr. Arne Babenhauserheide
2023-10-05 14:10                                                 ` Dr. Arne Babenhauserheide
2023-10-10 23:04                                                   ` Dr. Arne Babenhauserheide
2023-10-27 22:05                                                     ` Dr. Arne Babenhauserheide
2024-01-09  7:05                                                       ` Dr. Arne Babenhauserheide
2024-01-19  8:21                                                         ` Dr. Arne Babenhauserheide
2024-03-11  1:16                                                           ` [PATCH] add SRFI-119 / language/wisp to Guile? (new patch with more tests, squashed) Dr. Arne Babenhauserheide
2024-01-19 12:10                                                         ` [PATCH] add SRFI-119 / language/wisp to Guile? (new patch, squashed) Christina O'Donnell
2024-01-19 21:37                                                           ` Ricardo Wurmus
2024-01-19 21:47                                                             ` Christina O'Donnell
2024-01-20 11:01                                                               ` Damien Mattei
2024-01-20 19:18                                                                 ` Dr. Arne Babenhauserheide
2024-01-20 22:59                                                                   ` Damien Mattei
2024-01-20 23:22                                                                     ` Dr. Arne Babenhauserheide
2024-01-21 23:21                                                                       ` Damien Mattei
2024-01-19 23:56                                                           ` Dr. Arne Babenhauserheide
2023-02-24 23:48                             ` [PATCH] add language/wisp to Guile? Maxime Devos
2023-02-24 23:51                               ` Maxime Devos
2023-02-25  0:15                                 ` Matt Wette
2023-02-25 10:42                                   ` Maxime Devos
2023-02-17 23:06                     ` Maxime Devos
2023-02-18  3:50                       ` Philip McGrath
2023-02-18 15:58                         ` Maxime Devos
2023-02-18 19:56                           ` Matt Wette
2023-02-21 12:09                             ` Dr. Arne Babenhauserheide
2023-02-26  7:45                           ` Philip McGrath
2023-02-26 15:42                             ` Maxime Devos
2023-02-26 16:14                               ` Dr. Arne Babenhauserheide
2023-02-26 17:58                               ` Matt Wette
2023-02-26 18:03                                 ` Dr. Arne Babenhauserheide
2023-02-26 18:20                                   ` Matt Wette
2023-02-26 21:39                                     ` Dr. Arne Babenhauserheide
2023-10-02 14:59                             ` Christine Lemmer-Webber
2023-10-02 21:46                               ` guile support for multiple languages [was: [PATCH] add language/wisp to Guile?] Matt Wette
2023-02-23  7:59                         ` [PATCH] add language/wisp to Guile? Maxime Devos
2023-02-23  8:51                           ` Dr. Arne Babenhauserheide
2023-02-23 18:04                             ` Maxime Devos
2023-02-23 18:22                               ` Maxime Devos
2023-02-23 18:36                               ` Maxime Devos
2023-02-23 18:37                               ` Maxime Devos
2023-02-15  8:36                 ` Dr. Arne Babenhauserheide
2023-02-15 20:13                   ` Maxime Devos
2023-02-16  7:01                     ` Dr. Arne Babenhauserheide
2023-02-16  8:03   ` Dr. Arne Babenhauserheide
2023-02-16 11:30     ` Maxime Devos
2023-02-16 21:35       ` Dr. Arne Babenhauserheide
2023-09-30 13:17 ` Christine Lemmer-Webber
2023-09-30 20:09   ` Maxime Devos
2023-10-02 14:48     ` Christine Lemmer-Webber

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/guile/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=875y5h8j04.fsf@web.de \
    --to=arne_bab@web.de \
    --cc=guile-devel@gnu.org \
    --cc=ludo@gnu.org \
    --cc=maximedevos@telenet.be \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).