From: Maxim Cournoyer <maxim.cournoyer@gmail.com>
To: guile-devel@gnu.org
Cc: Maxim Cournoyer <maxim.cournoyer@gmail.com>
Subject: [PATCH v9 17/18] module: Add SRFI 48.
Date: Tue, 12 Dec 2023 23:37:56 -0500 [thread overview]
Message-ID: <20231213044217.14093-18-maxim.cournoyer@gmail.com> (raw)
In-Reply-To: <20231213044217.14093-1-maxim.cournoyer@gmail.com>
* module/srfi/srfi-48.sld: New file.
* module/srfi/srfi-48/48.body.scm: Likewise.
* am/bootstrap.am (srfi/srfi-48.go): New target.
(SOURCES): Register srfi/srfi-48.sld.
(NOCOMP_SOURCES): Register srfi/srfi-48/48.upstream.scm.
* test-suite/tests/srfi-48.test: New test.
* test-suite/Makefile.am (SCM_TESTS): Register it.
---
(no changes since v1)
NEWS | 1 +
am/bootstrap.am | 5 +-
doc/ref/guile.texi | 6 +-
doc/ref/srfi-modules.texi | 264 ++++++++++++++++++
module/srfi/srfi-48.sld | 14 +
module/srfi/srfi-48/48.upstream.scm | 409 ++++++++++++++++++++++++++++
test-suite/Makefile.am | 1 +
test-suite/tests/srfi-48.test | 320 ++++++++++++++++++++++
8 files changed, 1016 insertions(+), 4 deletions(-)
create mode 100644 module/srfi/srfi-48.sld
create mode 100644 module/srfi/srfi-48/48.upstream.scm
create mode 100644 test-suite/tests/srfi-48.test
diff --git a/NEWS b/NEWS
index a269e0776..1c4dd7b56 100644
--- a/NEWS
+++ b/NEWS
@@ -21,6 +21,7 @@ definitely unused---this is notably the case for modules that are only
used at macro-expansion time, such as (srfi srfi-26). In those cases,
the compiler reports it as "possibly unused".
+** Add (srfi 48), a string format library
** Add (srfi 126), a hash tables library
** Add (srfi 128), a comparators library
** Add (scheme comparator)
diff --git a/am/bootstrap.am b/am/bootstrap.am
index 343fe6dcd..67460b32d 100644
--- a/am/bootstrap.am
+++ b/am/bootstrap.am
@@ -54,8 +54,10 @@ COMPILE = $(AM_V_GUILEC) \
.el.go:
$(COMPILE) --from=elisp -o "$@" "$<"
+# Rebuild modules when their included sources have changes.
ice-9/boot-9.go: ice-9/boot-9.scm ice-9/quasisyntax.scm ice-9/r6rs-libraries.scm ice-9/r7rs-libraries.scm ice-9/read.scm
ice-9/match.go: ice-9/match.scm ice-9/match.upstream.scm
+srfi/srfi-48.go: srfi/srfi-48/48.upstream.scm
srfi/srfi-64.go: srfi/srfi-64.scm srfi/srfi-64/testing.scm
# Keep this rule in sync with that in `am/guilec'.
@@ -358,6 +360,7 @@ SOURCES = \
srfi/srfi-43.scm \
srfi/srfi-39.scm \
srfi/srfi-45.scm \
+ srfi/srfi-48.sld \
srfi/srfi-60.scm \
srfi/srfi-64.scm \
srfi/srfi-67.scm \
@@ -474,7 +477,7 @@ NOCOMP_SOURCES = \
ice-9/quasisyntax.scm \
scheme/features.scm \
srfi/srfi-42/ec.scm \
- srfi/srfi-64/testing.scm \
+ srfi/srfi-48/48.upstream.scm \
srfi/srfi-67/compare.scm \
srfi/srfi-125/125.body.scm \
srfi/srfi-128/128.body1.scm \
diff --git a/doc/ref/guile.texi b/doc/ref/guile.texi
index f2a2d08f4..9be1b7540 100644
--- a/doc/ref/guile.texi
+++ b/doc/ref/guile.texi
@@ -24,9 +24,9 @@ Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A
copy of the license is included in the section entitled ``GNU Free
Documentation License.''
-Additionally, the documentation of the 125, 126, 128, 151, 160, 178 and
-209 SRFI modules is adapted from their specification text, which is made
-available under the following Expat license:
+Additionally, the documentation of the 48, 125, 126, 128, 151, 160, 178
+and 209 SRFI modules is adapted from their specification text, which is
+made available under the following Expat license:
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
diff --git a/doc/ref/srfi-modules.texi b/doc/ref/srfi-modules.texi
index 3ca18979f..650d7f27f 100644
--- a/doc/ref/srfi-modules.texi
+++ b/doc/ref/srfi-modules.texi
@@ -2,6 +2,7 @@
@c This is part of the GNU Guile Reference Manual.
@c Copyright (C) 1996, 1997, 2000-2004, 2006, 2007-2014, 2017, 2018, 2019, 2020
@c Free Software Foundation, Inc.
+@c Copyright (C) 2003 Kenneth A Dickey
@c Copyright (C) 2015-2016 Taylan Ulrich Bayırlı/Kammer
@c Copyright (C) 2015-2016, 2018, 2020 John Cowan
@c See the file guile.texi for copying conditions.
@@ -53,6 +54,7 @@ get the relevant SRFI documents from the SRFI home page
* SRFI-43:: Vector Library.
* SRFI-45:: Primitives for expressing iterative lazy algorithms
* SRFI-46:: Basic syntax-rules Extensions.
+* SRFI 48:: Intermediate Format Strings.
* SRFI-55:: Requiring Features.
* SRFI-60:: Integers as bits.
* SRFI-61:: A more general `cond' clause
@@ -5108,6 +5110,268 @@ SRFI-46/R7RS. Tail patterns have been supported since at least Guile
2.0, and custom ellipsis identifiers have been supported since Guile
2.0.10. @xref{Syntax Rules}.
+@node SRFI 48
+@subsection SRFI 48: Intermediate Format Strings
+@cindex SRFI 48
+
+@menu
+* SRFI 48 Abstract::
+* SRFI 48 Rationale::
+* SRFI 48 Specification::
+@end menu
+
+@node SRFI 48 Abstract
+@subsubsection SRFI 48 Abstract
+
+This document specifies Format Strings, a method of interpreting a
+Scheme string which contains a number of format directives that are
+replaced with other string data according to the semantics of each
+directive. This SRFI extends SRFI 28 in being more generally useful but
+is less general than advanced format strings in that it does not allow,
+aside from ~F, for controlled positioning of text within fields.
+
+@node SRFI 48 Rationale
+@subsubsection SRFI 48 Rationale
+
+Inheriting from MacLisp, nearly all Lisp and Scheme implementations
+support some form of FORMAT function with support for various numbers of
+format directives. By agreeing to the options here, we raise the bar
+for portable code.
+
+The reference implementation is R5RS compliant and easy to port. In not
+requiring advanced features (aside from @samp{~W} and @samp{~F}) small
+implementations are possible. E.g.@: the reference code does not use
+side effects (assignment) and is less than a third the source size of
+the latest SLIB implementation of FORMAT (less than a tenth if @samp{~F}
+support is elided).
+
+The optional @var{port} argument allows for compatibility with older
+code written for, e.g.@: scheme48, MIT Scheme, T, et cetera, which
+required a port argument. It is also useful in cases where a synoptic
+implementation of Scheme and CommonLisp is maintained.
+
+@node SRFI 48 Specification
+@subsubsection SRFI 48 Specification
+
+@deffn format [port] format-string [obj @dots{}]
+
+Accepts a format template (a Scheme String), and processes it, replacing
+any format directives in order with one or more characters, the
+characters themselves dependent on the semantics of the format directive
+encountered. Each directive may consume one @var{obj}. It is an error
+if fewer or more @var{obj} values are provided than format directives
+that require them.
+
+When @var{port} is specified it must be either an output port or a
+boolean. If an output port is specified, the formatted output is output
+into that port. If the @var{port} argument is @code{#t}, output is to
+the @code{current-output-port}. If @var{port} is @code{#f} or no port
+is specified, the output is returned as a string. If @var{port} is
+specified and is @code{#t} or an output port, the result of the format
+function is unspecified.
+
+It is unspecified which encoding is used (e.g.@: ASCII, EBCDIC,
+UNICODE). A given implementation must specify which encoding is used.
+The implementation may or may not allow the encoding to be selected or
+changed.
+
+It is an error if a format directive consumes an @var{obj} argument and
+that argument does not confirm to a required type as noted in the table
+below.
+
+It is permissible, but highly discouraged, to implement
+@code{pretty-print} as @samp{(define pretty-print write)}.
+
+A format directive is a two character sequence in the string where the
+first character is a tilde '~'. Directive characters are
+case-independent, i.e.@: upper and lower case characters are interpreted
+the same. Each directive code's meaning is described in the following
+table:
+
+@multitable @columnfractions .125 .20 .55 .125
+@headitem Directive @tab Mnemonic @tab Action @tab Consumes?
+@item ~a @tab Any @tab (display obj) for humans @tab yes
+@item ~s @tab Slashified @tab (write obj) for parsers @tab yes
+
+@item ~w @tab WriteCircular
+@tab (write-with-shared-structure obj) like ~s, but handles recursive structures
+@tab yes
+
+@item ~d @tab Decimal
+@tab the obj is a number which is output in decimal radix @tab yes
+
+@item ~x @tab heXadecimal
+@tab the obj is a number which is output in hexdecimal radix @tab yes
+
+@item ~o @tab Octal
+@tab the obj is a number which is output in octal radix @tab yes
+
+@item ~b @tab Binary
+@tab the obj is a number which is output in binary radix @tab yes
+
+@item ~c @tab Character
+@tab the single charater obj is output by write-char @tab yes
+
+@item ~y @tab Yuppify
+@tab the list obj is pretty-printed to the output @tab yes
+
+@item ~? @tab Indirection
+@tab the obj is another format-string and the following obj is a list
+of arguments; format is called recursively @tab yes
+
+@item ~K @tab Indirection
+@tab the same as ~? for backward compatibility with
+some existing implementations @tab yes
+
+@item ~[w[,d]]F @tab Fixed
+@tab ~w,dF outputs a number with width w and d digits after the decimal;
+~wF outputs a string or number with width w. @tab yes
+
+@item ~~ @tab Tilde @tab output a tilde @tab no
+@item ~t @tab Tab @tab output a tab character @tab no
+@item ~% @tab Newline @tab output a newline character @tab no
+
+@item ~& @tab Freshline
+@tab output a newline character if it is known that the previous
+output was not a newline @tab no
+
+@item ~_ @tab Space @tab a single space character is output @tab no
+
+@item ~h @tab Help
+@tab outputs one line of call synopsis, one line of comment, and one line of
+synopsis for each format directive, starting with the directive (e.g. "~t")
+@tab no
+@end multitable
+
+The @samp{~F}, fixed format, directive requires some elucidation.
+
+@samp{~wF} is useful for strings or numbers. Where the string (or
+@code{number->string} of the number) has fewer characters than the
+integer width @samp{w}, the string is padded on the left with space
+characters.
+
+@samp{~w,dF} is typically used only on numbers. For strings, the
+@samp{d} specifier is ignored. For numbers, the integer @samp{d}
+specifies the number of decimal digits after the decimal place. Both
+@samp{w} and @samp{d} must be zero or positive.
+
+If @samp{d} is specified, the number is processed as if added to 0.0,
+i.e.@: it is converted to an inexact value.
+
+@lisp
+(format "~8,2F" 1/3) => " 0.33"
+@end lisp
+
+If no @samp{d} is specified, the number is @emph{not} coerced to
+inexact.
+
+@lisp
+(format "~6F" 32) => " 32"
+@end lisp
+
+Digits are padded to the right with zeros.
+
+@lisp
+(format "~8,2F" 32) => " 32.00"
+@end lisp
+
+If the number is too large to fit in the width specified, a string
+longer than the width is returned.
+
+@lisp
+(format "~1,2F" 4321) => "4321.00"
+@end lisp
+
+If the number is complex, @samp{d} is applied to both real and imaginal
+parts.
+
+@lisp
+(format "~1,2F" (sqrt -3.9)) => "0.00+1.97i"
+@end lisp
+
+For very large or very small numbers, the point where exponential
+notation is used is implementation defined.
+
+@lisp
+(format "~8F" 32e5) => " 3.2e6" or "3200000.0"
+@end lisp
+
+@subsubheading Examples
+
+@lisp
+(format "~h")
+; =>
+"(format [<port>] <format-string> [<arg>@dots{}]) -- <port> is #t, #f or an output-port
+OPTION [MNEMONIC] DESCRIPTION -- This implementation Assumes ASCII Text Encoding
+~H [Help] output this text
+~A [Any] (display arg) for humans
+~S [Slashified] (write arg) for parsers
+~~ [tilde] output a tilde
+~T [Tab] output a tab character
+~% [Newline] output a newline character
+~& [Freshline] output a newline character if the previous output was not a newline
+~D [Decimal] the arg is a number which is output in decimal radix
+~X [heXadecimal] the arg is a number which is output in hexdecimal radix
+~O [Octal] the arg is a number which is output in octal radix
+~B [Binary] the arg is a number which is output in binary radix
+~w,dF [Fixed] the arg is a string or number which has width w and d digits after the decimal
+~C [Character] charater arg is output by write-char
+~_ [Space] a single space character is output
+~Y [Yuppify] the list arg is pretty-printed to the output
+~? [Indirection] recursive format: next arg is a format-string and the following arg a list of arguments
+~K [Indirection] same as ~?
+"
+(format "Hello, ~a" "World!")
+; => "Hello, World!"
+(format "Error, list is too short: ~s" '(one "two" 3))
+; => "Error, list is too short: (one \"two\" 3)"
+(format "test me")
+; => "test me"
+(format "~a ~s ~a ~s" 'this 'is "a" "test")
+; => "this is a \"test\""
+(format #t "#d~d #x~x #o~o #b~b~%" 32 32 32 32)
+;; Prints: #d32 #x20 #o40 #b100000
+; => <unspecified>
+(format "~a ~? ~a" 'a "~s" '(new) 'test)
+; =>"a new test"
+(format #f "~&1~&~&2~&~&~&3~%")
+; =>
+"
+1
+2
+3
+"
+(format #f "~a ~? ~a ~%" 3 " ~s ~s " '(2 2) 3)
+; =>
+"3 2 2 3
+"
+(format "~w" (let ( (c '(a b c)) ) (set-cdr! (cddr c) c) c))
+; => "#1=(a b c . #1#)"
+(format "~8,2F" 32)
+; => " 32.00"
+(format "~8,3F" (sqrt -3.8))
+; => "0.000+1.949i"
+(format "~8,2F" 3.4567e11)
+; => " 3.45e11"
+(format "~6,3F" 1/3)
+; => " 0.333"
+(format "~4F" 12)
+; => " 12"
+(format "~8,3F" 123.3456)
+; => " 123.346"
+ (format "~6,3F" 123.3456)
+; => "123.346"
+ (format "~2,3F" 123.3456)
+; => "123.346"
+(format "~8,3F" "foo")
+; => " foo"
+(format "~a~a~&" (list->string (list #\newline)) "")
+; =>
+"
+"
+@end lisp
+@end deffn
+
@node SRFI-55
@subsection SRFI-55 - Requiring Features
@cindex SRFI-55
diff --git a/module/srfi/srfi-48.sld b/module/srfi/srfi-48.sld
new file mode 100644
index 000000000..f488ca088
--- /dev/null
+++ b/module/srfi/srfi-48.sld
@@ -0,0 +1,14 @@
+;;;; SPDX-FileCopyrightText: 2014 Taylan Kammer <taylan.kammer@gmail.com>
+;;;;
+;;;; SPDX-License-Identifier: MIT
+
+(define-library (srfi 48)
+ (export format)
+ (import (rename (scheme base)
+ (exact inexact->exact)
+ (inexact exact->inexact))
+ (scheme char)
+ (scheme complex)
+ (rename (scheme write)
+ (write-shared write-with-shared-structure)))
+ (include "srfi-48/48.upstream.scm"))
diff --git a/module/srfi/srfi-48/48.upstream.scm b/module/srfi/srfi-48/48.upstream.scm
new file mode 100644
index 000000000..960d1a6b4
--- /dev/null
+++ b/module/srfi/srfi-48/48.upstream.scm
@@ -0,0 +1,409 @@
+;;; SPDX-FileCopyrightText: 2003 Kenneth A Dickey <ken.dickey@allvantage.com>
+;;; SPDX-FileCopyrightText: 2017 Hamayama <hamay1010@gmail.com>
+;;;
+;;; SPDX-License-Identifier: MIT
+
+;; IMPLEMENTATION DEPENDENT options
+
+(define ascii-tab (integer->char 9)) ;; NB: assumes ASCII encoding
+(define dont-print (if (eq? #t #f) 1))
+;;(define DONT-PRINT (string->symbol ""))
+;;(define DONT-PRINT (void))
+;;(define DONT-PRINT #!void)
+(define pretty-print write) ; ugly but permitted
+;; (require 'srfi-38) ;; write-with-shared-structure
+
+;; Following three procedures are used by format ~F .
+;; 'inexact-number->string' determines whether output is fixed-point
+;; notation or exponential notation. In the current definition,
+;; the notation depends on the implementation of 'number->string'.
+;; 'exact-number->string' is expected to output only numeric characters
+;; (not including such as '#', 'e', '.', '/') if the input is an positive
+;; integer or zero.
+;; 'real-number->string' is used when the digits of ~F is not specified.
+(define (inexact-number->string x) (number->string (exact->inexact x)))
+(define (exact-number->string x) (number->string (inexact->exact x)))
+(define (real-number->string x) (number->string x))
+
+;; FORMAT
+(define (format . args)
+ (cond
+ ((null? args)
+ (error "FORMAT: required format-string argument is missing")
+ )
+ ((string? (car args))
+ (apply format (cons #f args)))
+ ((< (length args) 2)
+ (error (format #f "FORMAT: too few arguments ~s" (cons 'format args)))
+ )
+ (else
+ (let ( (output-port (car args))
+ (format-string (cadr args))
+ (args (cddr args))
+ )
+ (letrec ( (port
+ (cond ((output-port? output-port) output-port)
+ ((eq? output-port #t) (current-output-port))
+ ((eq? output-port #f) (open-output-string))
+ (else (error
+ (format #f "FORMAT: bad output-port argument: ~s"
+ output-port)))
+ ) )
+ (return-value
+ (if (eq? output-port #f) ;; if format into a string
+ (lambda () (get-output-string port)) ;; then return the string
+ (lambda () dont-print)) ;; else do something harmless
+ )
+ )
+
+ (define (string-index str c)
+ (let ( (len (string-length str)) )
+ (let loop ( (i 0) )
+ (cond ((= i len) #f)
+ ((eqv? c (string-ref str i)) i)
+ (else (loop (+ i 1)))))))
+
+ (define (string-grow str len char)
+ (let ( (off (- len (string-length str))) )
+ (if (positive? off)
+ (string-append (make-string off char) str)
+ str)))
+
+ (define (compose-with-digits digits pre-str frac-str exp-str)
+ (let ( (frac-len (string-length frac-str)) )
+ (cond
+ ((< frac-len digits) ;; grow frac part, pad with zeros
+ (string-append pre-str "."
+ frac-str (make-string (- digits frac-len) #\0)
+ exp-str)
+ )
+ ((= frac-len digits) ;; frac-part is exactly the right size
+ (string-append pre-str "."
+ frac-str
+ exp-str)
+ )
+ (else ;; must round to shrink it
+ (let* ( (minus-flag (and (> (string-length pre-str) 0)
+ (char=? (string-ref pre-str 0) #\-)))
+ (pre-str* (if minus-flag
+ (substring pre-str 1 (string-length pre-str))
+ pre-str))
+ (first-part (substring frac-str 0 digits))
+ (last-part (substring frac-str digits frac-len))
+ (temp-str
+ (string-grow
+ (exact-number->string
+ (round (string->number
+ (string-append pre-str* first-part "." last-part))))
+ digits
+ #\0))
+ (temp-len (string-length temp-str))
+ (new-pre (substring temp-str 0 (- temp-len digits)))
+ (new-frac (substring temp-str (- temp-len digits) temp-len))
+ )
+ (string-append
+ (if minus-flag "-" "")
+ (if (string=? new-pre "")
+ ;; check if the system displays integer part of numbers
+ ;; whose absolute value is 0 < x < 1.
+ (if (and (string=? pre-str* "")
+ (> digits 0)
+ (not (= (string->number new-frac) 0)))
+ "" "0")
+ new-pre)
+ "."
+ new-frac
+ exp-str)))
+ ) ) )
+
+ (define (format-fixed number-or-string width digits) ; returns a string
+ (cond
+ ((string? number-or-string)
+ (string-grow number-or-string width #\space)
+ )
+ ((number? number-or-string)
+ (let ( (real (real-part number-or-string))
+ (imag (imag-part number-or-string))
+ )
+ (cond
+ ((not (zero? imag))
+ (string-grow
+ (string-append (format-fixed real 0 digits)
+ (if (negative? imag) "" "+")
+ (format-fixed imag 0 digits)
+ "i")
+ width
+ #\space)
+ )
+ (digits
+ (let* ( (num-str (inexact-number->string real))
+ (dot-index (string-index num-str #\.))
+ (exp-index (string-index num-str #\e))
+ (length (string-length num-str))
+ (pre-string
+ (if dot-index
+ (substring num-str 0 dot-index)
+ (if exp-index
+ (substring num-str 0 exp-index)
+ num-str))
+ )
+ (exp-string
+ (if exp-index
+ (substring num-str exp-index length)
+ "")
+ )
+ (frac-string
+ (if dot-index
+ (if exp-index
+ (substring num-str (+ dot-index 1) exp-index)
+ (substring num-str (+ dot-index 1) length))
+ "")
+ )
+ )
+ ;; check +inf.0, -inf.0, +nan.0, -nan.0
+ (if (string-index num-str #\n)
+ (string-grow num-str width #\space)
+ (string-grow
+ (compose-with-digits digits
+ pre-string
+ frac-string
+ exp-string)
+ width
+ #\space))
+ ))
+ (else ;; no digits
+ (string-grow (real-number->string real) width #\space)))
+ ))
+ (else
+ (error
+ (format "FORMAT: ~F requires a number or a string, got ~s" number-or-string)))
+ ))
+
+ (define documentation-string
+"(format [<port>] <format-string> [<arg>...]) -- <port> is #t, #f or an output-port
+OPTION [MNEMONIC] DESCRIPTION -- Implementation Assumes ASCII Text Encoding
+~H [Help] output this text
+~A [Any] (display arg) for humans
+~S [Slashified] (write arg) for parsers
+~W [WriteCircular] like ~s but outputs circular and recursive data structures
+~~ [tilde] output a tilde
+~T [Tab] output a tab character
+~% [Newline] output a newline character
+~& [Freshline] output a newline character if the previous output was not a newline
+~D [Decimal] the arg is a number which is output in decimal radix
+~X [heXadecimal] the arg is a number which is output in hexdecimal radix
+~O [Octal] the arg is a number which is output in octal radix
+~B [Binary] the arg is a number which is output in binary radix
+~w,dF [Fixed] the arg is a string or number which has width w and d digits after the decimal
+~C [Character] charater arg is output by write-char
+~_ [Space] a single space character is output
+~Y [Yuppify] the list arg is pretty-printed to the output
+~? [Indirection] recursive format: next 2 args are format-string and list of arguments
+~K [Indirection] same as ~?
+"
+ )
+
+ (define (require-an-arg args)
+ (if (null? args)
+ (error "FORMAT: too few arguments" ))
+ )
+
+ (define (format-help format-strg arglist)
+
+ (letrec (
+ (length-of-format-string (string-length format-strg))
+
+ (anychar-dispatch
+ (lambda (pos arglist last-was-newline)
+ (if (>= pos length-of-format-string)
+ arglist ; return unused args
+ (let ( (char (string-ref format-strg pos)) )
+ (cond
+ ((eqv? char #\~)
+ (tilde-dispatch (+ pos 1) arglist last-was-newline))
+ (else
+ (write-char char port)
+ (anychar-dispatch (+ pos 1) arglist #f)
+ ))
+ ))
+ )) ; end anychar-dispatch
+
+ (has-newline?
+ (lambda (whatever last-was-newline)
+ (or (eqv? whatever #\newline)
+ (and (string? whatever)
+ (let ( (len (string-length whatever)) )
+ (if (zero? len)
+ last-was-newline
+ (eqv? #\newline (string-ref whatever (- len 1)))))))
+ )) ; end has-newline?
+
+ (tilde-dispatch
+ (lambda (pos arglist last-was-newline)
+ (cond
+ ((>= pos length-of-format-string)
+ (write-char #\~ port) ; tilde at end of string is just output
+ arglist ; return unused args
+ )
+ (else
+ (case (char-upcase (string-ref format-strg pos))
+ ((#\A) ; Any -- for humans
+ (require-an-arg arglist)
+ (let ( (whatever (car arglist)) )
+ (display whatever port)
+ (anychar-dispatch (+ pos 1)
+ (cdr arglist)
+ (has-newline? whatever last-was-newline))
+ ))
+ ((#\S) ; Slashified -- for parsers
+ (require-an-arg arglist)
+ (let ( (whatever (car arglist)) )
+ (write whatever port)
+ (anychar-dispatch (+ pos 1)
+ (cdr arglist)
+ (has-newline? whatever last-was-newline))
+ ))
+ ((#\W)
+ (require-an-arg arglist)
+ (let ( (whatever (car arglist)) )
+ (write-with-shared-structure whatever port) ;; srfi-38
+ (anychar-dispatch (+ pos 1)
+ (cdr arglist)
+ (has-newline? whatever last-was-newline))
+ ))
+ ((#\D) ; Decimal
+ (require-an-arg arglist)
+ (display (number->string (car arglist) 10) port)
+ (anychar-dispatch (+ pos 1) (cdr arglist) #f)
+ )
+ ((#\X) ; HeXadecimal
+ (require-an-arg arglist)
+ (display (number->string (car arglist) 16) port)
+ (anychar-dispatch (+ pos 1) (cdr arglist) #f)
+ )
+ ((#\O) ; Octal
+ (require-an-arg arglist)
+ (display (number->string (car arglist) 8) port)
+ (anychar-dispatch (+ pos 1) (cdr arglist) #f)
+ )
+ ((#\B) ; Binary
+ (require-an-arg arglist)
+ (display (number->string (car arglist) 2) port)
+ (anychar-dispatch (+ pos 1) (cdr arglist) #f)
+ )
+ ((#\C) ; Character
+ (require-an-arg arglist)
+ (write-char (car arglist) port)
+ (anychar-dispatch (+ pos 1) (cdr arglist) (eqv? (car arglist) #\newline))
+ )
+ ((#\~) ; Tilde
+ (write-char #\~ port)
+ (anychar-dispatch (+ pos 1) arglist #f)
+ )
+ ((#\%) ; Newline
+ (newline port)
+ (anychar-dispatch (+ pos 1) arglist #t)
+ )
+ ((#\&) ; Freshline
+ (if (not last-was-newline) ;; (unless last-was-newline ..
+ (newline port))
+ (anychar-dispatch (+ pos 1) arglist #t)
+ )
+ ((#\_) ; Space
+ (write-char #\space port)
+ (anychar-dispatch (+ pos 1) arglist #f)
+ )
+ ((#\T) ; Tab -- IMPLEMENTATION DEPENDENT ENCODING
+ (write-char ascii-tab port)
+ (anychar-dispatch (+ pos 1) arglist #f)
+ )
+ ((#\Y) ; Pretty-print
+ (pretty-print (car arglist) port) ;; IMPLEMENTATION DEPENDENT
+ (anychar-dispatch (+ pos 1) (cdr arglist) #f)
+ )
+ ((#\F)
+ (require-an-arg arglist)
+ (display (format-fixed (car arglist) 0 #f) port)
+ (anychar-dispatch (+ pos 1) (cdr arglist) #f)
+ )
+ ((#\0 #\1 #\2 #\3 #\4 #\5 #\6 #\7 #\8 #\9) ;; gather "~w[,d]F" w and d digits
+ (let loop ( (index (+ pos 1))
+ (w-digits (list (string-ref format-strg pos)))
+ (d-digits '())
+ (in-width? #t)
+ )
+ (if (>= index length-of-format-string)
+ (error
+ (format "FORMAT: improper numeric format directive in ~s" format-strg))
+ (let ( (next-char (string-ref format-strg index)) )
+ (cond
+ ((char-numeric? next-char)
+ (if in-width?
+ (loop (+ index 1)
+ (cons next-char w-digits)
+ d-digits
+ in-width?)
+ (loop (+ index 1)
+ w-digits
+ (cons next-char d-digits)
+ in-width?))
+ )
+ ((char=? (char-upcase next-char) #\F)
+ (let ( (width (string->number (list->string (reverse w-digits))))
+ (digits (if (zero? (length d-digits))
+ #f
+ (string->number (list->string (reverse d-digits)))))
+ )
+ (display (format-fixed (car arglist) width digits) port)
+ (anychar-dispatch (+ index 1) (cdr arglist) #f))
+ )
+ ((char=? next-char #\,)
+ (if in-width?
+ (loop (+ index 1)
+ w-digits
+ d-digits
+ #f)
+ (error
+ (format "FORMAT: too many commas in directive ~s" format-strg)))
+ )
+ (else
+ (error (format "FORMAT: ~~w.dF directive ill-formed in ~s" format-strg))))))
+ ))
+ ((#\? #\K) ; indirection -- take next arg as format string
+ (cond ; and following arg as list of format args
+ ((< (length arglist) 2)
+ (error
+ (format "FORMAT: less arguments than specified for ~~?: ~s" arglist))
+ )
+ ((not (string? (car arglist)))
+ (error
+ (format "FORMAT: ~~? requires a string: ~s" (car arglist)))
+ )
+ (else
+ (format-help (car arglist) (cadr arglist))
+ (anychar-dispatch (+ pos 1) (cddr arglist) #f)
+ )))
+ ((#\H) ; Help
+ (display documentation-string port)
+ (anychar-dispatch (+ pos 1) arglist #t)
+ )
+ (else
+ (error (format "FORMAT: unknown tilde escape: ~s"
+ (string-ref format-strg pos))))
+ )))
+ )) ; end tilde-dispatch
+ ) ; end letrec
+
+ ; format-help main
+ (anychar-dispatch 0 arglist #f)
+ )) ; end format-help
+
+ ; format main
+ (let ( (unused-args (format-help format-string args)) )
+ (if (not (null? unused-args))
+ (error
+ (format "FORMAT: unused arguments ~s" unused-args)))
+ (return-value))
+
+ )) ; end letrec, if
+))) ; end format
diff --git a/test-suite/Makefile.am b/test-suite/Makefile.am
index 2b5156923..612f6935c 100644
--- a/test-suite/Makefile.am
+++ b/test-suite/Makefile.am
@@ -153,6 +153,7 @@ SCM_TESTS = tests/00-initial-env.test \
tests/srfi-42.test \
tests/srfi-43.test \
tests/srfi-45.test \
+ tests/srfi-48.test \
tests/srfi-60.test \
tests/srfi-64.test \
tests/srfi-67.test \
diff --git a/test-suite/tests/srfi-48.test b/test-suite/tests/srfi-48.test
new file mode 100644
index 000000000..9d97a863d
--- /dev/null
+++ b/test-suite/tests/srfi-48.test
@@ -0,0 +1,320 @@
+;;; SPDX-FileCopyrightText: 2017 Hamayama <hamay1010@gmail.com>
+;;;
+;;; SPDX-License-Identifier: MIT
+
+;;
+;; srfi-48 format test for Gauche, Sagittarius, Guile, Chez Scheme
+;;
+
+;;; START Guile-specific modifications.
+(use-modules (srfi srfi-48)
+ (test-suite lib))
+
+(define-syntax-rule (test-start name)
+ #t)
+
+(define-syntax-rule (test-end)
+ #t)
+
+(define-syntax-rule (test-section name)
+ #t)
+
+(define-syntax expect
+ (syntax-rules ()
+ ((_ expected result)
+ (pass-if (equal? expected result)))
+ ((_ expected result check)
+ (pass-if (check expected result)))))
+;;; END Guile-specific modifications.
+
+(cond-expand
+ (gauche)
+ (else
+ (define (x->number x)
+ (cond
+ ((number? x) x)
+ ((string? x) (string->number x))
+ (else (error "x->number error"))))
+ ))
+
+(define (nearly=? a b)
+ (let* ((a1 (x->number a))
+ (b1 (x->number b))
+ (e1 (abs (- a1 b1))))
+ ;(format #t "(a1 = ~s, b1 = ~s, e1 = ~s)~%" a1 b1 e1)
+ (< e1 1.0e-10)))
+
+(define pi 3.141592653589793)
+
+(test-start "srfi-48 format test")
+
+(test-section "original")
+(expect (format "test ~s" 'me) (format #f "test ~a" "me"))
+(expect " 0.333" (format "~6,3F" 1/3)) ;;; " .333" OK
+(expect " 12" (format "~4F" 12))
+(expect " 12.346" (format "~8,3F" 12.3456))
+(expect "123.346" (format "~6,3F" 123.3456))
+(expect "123.346" (format "~4,3F" 123.3456))
+(expect "0.000+1.949i" (format "~8,3F" (sqrt -3.8)))
+(expect " 32.00" (format "~6,2F" 32))
+(expect " 32" (format "~6F" 32))
+;(expect " 32." (format "~6F" 32.)) ;; " 32.0" OK
+(expect " 32.0" (format "~6F" 32.))
+;; NB: (not (and (exact? 32.) (integer? 32.)))
+(expect " 3.2e46" (format "~8F" 32e45))
+(expect " 3.2e-44" (format "~8F" 32e-45))
+(expect " 3.2e21" (format "~8F" 32e20))
+;;(expect " 3.2e6" (format "~8F" 32e5)) ;; ok. converted in input to 3200000.0
+;(expect " 3200." (format "~8F" 32e2)) ;; " 3200.0" OK
+(expect " 3200.0" (format "~8F" 32e2))
+(expect " 3.20e11" (format "~8,2F" 32e10))
+(expect " 1.2345" (format "~12F" 1.2345))
+(expect " 1.23" (format "~12,2F" 1.2345))
+(expect " 1.234" (format "~12,3F" 1.2345))
+(expect " 0.000+1.949i" (format "~20,3F" (sqrt -3.8)))
+(expect "0.000+1.949i" (format "~8,3F" (sqrt -3.8)))
+(expect " 3.46e11" (format "~8,2F" 3.4567e11))
+; (expect "#1=(a b c . #1#)"
+; (format "~w" (let ( (c '(a b c)) ) (set-cdr! (cddr c) c) c)))
+(expect "
+"
+ (format "~A~A~&" (list->string (list #\newline)) ""))
+(expect "a new test"
+ (format "~a ~? ~a" 'a "~s" '(new) 'test))
+(expect "a new test, yes!"
+ (format "~a ~?, ~a!" 'a "~s ~a" '(new test) 'yes))
+(expect " 3.46e20" (format "~8,2F" 3.4567e20))
+(expect " 3.46e21" (format "~8,2F" 3.4567e21))
+(expect " 3.46e22" (format "~8,2F" 3.4567e22))
+(expect " 3.46e23" (format "~8,2F" 3.4567e23))
+(expect " 3.e24" (format "~8,0F" 3.4567e24))
+(expect " 3.5e24" (format "~8,1F" 3.4567e24))
+(expect " 3.46e24" (format "~8,2F" 3.4567e24))
+(expect "3.457e24" (format "~8,3F" 3.4567e24))
+(expect " 4.e24" (format "~8,0F" 3.5567e24))
+(expect " 3.6e24" (format "~8,1F" 3.5567e24))
+(expect " 3.56e24" (format "~8,2F" 3.5567e24))
+(expect " -3.e-4" (format "~10,0F" -3e-4))
+(expect " -3.0e-4" (format "~10,1F" -3e-4))
+(expect " -3.00e-4" (format "~10,2F" -3e-4))
+(expect " -3.000e-4" (format "~10,3F" -3e-4))
+(expect "-3.0000e-4" (format "~10,4F" -3e-4))
+(expect "-3.00000e-4" (format "~10,5F" -3e-4))
+(expect " 1.020" (format "~10,3F" 1.02))
+(expect " 1.025" (format "~10,3F" 1.025))
+(expect " 1.026" (format "~10,3F" 1.0256))
+(expect " 1.002" (format "~10,3F" 1.002))
+(expect " 1.002" (format "~10,3F" 1.0025))
+(expect " 1.003" (format "~10,3F" 1.00256))
+
+
+(test-section "examples")
+(expect " 0.33" (format "~8,2F" 1/3))
+(expect " 32" (format "~6F" 32))
+(expect " 32.00" (format "~8,2F" 32))
+(expect "4321.00" (format "~1,2F" 4321))
+(expect "0.00+1.97i" (format "~1,2F" (sqrt -3.9)))
+(expect "3200000.0" (format "~8F" 32e5))
+;(expect " 3.2e6" (format "~8F" 32e5))
+(expect "<string>" (format "~h") (lambda (e r) (string? r)))
+(expect "Hello, World!" (format "Hello, ~a" "World!"))
+(expect "Error, list is too short: (one \"two\" 3)" (format "Error, list is too short: ~s" '(one "two" 3)))
+(expect "test me" (format "test me"))
+(expect "this is a \"test\"" (format "~a ~s ~a ~s" 'this 'is "a" "test"))
+(expect (if #f #f) (format #t "#d~d #x~x #o~o #b~b~%" 32 32 32 32))
+(expect "a new test" (format "~a ~? ~a" 'a "~s" '(new) 'test))
+(expect "\n1\n2\n3\n" (format #f "~&1~&~&2~&~&~&3~%"))
+(expect "3 2 2 3 \n" (format #f "~a ~? ~a ~%" 3 " ~s ~s " '(2 2) 3))
+;; incorrect mutation of literal list in example
+;(expect "#1=(a b c . #1#)" (format "~w" (let ( (c '(a b c)) ) (set-cdr! (cddr c) c) c)))
+(cond-expand
+ (chezscheme)
+ (guile
+ (expect "#1=(a b c . #1#)" (format "~w" (let ( (c (list 'a 'b 'c)) ) (set-cdr! (cddr c) c) c)))
+ )
+ (else
+ (expect "#0=(a b c . #0#)" (format "~w" (let ( (c (list 'a 'b 'c)) ) (set-cdr! (cddr c) c) c)))
+ ))
+(expect " 32.00" (format "~8,2F" 32))
+(expect "0.000+1.949i" (format "~8,3F" (sqrt -3.8)))
+;(expect " 3.45e11" (format "~8,2F" 3.4567e11))
+(expect " 3.46e11" (format "~8,2F" 3.4567e11))
+(expect " 0.333" (format "~6,3F" 1/3))
+(expect " 12" (format "~4F" 12))
+(expect " 123.346" (format "~8,3F" 123.3456))
+(expect "123.346" (format "~6,3F" 123.3456))
+(expect "123.346" (format "~2,3F" 123.3456))
+(expect " foo" (format "~8,3F" "foo"))
+(expect "\n" (format "~a~a~&" (list->string (list #\newline)) ""))
+
+
+(test-section "~F normal")
+(expect "0" (format "~F" 0))
+(expect "1" (format "~F" 1))
+(expect "123" (format "~F" 123))
+(expect "0.456" (format "~F" 0.456))
+(expect "123.456" (format "~F" 123.456))
+(expect "-1" (format "~F" -1))
+(expect "-123" (format "~F" -123))
+(expect "-0.456" (format "~F" -0.456))
+(expect "-123.456" (format "~F" -123.456))
+
+
+(test-section "~F width")
+(expect "123" (format "~0F" 123))
+(expect "123" (format "~1F" 123))
+(expect "123" (format "~2F" 123))
+(expect "123" (format "~3F" 123))
+(expect " 123" (format "~4F" 123))
+(expect " 123" (format "~5F" 123))
+(expect "-123" (format "~3F" -123))
+(expect "-123" (format "~4F" -123))
+(expect " -123" (format "~5F" -123))
+(expect " -123" (format "~6F" -123))
+
+
+(test-section "~F digits")
+(expect "123." (format "~1,0F" 123))
+(expect "123.0" (format "~1,1F" 123))
+(expect "123.00" (format "~1,2F" 123))
+(expect "0.12" (format "~1,2F" 0.123))
+(expect "0.123" (format "~1,3F" 0.123))
+(expect "0.1230" (format "~1,4F" 0.123))
+(expect "-123." (format "~1,0F" -123))
+(expect "-123.0" (format "~1,1F" -123))
+(expect "-123.00" (format "~1,2F" -123))
+(expect "-0.12" (format "~1,2F" -0.123))
+(expect "-0.123" (format "~1,3F" -0.123))
+(expect "-0.1230" (format "~1,4F" -0.123))
+
+
+(test-section "~F rounding (banker's rounding)")
+(expect "123." (format "~1,0F" 123.456))
+(expect "123.5" (format "~1,1F" 123.456))
+(expect "123.46" (format "~1,2F" 123.456))
+(expect "-123." (format "~1,0F" -123.456))
+(expect "-123.5" (format "~1,1F" -123.456))
+(expect "-123.46" (format "~1,2F" -123.456))
+(expect "123.0" (format "~1,1F" 123.05))
+(expect "123.2" (format "~1,1F" 123.15))
+(expect "124.0" (format "~1,1F" 123.95))
+(expect "-123.0" (format "~1,1F" -123.05))
+(expect "-123.2" (format "~1,1F" -123.15))
+(expect "-124.0" (format "~1,1F" -123.95))
+(expect "1000.00" (format "~1,2F" 999.995))
+(expect "-1000.00" (format "~1,2F" -999.995))
+(expect "1." (format "~1,0F" 1.49))
+(expect "2." (format "~1,0F" 1.5))
+(expect "2." (format "~1,0F" 1.51))
+(expect "2." (format "~1,0F" 2.49))
+(expect "2." (format "~1,0F" 2.5))
+(expect "3." (format "~1,0F" 2.51))
+
+
+(test-section "~F misc")
+(expect "+inf.0" (format "~F" +inf.0))
+(expect "-inf.0" (format "~F" -inf.0))
+(expect "+nan.0" (format "~F" +nan.0))
+(expect "0.0" (format "~F" 0.0))
+(expect "-0.0" (format "~F" -0.0))
+(expect "+inf.0" (format "~1F" +inf.0))
+(expect "-inf.0" (format "~1F" -inf.0))
+(expect "+nan.0" (format "~1F" +nan.0))
+(expect "0.0" (format "~1F" 0.0))
+(expect "-0.0" (format "~1F" -0.0))
+(expect "+inf.0" (format "~1,0F" +inf.0))
+(expect "-inf.0" (format "~1,0F" -inf.0))
+(expect "+nan.0" (format "~1,0F" +nan.0))
+(expect "0." (format "~1,0F" 0.0))
+(expect "-0." (format "~1,0F" -0.0))
+(expect "+inf.0" (format "~1,1F" +inf.0))
+(expect "-inf.0" (format "~1,1F" -inf.0))
+(expect "+nan.0" (format "~1,1F" +nan.0))
+(expect "0.0" (format "~1,1F" 0.0))
+(expect "-0.0" (format "~1,1F" -0.0))
+(expect "31.41592653589793" (format "~F" (* pi 10)))
+(expect "0.33333" (format "~1,5F" 1/3))
+(expect "-0.33333" (format "~1,5F" -1/3))
+(expect "0.142857142857" (format "~1,12F" 1/7))
+(expect "299999999.999999999" (format "~F" 299999999999999999/1000000000) nearly=?)
+(expect "1.797693e308" (format "~F" 1.797693e308))
+(expect "1.797693e308" (format "~1F" 1.797693e308))
+(expect "2.e308" (format "~1,0F" 1.797693e308))
+(expect "1.8e308" (format "~1,1F" 1.797693e308))
+(expect "-1.797693e308" (format "~F" -1.797693e308))
+(expect "-1.797693e308" (format "~1F" -1.797693e308))
+(expect "-2.e308" (format "~1,0F" -1.797693e308))
+(expect "-1.8e308" (format "~1,1F" -1.797693e308))
+(expect "2.225074e-308" (format "~F" 2.225074e-308))
+(expect "5.02" (format "~1,2F" 5.015))
+(expect "6.00" (format "~1,2F" 5.999))
+(expect "123." (format "~1,0F" 123.00))
+(expect "0.1" (format "~F" .1))
+(expect "1" (format "~1f" 1)) ; lower case f
+(expect "1.e100" (format "~1,0F" 1e100))
+(expect "1." (format "~1,0F" 1))
+(expect "0." (format "~1,0F" .1))
+(expect "0.0" (format "~1,1F" .01))
+
+
+(cond-expand
+ (guile)
+ (else
+ (test-section "~F error")
+ (expect "<error>" (guard (e (else "<error>")) (format "~-1F" 1)))
+ (expect "<error>" (guard (e (else "<error>")) (format "~1,-1F" 1)))
+ ))
+
+
+(test-section "from mailing list 2004-05-27")
+(expect "1.230e20" (format "~0,3F" 1.23e20))
+(expect "1.230e-20" (format "~0,3F" 1.23e-20))
+
+
+(test-section "from mailing list 2004-06-11")
+(expect "3.457e15" (format "~8,3F" 3.4569e15))
+(expect " 3.457" (format "~8,3F" 3.4569))
+(expect " 3.46e15" (format "~8,2F" 3.456e15))
+(expect " 3.46" (format "~8,2F" 3.456))
+
+
+(test-section "from mailing list 2005-06-03")
+(expect " -3.e-4" (format "~10,0F" -3e-4))
+(expect " -3.0e-4" (format "~10,1F" -3e-4))
+(expect " -3.00e-4" (format "~10,2F" -3e-4))
+(expect " -3.000e-4" (format "~10,3F" -3e-4))
+(expect "-3.0000e-4" (format "~10,4F" -3e-4))
+(expect " 3.0000e-5" (format "~10,4F" 3e-5))
+
+
+(test-section "from mailing list 2005-06-07")
+(expect " 1.020" (format "~10,3F" 1.02))
+(expect " 1.025" (format "~10,3F" 1.025))
+(expect " 1.026" (format "~10,3F" 1.0256))
+(expect " 1.002" (format "~10,3F" 1.002))
+(expect " 1.002" (format "~10,3F" 1.0025))
+(expect " 1.003" (format "~10,3F" 1.00256))
+
+
+(test-section "from mailing list 2005-06-07")
+(expect "1.000012" (format "~8,6F" 1.00001234))
+
+
+(test-section "from mailing list 2005-07-02")
+(expect "abc\ndef\nghi\n" (format "abc~%~&def~&ghi~%"))
+(expect "\ndef\nghi\n" (format "~&def~&ghi~%"))
+
+
+(test-section "from mailing list 2017-10-11")
+(expect " 1.00" (format "~7,2F" .997554209949891))
+(expect " 1.00" (format "~7,2F" .99755))
+(expect " 1.00" (format "~7,2F" .9975))
+(expect " 1.00" (format "~7,2F" .997))
+(expect " 0.99" (format "~7,2F" .99))
+
+
+(test-section "from mailing list 2017-10-13")
+(expect " 18.00" (format "~7,2F" 18.0000000000008))
+(expect " -15." (format "~8,0F" -14.99995999999362))
+
+(test-end)
--
2.41.0
next prev parent reply other threads:[~2023-12-13 4:37 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-12-13 4:37 [PATCH v9 00/18] Add SRFI 209 and dependencies; improve support for R7RS libraries Maxim Cournoyer
2023-12-13 4:37 ` [PATCH v9 01/18] ice-9: Fix 'include' when used in compilation contexts Maxim Cournoyer
2023-12-13 4:37 ` [PATCH v9 02/18] Use R7RS 'rename' syntax for exports Maxim Cournoyer
2023-12-13 4:37 ` [PATCH v9 03/18] r7rs-libraries: Add support for 'else' clause in cond-expand Maxim Cournoyer
2023-12-13 4:37 ` [PATCH v9 04/18] r7rs-libraries: Better support R7RS SRFI library names Maxim Cournoyer
2023-12-13 4:37 ` [PATCH v9 05/18] (scheme base): Support non-negative SRFI integer names in cond-expand Maxim Cournoyer
2023-12-13 4:37 ` [PATCH v9 06/18] Share features tested by cond-expand library declarations and expressions Maxim Cournoyer
2023-12-13 4:37 ` [PATCH v9 07/18] build: Register '.sld' as an alternative extension to '.scm' Maxim Cournoyer
2023-12-13 4:37 ` [PATCH v9 08/18] module: Add SRFI 126 Maxim Cournoyer
2023-12-13 4:37 ` [PATCH v9 09/18] module: Add SRFI 128 Maxim Cournoyer
2023-12-13 4:37 ` [PATCH v9 10/18] module: Add (scheme comparator) Maxim Cournoyer
2023-12-13 4:37 ` [PATCH v9 11/18] module: Add (scheme sort) Maxim Cournoyer
2023-12-13 4:37 ` [PATCH v9 12/18] module: Add SRFI 125 Maxim Cournoyer
2023-12-13 4:37 ` [PATCH v9 13/18] module: Add SRFI 151 Maxim Cournoyer
2023-12-13 4:37 ` [PATCH v9 14/18] module: Add SRFI 160 Maxim Cournoyer
2023-12-13 4:37 ` [PATCH v9 15/18] module: Add SRFI 178 Maxim Cournoyer
2023-12-13 4:37 ` [PATCH v9 16/18] module: Add SRFI 209 Maxim Cournoyer
2023-12-13 4:37 ` Maxim Cournoyer [this message]
2023-12-13 4:37 ` [PATCH v9 18/18] module: Upgrade SRFI 64 to modern R7RS library implementation Maxim Cournoyer
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=20231213044217.14093-18-maxim.cournoyer@gmail.com \
--to=maxim.cournoyer@gmail.com \
--cc=guile-devel@gnu.org \
/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).