Re: [PATCH] Implement SRFI 28

2014-12-01 Thread Chris K. Jester-Young
Hi Mark,

Thanks for your review! I've implemented all your review comments, and
have attached a new patch.

On Mon, Dec 01, 2014 at 01:52:08PM -0500, Mark H Weaver wrote:
   Also, please put two spaces
 between sentences.

I sidestepped this by putting the new sentence on a new line. This is
also what I do with all the manpages I write. :-D

Cheers,
Chris.
From 34cfbd817aecc119fd6bbc9925a6ecbace3961bc Mon Sep 17 00:00:00 2001
From: Chris Jester-Young cky...@gmail.com
Date: Sun, 30 Nov 2014 05:20:54 -0500
Subject: [PATCH] Implement SRFI 28: Basic Format Strings.

* module/srfi/srfi-28.scm: New module.
* module/Makefile.am (SRFI_SOURCES): Add srfi/srfi-28.scm.
* doc/ref/srfi-modules.texi (SRFI-28): New node.
---
 doc/ref/srfi-modules.texi | 37 +
 module/Makefile.am|  1 +
 module/srfi/srfi-28.scm   | 34 ++
 3 files changed, 72 insertions(+)
 create mode 100644 module/srfi/srfi-28.scm

diff --git a/doc/ref/srfi-modules.texi b/doc/ref/srfi-modules.texi
index 2cf9fd1..d8ed8e1 100644
--- a/doc/ref/srfi-modules.texi
+++ b/doc/ref/srfi-modules.texi
@@ -38,6 +38,7 @@ get the relevant SRFI documents from the SRFI home page
 * SRFI-23:: Error reporting
 * SRFI-26:: Specializing parameters
 * SRFI-27:: Sources of Random Bits
+* SRFI-28:: Basic format strings.
 * SRFI-30:: Nested multi-line block comments
 * SRFI-31:: A special form `rec' for recursive evaluation
 * SRFI-34:: Exception handling.
@@ -3276,6 +3277,42 @@ reasonably small value (related to the width of the mantissa of an
 efficient number format).
 @end defun
 
+@node SRFI-28
+@subsection SRFI-28 - Basic Format Strings
+@cindex SRFI-28
+
+SRFI-28 provides a basic @code{format} procedure that provides only
+the @code{~a}, @code{~s}, @code{~%}, and @code{~~} format specifiers.
+You can import this procedure by using:
+
+@lisp
+(use-modules (srfi srfi-28))
+@end lisp
+
+@deffn {Scheme Procedure} format message arg @dots{}
+Returns a formatted message, using @var{message} as the format string,
+which can contain the following format specifiers:
+
+@table @code
+@item ~a
+Insert the textual representation of the next @var{arg}, as if printed
+by @code{display}.
+
+@item ~s
+Insert the textual representation of the next @var{arg}, as if printed
+by @code{write}.
+
+@item ~%
+Insert a newline.
+
+@item ~~
+Insert a tilde.
+@end table
+
+This procedure is the same as calling @code{simple-format} (@pxref{Writing})
+with @code{#f} as the destination.
+@end deffn
+
 @node SRFI-30
 @subsection SRFI-30 - Nested Multi-line Comments
 @cindex SRFI-30
diff --git a/module/Makefile.am b/module/Makefile.am
index a9aaa76..7e96de7 100644
--- a/module/Makefile.am
+++ b/module/Makefile.am
@@ -278,6 +278,7 @@ SRFI_SOURCES = \
   srfi/srfi-19.scm \
   srfi/srfi-26.scm \
   srfi/srfi-27.scm \
+  srfi/srfi-28.scm \
   srfi/srfi-31.scm \
   srfi/srfi-34.scm \
   srfi/srfi-35.scm \
diff --git a/module/srfi/srfi-28.scm b/module/srfi/srfi-28.scm
new file mode 100644
index 000..7fc73eb
--- /dev/null
+++ b/module/srfi/srfi-28.scm
@@ -0,0 +1,34 @@
+;;; srfi-28.scm --- Basic Format Strings
+
+;; Copyright (C) 2014 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
+
+;;; Commentary:
+
+;; This module provides a wrapper for simple-format that always outputs
+;; to a string.
+;;
+;; This module is documented in the Guile Reference Manual.
+
+;;; Code:
+
+(define-module (srfi srfi-28)
+  #:replace (format))
+
+(define (format message . args)
+  (apply simple-format #f message args))
+
+(cond-expand-provide (current-module) '(srfi-28))
-- 
1.9.3 (Apple Git-50)



[PATCH] Fixing srfi-18.test when building on OS X with clang

2014-11-30 Thread Chris K. Jester-Young
Hi there,

I've recently been poking around the srfi-18.test failure that occurs
when building on OS X with the Xcode-provided clang. (Tested on OS X
10.10 Yosemite with Xcode 6.1.) It seems other people have experienced
the same problem on older versions, so it's not unique to this version:
http://lists.gnu.org/archive/html/guile-devel/2014-04/msg3.html

Therefore, I've posted a patch in hopes that other OS X users could
test it out and see if it fixes things for them. Please let me know of
any improvements to the patch, too. :-)

The basic purpose of the patch is to disable thread-local storage when
building on OS X. This is probably clang-specific, but I don't have
enough autotools-fu to check for that. In any case, when using TLS, the
value of (current-thread) is not always correctly maintained, which
then causes srfi-18.test to fail.

Many thanks,
Chris.

P.S. Note that I manually build all the dependent packages, each at the
latest current version. I do not use Homebrew or anything similar, and
I always run make check and ensure that each package is green before
installing. Here are the actual versions I presently have installed:

+ autoconf-2.69
+ automake-1.14
+ bdwgc-7.4.2
+ gettext-0.19.3
+ gmp-6.0.0a
+ libatomic_ops-7.4.2
+ libffi-3.2.1
+ libtool-2.4.3
+ libunistring-0.9.4
+ pkg-config-0.28
+ readline-6.3
From 18bc7bd726adb6c820bdc008c8e8fe091deb0313 Mon Sep 17 00:00:00 2001
From: Chris Jester-Young cky...@gmail.com
Date: Sun, 30 Nov 2014 02:10:51 -0500
Subject: [PATCH] Do not use thread-local storage on OS X.

* acinclude.m4 (GUILE_THREAD_LOCAL_STORAGE): Do not use thread-local
  storage on OS X. This causes (current-thread) to return the wrong
  value (tested under clang as bundled with Xcode 6.1), which causes
  srfi-18.test to fail.
---
 acinclude.m4 | 7 ++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/acinclude.m4 b/acinclude.m4
index 8ef6e99..8eba3e1 100644
--- a/acinclude.m4
+++ b/acinclude.m4
@@ -380,8 +380,13 @@ AC_DEFUN([GUILE_THREAD_LOCAL_STORAGE], [
  dnl On `x86_64-unknown-freebsd8.0', thread-local storage appears to
  dnl be reclaimed at the wrong time, leading to a segfault when
  dnl running `threads.test'.  So disable it.
+ dnl
+ dnl On `x86_64-apple-darwin14.0.0', thread-local storage appears to
+ dnl return the wrong value for `scm_i_current_thread', resulting in
+ dnl (current-thread) returning the wrong value. This then causes
+ dnl `srfi-18.test' to fail.
  case $enable_shared--$host_os in
-   [yes--netbsd[0-5].[0-9]*|yes--solaris2.8|yes--freebsd[0-8]*])
+   [yes--netbsd[0-5].[0-9]*|yes--solaris2.8|yes--freebsd[0-8]*|yes--darwin*])
  ac_cv_have_thread_storage_class=no
  ;;
*)
-- 
1.9.3 (Apple Git-50)



Mutable top-level bindings (was: vectors are something else)

2013-04-17 Thread Chris K. Jester-Young
On Mon, Apr 15, 2013 at 10:00:55PM -0400, Mark H Weaver wrote:
 Unfortunately, this is rarely possible in a language like Scheme, where
 calls to procedures bound by mutable top-level variables are frequent.
 We cannot fix this without making most commonly-used top-level bindings
 immutable.  Last I checked, there was strong resistance to this idea.

Maybe it's time to reopen this (and hope it's not a can of worms). :-)

With a proper module system, I don't see why top-level bindings should
be mutable. That would make even things like direct inlining of cons or
+ somewhat harder than it needs to be. The way I understand it, the
definition of (@ (guile) cons) or the like should not be subject to
change at runtime. If people want to change the behaviour of cons, write
a module that replaces the top-level binding.

Yes, this does disable the ability to perform monkey-patching. I don't
see this as a big loss, but perhaps there are legitimate use cases for
monkey-patching that I haven't thought of.

Another thing we will need to provide is define-values, which allows you
to make top-level bindings that are mutually-recursive. By which I mean:

(define-values (foo bar baz)
  (letrec ((foo ...)
   (bar ...)
   (baz ...))
(values foo bar baz)))

This would obviate the need to use the following pattern:

(define foo #f)
(define bar #f)
(define baz #f)
(letrec ((my-foo ...)
 (my-bar ...)
 (my-baz ...))
  (set! foo my-foo)
  (set! bar my-bar)
  (set! baz my-baz))

Granted, there are existing modules that use that approach currently, as
we don't currently have define-values. But I think it should be possible
to annotate individual modules as having immutable top-level bindings,
so that we can gradually migrate modules to the define-values style.

Cheers,
Chris.



Record type printers for SRFI 45 promises and SRFI 41 streams

2013-04-07 Thread Chris K. Jester-Young
Hi all,

I've attached record type printers for SRFI 45 promises and SRFI 41
streams. I've tried to make promise-visit more self-documenting with
the use of keyword arguments; let me know if you think that's an
improvement!

Also as discussed with Mark H Weaver, I've currently implemented the
format for promises as #promise = ... for unevaluated promises, and
#promise = ... for evaluated ones. Hopefully this is is easy to read
and will clearly distinguish between the two types, and still look
different from core promises too.

Comments are most welcome!

Thanks,
Chris.
---BeginMessage---
* module/srfi/srfi-45.scm: Add record type printer for promises.
  (promise-visit): New helper for visiting lazy promises.
---
 module/srfi/srfi-45.scm |   17 -
 1 files changed, 16 insertions(+), 1 deletions(-)

diff --git a/module/srfi/srfi-45.scm b/module/srfi/srfi-45.scm
index 5194770..6f7ba7e 100644
--- a/module/srfi/srfi-45.scm
+++ b/module/srfi/srfi-45.scm
@@ -39,7 +39,8 @@
  eager
  promise?)
   #:replace (delay force promise?)
-  #:use-module (srfi srfi-9))
+  #:use-module (srfi srfi-9)
+  #:use-module (srfi srfi-9 gnu))
 
 (cond-expand-provide (current-module) '(srfi-45))
 
@@ -76,3 +77,17 @@
 ;; (*) These two lines re-fetch and check the original promise in case
 ;; the first line of the let* caused it to be forced.  For an example
 ;; where this happens, see reentrancy test 3 below.
+
+(define* (promise-visit promise #:key on-eager on-lazy)
+  (define content (promise-val promise))
+  (case (value-tag content)
+((eager) (on-eager (value-proc content)))
+((lazy)  (on-lazy (value-proc content)
+
+(set-record-type-printer! promise
+  (lambda (promise port)
+(promise-visit promise
+  #:on-eager (lambda (value)
+   (format port #promise = ~s value))
+  #:on-lazy  (lambda (proc)
+   (format port #promise = ~s proc)
-- 
1.7.2.5

---End Message---
---BeginMessage---
* module/srfi/srfi-41.scm: Add record type printer for streams.
  (stream-promise-visit): New helper for visiting stream promises.
---
 module/srfi/srfi-41.scm |   23 +++
 1 files changed, 23 insertions(+), 0 deletions(-)

diff --git a/module/srfi/srfi-41.scm b/module/srfi/srfi-41.scm
index 6f73ce3..3589b35 100644
--- a/module/srfi/srfi-41.scm
+++ b/module/srfi/srfi-41.scm
@@ -27,6 +27,7 @@
   #:use-module (srfi srfi-1)
   #:use-module (srfi srfi-8)
   #:use-module (srfi srfi-9)
+  #:use-module (srfi srfi-9 gnu)
   #:use-module (srfi srfi-26)
   #:use-module (ice-9 match)
   #:export (stream-null stream-cons stream? stream-null? stream-pair?
@@ -180,6 +181,28 @@
 (define-syntax-rule (stream-lambda formals body0 body1 ...)
   (lambda formals (stream-lazy (begin body0 body1 ...
 
+(define* (stream-promise-visit promise #:key on-eager on-lazy)
+  (define content (stream-promise-val promise))
+  (case (stream-value-tag content)
+((eager) (on-eager (stream-value-proc content)))
+((lazy)  (on-lazy (stream-value-proc content)
+
+(set-record-type-printer! stream-promise
+  (lambda (strm port)
+(display #stream port)
+(let loop ((strm strm))
+  (stream-promise-visit strm
+#:on-eager (lambda (pare)
+ (cond ((eq? pare %stream-null)
+(write-char #\ port))
+   (else
+(write-char #\space port)
+(stream-promise-visit (stream-kar pare)
+  #:on-eager (cut write  port)
+  #:on-lazy  (lambda (_) (write-char #\? port)))
+(loop (stream-kdr pare)
+#:on-lazy (lambda (_) (display  ... port))
+
 ;;; Derived stream functions and macros: (streams derived)
 
 (define-syntax-rule (define-stream (name . formal) body0 body1 ...)
-- 
1.7.2.5

---End Message---


Re: [PATCH] Implement efficient 'scm_unget_bytes' and use it

2013-04-06 Thread Chris K. Jester-Young
On Sat, Apr 06, 2013 at 02:28:14AM -0400, Mark H Weaver wrote:
 This patch implements a function 'scm_unget_bytes' that enables large
 buffers to be unread efficiently.  It keeps the bytes at the end of the
 buffer instead of the beginning, but it can cope if some external code
 manipulates the pushback buffer by hand and puts the bytes at the
 beginning.

Looks good to me! I did write a comment on IRC about how the following
lines

+  if (new_len  pt-read_buf_size)
+/* The putback buffer needs to be enlarged.  */

used inconsistent references to read_buf and putback buffer, but
I don't think there's a very good solution for that, other than just
making the human reader aware that read_buf _is_ putback_buf in this
context.

Cheers,
Chris.



Re: regexp-split for Guile

2012-10-21 Thread Chris K. Jester-Young
On Sat, Oct 20, 2012 at 10:16:49AM -0400, Mark H Weaver wrote:
 Sorry, that last example is wrong of course, but both of these examples
 raise an interesting question about how #:limit and #:trim should
 interact.  To my mind, the top example above is correct.  I think the
 last result should be baz, not baz  .
[...]
 Honestly, this question makes me wonder if the proposed 'regexp-split'
 is too complicated.  If you want to trim whitespace, how about using
 'string-trim-right' or 'string-trim-both' before splitting?  It seems
 more likely to do what I would expect.

Thanks so much for your feedback, Mark! I appreciate it.

Yeah, I think given the left-to-right nature of regex matching, the
only kind of trimming that makes sense is a right trim. And then once
you do that, people start asking for left trim, and mayhem begins. ;-)

I do want to consider the string pre-trimming approach, as it's more
clear what's going on, and is less magical (where magic is a plus
in the Perl world, and not so much of a plus in other languages).

Thankfully, the string-trim{,-right,-both} functions you mentioned use
substring behind the scenes, which uses copy-on-write. So that solves
one of my potential concerns, which is that a pre-trim would require
copying most of the string.

*   *   *

Granted, if you want trimming-with-complicated-regex-delimiter, and
not just whitespace, then your best bet is to trim the output list.
This is slightly more complicated, because my original code simply
uses drop-while before reversing the output list for return, but since
the caller doesn't receive the reversed list, they either have to
reverse+trim+reverse (yuck), or we have to implement drop-right-while
(like you mentioned previously).

In that regard, here's one implementation of drop-right-while (that I
just wrote on the spot):

(define (drop-right-while pred lst)
  (let recur ((lst lst))
(if (null? lst) '()
(let ((elem (car lst))
  (next (recur (cdr lst
  (if (and (null? next) (pred elem)) '()
  (cons elem next))

One could theoretically write drop-right-while! also (I can think of
two different implementation strategies) but it sounds like it's more
work than it's worth.

So, that's our last hurdle: we just have to get drop-right-while
integrated into Guile, then we can separate out the splitting and
trimming processes. And everybody will be happy. :-)

Comments welcome,
Chris.



Re: regexp-split for Guile

2012-10-21 Thread Chris K. Jester-Young
On Sun, Oct 21, 2012 at 04:20:09PM +0800, Daniel Hartwig wrote:
 Yes.  Keep it simple.  Operations like trim-whitespace and
 drop-empty-strings-from-the-result (mentioned in the previous
 discussion) are so easy to do outside of regexp-split, why complicate
 the semantics?

So easy, but so verbose. We should prefer to make common use cases
easy (and succinct) to use, and not optimise for uncommon ones.

Anyway, in my response to Mark, I mentioned that if we can get
drop-right-while in-tree, we have a middle ground that should make
everyone happy. I am against requiring users of regexp-split to
reinvent that wheel each time. Leave the reinvention to Phil Bewig.[1]

Cheers,
Chris.

[1] http://lists.nongnu.org/archive/html/chicken-users/2009-05/msg00024.html
I never use SRFI-1. My personal standard library has take, drop,
 take-while, drop-while, range, iterate, filter, zip, [...]



Re: regexp-split for Guile

2012-10-19 Thread Chris K. Jester-Young
On Fri, Oct 12, 2012 at 05:57:11PM -0400, Mark H Weaver wrote:
 FWIW, I agree with Daniel.  I dislike the complicated semantics of this
 'limit' argument, which combines into a single number two different
 concepts:

First, I want to thank both Daniel and Mark for their feedback. I'm
sorry I haven't had a chance to reply until now; last weekend I went
to (and presented at) RacketCon, so I didn't have a lot of time for
replying to emails.

(And if you want to see my RacketCon presentation, feel free to visit
https://speakerdeck.com/u/cky/p/rackona :-))

 Beyond matters of taste, I don't like this because it makes bugs less
 likely to be caught.  Suppose 'limit' is a computed value, normally
 expected to be positive.  Code that follows may implicitly assume that
 the returned list has no more than 'limit' elements.  Now suppose that
 due to a bug or exceptional circumstance, the computed 'limit' ends up
 being less than 1.  Now 'regexp-split' switches to a qualitatively
 different mode of behavior.

I am sympathetic to this. It would definitely be good for the limit to
mean only that, and not have two other meanings attached to it.

So, in this spirit, below is my proposal for something that I hope would
fit within the character of your feedback, while not making the common
use cases needlessly verbose: we should favour the common use cases by
making them easy to use.

Before I begin, remember that in Perl's split, the default limit is 0,
which is to strip off all the blank trailing fields. This is the common
use case when using whitespace as a delimiter, where you simply want to
ignore all the end-of-line whitespace. Making the calling code manually
call drop-right-while is counter-productive for this common use case.

Here is my proposal:

(regexp-split pat str #:key limit (trim? (not limit)))

With no optional arguments specified (so, #:limit is #f and #:trim? is
#t), it behaves like limit == 0 in Perl. i.e., return all fields, minus
blank trailing ones.

With a #:limit specified (which must be a positive integer), return
that number of fields at most (subsequent ones are not split out, and
are returned as part of the last field, with all delimiters intact).

With #:trim? given a false value, return all fields, including blank
trailing ones. This is false by default iff #:limit is specified.

Rationale: The common use case is the most succinct version. The next
most common use case has a relatively short formulation (#:trim?).
Also, the default for #:trim? is based on common use cases depending on
whether #:limit is specified. (Trim-with-limit is not supported in Perl,
but it seemed to take more work to ban it here than just let it be.)

Examples:

(regexp-split  + foo  bar  baz  )
  = (foo bar baz)
(regexp-split  + foo  bar  baz   #:trim? #f)
  = (foo bar baz )
(regexp-split  + foo  bar  baz   #:limit 4)
  = (foo bar baz )
(regexp-split  + foo  bar  baz   #:limit 4 #:trim? #t)
  = (foo bar baz)
(regexp-split  + foo  bar  baz   #:limit 3)
  = (foo bar baz  )
(regexp-split  + foo  bar  baz   #:limit 2)
  = (foo bar  baz  )

Does that sound reasonable?

Comments welcome,
Chris.



Re: regexp-split for Guile

2012-09-18 Thread Chris K. Jester-Young
On Tue, Sep 18, 2012 at 09:06:55AM +0200, Sjoerd van Leent Privé wrote:
 It might just be me, but would it not be more sensible for scheme to
 just perform the opposite. Return the same amount of fields at most,
 but starting from the end, thus:
 
 (regexp-split : foo:bar:baz:qux: -3)
 = (foo:bar baz qux )

Unfortunately, this is not ideal to implement:

1. Regexes are inherently forward-searching only. This means that
   matches are always built up from left-to-right.

2. Thus, there is no sensible way to implement right-fold-matches,
   which is what would be required for what you're proposing. What
   would instead have to happen is that you have to do list-matches
   with no limit, then ignore the front matches. This complicates
   the code significantly.

3. It's not compatible with Perl's split limits. The appeal of the
   Perl semantics is that it's already implemented exactly the same
   way in Ruby and Java, so the learning curve is lower.

 The problem described in your second case could be solved by using a
 symbol, such as #:all, or something similar.

I'm not a fan of this. :-( Because then you'd have to add another
keyword, like #:trim, to trim off the blanks (which is what happens with
a limit of 0), and then the interface suddenly got a lot more verbose.

Wanting all the fields, or trimming blank ones, are the commonest use
cases, and people who want to use it should not be punished with having
to use a verbose syntax for it.

Thanks for your feedback! Unfortunately, it sounds like implementing it
would complicate things too much, in my opinion. :-( YMMV.

Cheers,
Chris.



Re: regexp-split for Guile

2012-09-18 Thread Chris K. Jester-Young
On Tue, Sep 18, 2012 at 08:59:33PM +0800, nalaginrut wrote:
 Anyway, if there're so many people like this nice thing, why not we add
 it (at any option of these three implementations) into ice-9?

Oh noes! This is where the bikeshedding begins. ;-)

Seriously, I do think having a regexp-split in (ice-9 regex) would be
good. The question is what interface is best. The one I presented is
a Perl-style one (as also used in Ruby and Java), which is easy to use,
easy to learn (if you come from one of those languages), and easy to
implement. So do we go with it, or do people have a better idea?

Cheers,
Chris.



Re: regexp-split for Guile

2012-09-18 Thread Chris K. Jester-Young
Here's a revised version, implementing Thien-Thi Nguyen's comments. I
added line breaks for the cons and the bottom if (I feel that the
top if is still simple enough to keep on the same line).

Cheers,
Chris.

*   *   *

(define (regexp-split-fold match prev)
  (if (zero? (match:end match)) prev
  (cons* (match:end match)
 (substring (match:string match) (car prev) (match:start match))
 (cdr prev

(define* (regexp-split pat str #:optional (limit 0))
  (let* ((result (fold-matches pat str '(0) regexp-split-fold 0
   (if (positive? limit) (1- limit) #f)))
 (final (cons (substring str (car result))
  (cdr result
(reverse (if (zero? limit)
 (drop-while string-null? final)
 final



regexp-split for Guile

2012-09-17 Thread Chris K. Jester-Young
Hi there,

I'm currently implementing regexp-split for Guile, which provides a
Perl-style split function (including correctly implementing the limit
parameter), minus the special awk-style whitespace handling (that is
used with a pattern of  , as opposed to / /, with Perl's split).

Attached is a couple of patches, to support the regexp-split function
which I'm proposing at the bottom of this message:

1. The first fixes the behaviour of fold-matches and list-matches when
   the pattern contains a ^ (identical to the patch in my last email).
2. The second adds the ability to limit the number of matches done.
   This applies on top of the first patch.

Some comments about the regexp-split implementation: the value that's
being passed to regexp-split-fold is a cons, where the car is the last
match's end position, and the cdr is the substrings so far collected.

The special check in regexp-split-fold for match-end being zero is to
emulate a specific behaviour as documented for Perl's split: Empty
leading fields are produced when there are positive-width matches at
the beginning of the string; a zero-width match at the beginning of the
string does not produce an empty field.

Below is the implementation; comments are welcome! If it all looks good,
I'll write tests and documentation, with a view to eventually putting it
into (ice-9 regex).

Thanks,
Chris.

*   *   *

(define (regexp-split-fold match prev)
  (if (zero? (match:end match)) prev
  (cons* (match:end match)
 (substring (match:string match) (car prev) (match:start match))
 (cdr prev

(define (string-empty? str)
  (zero? (string-length str)))

(define* (regexp-split pat str #:optional (limit 0))
  (let* ((result (fold-matches pat str '(0) regexp-split-fold 0
   (if (positive? limit) (1- limit) #f)))
 (final (cons (substring str (car result)) (cdr result
(reverse! (if (zero? limit) (drop-while string-empty? final) final
From da8b0cd523f6e9bf9e1d46829cccf01e3115c614 Mon Sep 17 00:00:00 2001
From: Chris K. Jester-Young cky...@gmail.com
Date: Sun, 16 Sep 2012 02:20:56 -0400
Subject: [PATCH 1/2] In fold-matches, set regexp/notbol unless matching
 string start.

* module/ice-9/regex.scm (fold-matches): Set regexp/notbol if the
  starting position is nonzero.
* test-suite/tests/regexp.test (fold-matches): Check that when
  matching /^foo/ against foofoofoofoo, only one match results.
---
 module/ice-9/regex.scm   |3 ++-
 test-suite/tests/regexp.test |9 -
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/module/ice-9/regex.scm b/module/ice-9/regex.scm
index f7b94b7..08ae2c2 100644
--- a/module/ice-9/regex.scm
+++ b/module/ice-9/regex.scm
@@ -172,8 +172,9 @@
 (let loop ((start 0)
(value init)
(abuts #f))  ; True if start abuts a previous match.
+  (define bol (if (zero? start) 0 regexp/notbol))
   (let ((m (if ( start (string-length string)) #f
-   (regexp-exec regexp string start flags
+   (regexp-exec regexp string start (logior flags bol)
 (cond
  ((not m) value)
  ((and (= (match:start m) (match:end m)) abuts)
diff --git a/test-suite/tests/regexp.test b/test-suite/tests/regexp.test
index ef59465..d549df2 100644
--- a/test-suite/tests/regexp.test
+++ b/test-suite/tests/regexp.test
@@ -132,7 +132,14 @@
(lambda (match result)
  (cons (match:substring match)
result))
-   (logior regexp/notbol regexp/noteol)
+   (logior regexp/notbol regexp/noteol
+
+  (pass-if regexp/notbol is set correctly
+(equal? '(foo)
+(fold-matches ^foo foofoofoofoo '()
+  (lambda (match result)
+(cons (match:substring match)
+  result))
 
 
 ;;;
-- 
1.7.9.5

From 147dc0d7fd9ab04d10b4f13cecf47a32c5b6c4b6 Mon Sep 17 00:00:00 2001
From: Chris K. Jester-Young cky...@gmail.com
Date: Mon, 17 Sep 2012 01:06:07 -0400
Subject: [PATCH 2/2] Add limit parameter to fold-matches and list-matches.

* doc/ref/api-regex.texi: Document new limit parameter.

* module/ice-9/regex.scm (fold-matches, list-matches): Optionally take
  a limit argument that, if specified, limits how many times the
  pattern is matched.

* test-suite/tests/regexp.test (fold-matches): Add tests for the correct
  functioning of the limit parameter.
---
 doc/ref/api-regex.texi   |   10 ++
 module/ice-9/regex.scm   |   18 ++
 test-suite/tests/regexp.test |   16 +++-
 3 files changed, 31 insertions(+), 13 deletions(-)

diff --git a/doc/ref/api-regex.texi b/doc/ref/api-regex.texi
index 082fb87..2d2243f 100644
--- a/doc/ref/api-regex.texi
+++ b/doc/ref/api-regex.texi
@@ -189,11 +189,12 @@ or @code{#f} otherwise.
 @end

Re: regexp-split for Guile

2012-09-17 Thread Chris K. Jester-Young
On Mon, Sep 17, 2012 at 09:32:14PM +0200, Thien-Thi Nguyen wrote:
(define (string-empty? str)
  (zero? (string-length str)))
 
 You can use ‘string-null?’ instead.

Ah, nice! Thanks for the pointer.

 Style nit: i find it easier to read ‘if’ expressions w/ the condition,
 then and else expressions on separate lines.  Similarly ‘cons’.  E.g.:

Right, that sounds like a good idea. It does make the code longer, and
so for simple cases of if and cons, I'd probably still keep it in
one line, but in this case you do make a very clear case with the cons
(which involves somewhat lengthier subexpressions).

 A more substantial line of questioning: What happens if ‘regexp-split’
 is called w/ negative ‘limit’?  Should that be handled in ‘regexp-split’
 or will the procs it calls DTRT?  What is TRT, anyway?  In the absence
 of explicit validation, maybe a comment here will help the non-expert.

So, basically, the Perl split's limit is used this way:

1. Positive limit: Return this many fields at most:

(regexp-split : foo:bar:baz:qux: 3)
= (foo bar baz:qux:)

2. Negative limit: Return all fields:

(regexp-split : foo:bar:baz:qux: -1)
= (foo bar baz qux )

3. Zero limit: Return all fields, after removing trailing blank fields:

(regexp-split : foo:bar:baz:qux: 0)
= (foo bar baz qux)

Because of this, the specific negative value doesn't matter; they are
all treated the same. This is why the code checks for a positive limit
and passes #f to fold-matches if it's not positive. I hope this makes
sense. :-)

Thanks so much for your feedback. I'll incorporate your comments.

Cheers,
Chris.



[PATCH] In fold-matches, set regexp/notbol unless matching string start.

2012-09-16 Thread Chris K. Jester-Young
* module/ice-9/regex.scm (fold-matches): Set regexp/notbol if the
  starting position is nonzero.
* test-suite/tests/regexp.test (fold-matches): Check that when
  matching /^foo/ against foofoofoofoo, only one match results.
---
 module/ice-9/regex.scm   |3 ++-
 test-suite/tests/regexp.test |9 -
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/module/ice-9/regex.scm b/module/ice-9/regex.scm
index f7b94b7..08ae2c2 100644
--- a/module/ice-9/regex.scm
+++ b/module/ice-9/regex.scm
@@ -172,8 +172,9 @@
 (let loop ((start 0)
(value init)
(abuts #f))  ; True if start abuts a previous match.
+  (define bol (if (zero? start) 0 regexp/notbol))
   (let ((m (if ( start (string-length string)) #f
-   (regexp-exec regexp string start flags
+   (regexp-exec regexp string start (logior flags bol)
 (cond
  ((not m) value)
  ((and (= (match:start m) (match:end m)) abuts)
diff --git a/test-suite/tests/regexp.test b/test-suite/tests/regexp.test
index ef59465..d549df2 100644
--- a/test-suite/tests/regexp.test
+++ b/test-suite/tests/regexp.test
@@ -132,7 +132,14 @@
(lambda (match result)
  (cons (match:substring match)
result))
-   (logior regexp/notbol regexp/noteol)
+   (logior regexp/notbol regexp/noteol
+
+  (pass-if regexp/notbol is set correctly
+(equal? '(foo)
+(fold-matches ^foo foofoofoofoo '()
+  (lambda (match result)
+(cons (match:substring match)
+  result))
 
 
 ;;;
-- 
1.7.9.5



Re: SRFI 41, revisited

2012-09-11 Thread Chris K. Jester-Young
On Tue, Sep 11, 2012 at 01:58:26PM +0800, Daniel Hartwig wrote:
 This is not compatible with the (ice-9 streams) module is it?  At
 least, it does not appear to be by quickly scanning the source.

Nope, the two are not related at all. As you've correctly identified,
(ice-9 streams) uses a generator, whereas SRFI 41 uses stream-cons so
that you can build streams recursively from other streams (but in a way
that doesn't bust your stack).

The magic ingredient in all of this is SRFI 45's lazy, which is not
provided by standard Scheme promises.

In so saying, SRFI 41 does provide a generator-style stream builder too,
in the form of stream-unfolds. So it shouldn't be hard to port code from
using (ice-9 streams) to SRFI 41. The other direction isn't quite so
simple. ;-)

 At the time I investigated the two alternate implementations (ice-9's
 make-stream is constructed using a generator) and found that depending
 on the use case either approach could be more efficient in terms of
 coding and run-time performance.  So at least having the two options
 is great.

Yes, I think both libraries have a place; although SRFI 41 can do
everything (ice-9 streams) can do, it's also somewhat more complicated,
and sometimes all you need is something quick and easy.

 I wonder if there is an underlying base which is common to both
 methods…  Such a base is great if ice-9 streams were extended with the
 useful procedures as well (stream-filter, stream-ref, etc.).

I don't think there is a common base, since a lot of SRFI 41's utility
functions do make use of stream-cons. But you can reimplement them for
(ice-9 streams) in order to provide the same API. Then code can more
easily switch between the two implementations without requiring too much
source changes.

 Anyway, looks quite good and I'll play more with this module during the week.

Sounds good. Thanks!

Cheers,
Chris.



Re: things are eq? but not generated at the same time

2012-09-11 Thread Chris K. Jester-Young
On Wed, Sep 05, 2012 at 08:24:58PM +0100, Ian Price wrote:
 I, of course, meant vector literals, but a quick test shows this is not
 the case. 

Literals are always immutable, and trying to modify them is nasal demon
stuff. Of course, R6RS says implementations should raise an exception
when an attempt is made to modify an immutable object, so perhaps that
is something we should consider.

Related: http://stackoverflow.com/a/12332939/13

Cheers,
Chris.



SRFI 41, revisited

2012-09-10 Thread Chris K. Jester-Young
It's been over half a year since I last wrote about SRFI 41; two whole
releases have happened since then. I'm pretty sure I don't want to wait
for another. ;-)

Thanks to Andy and Ludovic for all the feedback last time; I think I've
implemented all the feedback, so let's get this thing across the finish
line! I just updated the srfi-41 branch with a merge of v2.0.6, and ran
the tests (which passed with no changes to the code).

So, a final review would be highly appreciated.

One thing that is still missing is the documentation. I believe Ludovic
mentioned that this can be lifted straight from the SRFI specification
if need be. (I do hope to write something more original, even if only as
a later thing. But let's not let that hold up making srfi-41 available!)

Cheers,
Chris.



Re: SRFI 41 for Guile

2012-01-27 Thread Chris K. Jester-Young
Hi Andy,

On Sat, Jan 07, 2012 at 01:47:29AM +0100, Andy Wingo wrote:
 Cky!  Clearly I should have finished ploughing through guile-devel
 before we had the pleaseure of meeting up last week.  Because if I had,
 I would have asked you to deliver two files: srfi-41.scm, and
 srfi-41.test :-)

Wow, I must have fallen off the edge of the world for the last 3+ weeks,
as I'm only just (vaguely) catching up with the list now. ;-) I haven't
forgotten about this. While I can't promise for it to be completed this
weekend, I will work on this as I find time to.

It was good meeting up! Hopefully we'll get another chance to do so. :-)

Cheers,
Chris.



Re: when and unless

2011-12-08 Thread Chris K. Jester-Young
On Thu, Dec 08, 2011 at 09:42:36AM +0100, David Kastrup wrote:
 So here is another proposal: (values) is not the same as *unspecified*.
 But if you take the first value of a values list in single-value
 contexts, there is nothing about that coercion mechanism that would keep
 you from using *unspecified* whenever that values list would be empty.

That's easy to implement (patch at bottom of post; I tested it). The
question for the people on the list to decide is whether it's a good
idea. :-) Personally, I don't object to it, but, perhaps others do.

Cheers,
Chris.

*   *   *

diff --git a/libguile/vm-i-system.c b/libguile/vm-i-system.c
index 474fe78..6ce5ee3 100644
--- a/libguile/vm-i-system.c
+++ b/libguile/vm-i-system.c
@@ -1311,7 +1311,7 @@ VM_DEFINE_INSTRUCTION (68, return_values, 
return/values, 1, -1, -1)
   /* Finally null the end of the stack */
   NULLSTACK (vals + nvalues - sp);
 }
-  else if (nvalues = 1)
+  else
 {
   /* Multiple values for a single-valued continuation -- here's where I
  break with guile tradition and try and do something sensible. (Also,
@@ -1324,13 +1324,11 @@ VM_DEFINE_INSTRUCTION (68, return_values, 
return/values, 1, -1, -1)
   fp = SCM_FRAME_DYNAMIC_LINK (fp);
 
   /* Push first value */
-  *++sp = vals[1];
+  *++sp = nvalues = 1 ? vals[1] : SCM_UNSPECIFIED;
  
   /* Finally null the end of the stack */
   NULLSTACK (vals + nvalues - sp);
 }
-  else
-goto vm_error_no_values;
 
   /* Restore the last program */
   program = SCM_FRAME_PROGRAM (fp);



Re: impressions on gc

2011-12-08 Thread Chris K. Jester-Young
On Fri, Dec 02, 2011 at 12:09:12AM +0100, Andy Wingo wrote:
 One change was to make GC run more often when a process is growing, in
 terms of resident memory size.  This seems to be a good idea in general.
 
 The other was to add a function that users can call to note
 non-gc-managed allocations -- allocations that may be freed when GC is
 run, but which the GC doesn't know about.  That is
 scm_gc_register_allocation.  This routine runs GC after allocated bytes
 exceed some limit, currently the GC-managed heap size, reset after every
 GC.  This is to catch steady-state mallocation.

I looked at the change for it, fd51e66190bde8cef74fec9725de4da3471901c4.
It looks cool. :-)

Alas, part of that diff also breaks libgc 7.1 (which is the version that
Debian currently has packaged), which lack the unmapping functions.
Here's my diff to make it work again.

Many thanks,
Chris.

*   *   *

diff --git a/configure.ac b/configure.ac
index d63dd63..0cfe961 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1259,7 +1259,7 @@ save_LIBS=$LIBS
 LIBS=$BDW_GC_LIBS $LIBS
 CFLAGS=$BDW_GC_CFLAGS $CFLAGS
 
-AC_CHECK_FUNCS([GC_do_blocking GC_call_with_gc_active GC_pthread_exit 
GC_pthread_cancel GC_allow_register_threads GC_pthread_sigmask 
GC_set_start_callback GC_get_heap_usage_safe GC_get_free_space_divisor])
+AC_CHECK_FUNCS([GC_do_blocking GC_call_with_gc_active GC_pthread_exit 
GC_pthread_cancel GC_allow_register_threads GC_pthread_sigmask 
GC_set_start_callback GC_get_heap_usage_safe GC_get_free_space_divisor 
GC_gcollect_and_unmap GC_get_unmapped_bytes])
 
 # Though the `GC_do_blocking ()' symbol is present in GC 7.1, it is not
 # declared, and has a different type (returning void instead of
diff --git a/libguile/gc-malloc.c b/libguile/gc-malloc.c
index 72142ca..b7781f3 100644
--- a/libguile/gc-malloc.c
+++ b/libguile/gc-malloc.c
@@ -96,7 +96,11 @@ scm_realloc (void *mem, size_t size)
 return ptr;
 
   /* Time is hard: trigger a full, ``stop-the-world'' GC, and try again.  */
+#ifdef HAVE_GC_GCOLLECT_AND_UNMAP
   GC_gcollect_and_unmap ();
+#else
+  GC_gcollect ();
+#endif
 
   SCM_SYSCALL (ptr = realloc (mem, size));
   if (ptr)
diff --git a/libguile/gc.c b/libguile/gc.c
index ff1ebe6..0ab27a5 100644
--- a/libguile/gc.c
+++ b/libguile/gc.c
@@ -205,7 +205,11 @@ GC_get_heap_usage_safe (GC_word *pheap_size, GC_word 
*pfree_bytes,
 {
   *pheap_size = GC_get_heap_size ();
   *pfree_bytes = GC_get_free_bytes ();
+#ifdef HAVE_GC_GET_UNMAPPED_BYTES
   *punmapped_bytes = GC_get_unmapped_bytes ();
+#else
+  *punmapped_bytes = 0;
+#endif
   *pbytes_since_gc = GC_get_bytes_since_gc ();
   *ptotal_bytes = GC_get_total_bytes ();
 }



Re: when and unless

2011-12-06 Thread Chris K. Jester-Young
On Tue, Dec 06, 2011 at 08:48:01AM +0100, Marijn wrote:
 Couldn't help but wonder why they don't return the value of the last
 body form, so I looked around a bit and both CLHS[1] and my racket
 REPL seem to agree that they should:
[...]
 Is there some other source that suggests that the return value should
 be unspecified?

This isn't so much because the return value is somehow specified or
useful, but rather to avoid breaking tail position. See this discussion
I had with Eli Barzilay where this is explained:

http://rotty.yi.org/irclogs/freenode/%23scheme/2011-11-02/#e208

(Start at the 07:24 timestamp if the fragment reference isn't working.)

Cheers,
Chris.



SRFI 41 for Guile

2011-12-06 Thread Chris K. Jester-Young
Hi all,

Just writing to say that after many months of being busy with other
stuff, I finally got around to finishing my Guile port of SRFI 41:

https://github.com/cky/guile2-modules

Basically, both the code and the tests are based on the reference
implementation, albeit with somewhat significant changes (as Andreas
Rottmann pointed out ;-)) to make better use of Guile's features:

+ The tests use Guile's (test-suite lib) test framework.

+ define*/lambda* is used for handling optional arguments, rather than
  manual argument unpacking. In the odd case of stream-list where the
  optional argument is the leftmost one, I used case-lambda instead.

+ Guile's SRFI 45 is used directly, rather than reimplemented as in the
  reference implementation.

+ stream-match and stream-unfolds are complete rewrites. stream-match
  uses (ice-9 match), and stream-unfolds uses (ice-9 q) to store the
  unread results.

+ stream-constant uses circular-list to hold the values of interest,
  rather than...whatever the reference implementation does with append
  (see for yourself, if you're curious ;-)).

The long and short is that whatever functionality is covered by an
existing Guile module or builtin feature, I tried to make the best use
of it. Still, I don't know every Guile module there is, so if I missed
something, please let me know!

Before anyone asks, though, I can't use (ice-9 streams)---it works on
a very different streaming model from SRFI 41, as explained in the
latter's introduction.

Comments are very welcome. :-)

Enjoy!
Chris.



Re: when and unless

2011-12-06 Thread Chris K. Jester-Young
On Tue, Dec 06, 2011 at 11:08:08PM +0100, David Kastrup wrote:
  Have you considered using `(values)' as your way of saying, I'm not
  returning any values?
 
 Testing for that is not all that much fun.  It is also rather useless
 since pretty much all of the call-for-effect functions of Guile return
 *unspecified* rather than (values).

You're not really supposed to test for it. In fact, if you don't try to
use the value of when, unless, or one-armed ifs, you'll do just fine in
general.

 It is not clear to me why (values) can't just evaluate to a single
 *unspecified* just like '() evaluates to null.  Outside of
 call-with-values, I don't see much need to treat it special.

Implementing that would pretty much either require CPS transforms all
around (then you'd look at the arity of the continuation), or else
you'd have to be keeping track of the arity of the current continuation
some other way. Is it just me, or does that smell like Perl's wantarray?

Which brings me to a bigger question---do we even want anything like
wantarray? It seems so insanely hacky (to me), even in Perl code.

Just my humble opinion,
Chris.



SRFI 9's default printer doesn't handle cyclic data structures

2011-07-25 Thread Chris K. Jester-Young
[Crossposted from bug-guile@ since my message isn't posting there. :-(]

Hi there,

I've been playing around with Guile's implementation of SRFI 45 (which
uses SRFI 9), and have noticed something interesting: if you run the
following code in the REPL, printing out the value of the promise will
cause a stack overflow:

(use-modules (srfi srfi-45))
(define promise (delay promise))
(force promise)

#promise val: module/ice-9/format.scm:38:0: In procedure format:
module/ice-9/format.scm:38:0: Throw to key `vm-error' with args `(vm-run 
VM: Stack overflow ())'.

However, if I change the SRFI 45 code to use Guile's native records,
it prints correctly:

#promise val: #value tag: eager proc: #-1#

For reproducibility, I attached the diff to make SRFI 45 use Guile
native records.

So, it seems like SRFI 9's record printer doesn't handle cycles in the
record data very well. Unfortunately I don't know how to fix this (I
tried looking at the printer for Guile's native records, but couldn't
figure out what made it special enough to handle cycles correctly), so
no fix is attached.

Many thanks,
Chris.
--- module/srfi/srfi-45.scm	2011-02-08 22:38:34.0 -0500
+++ module/srfi/srfi-45.scm	2011-07-23 20:24:51.0 -0400
@@ -37,15 +37,21 @@
  lazy
  force
  eager)
-  #:replace (delay force)
-  #:use-module (srfi srfi-9))
+  #:replace (delay force))
 
-(define-record-type promise (make-promise val) promise?
-  (val promise-val promise-val-set!))
+(define promise (make-record-type promise '(val)))
+(define make-promise (record-constructor promise))
+(define promise? (record-predicate promise))
+(define promise-val (record-accessor promise 'val))
+(define promise-val-set! (record-modifier promise 'val))
 
-(define-record-type value (make-value tag proc) value?
-  (tag value-tag value-tag-set!)
-  (proc value-proc value-proc-set!))
+(define value (make-record-type value '(tag proc)))
+(define make-value (record-constructor value))
+(define value? (record-predicate value))
+(define value-tag (record-accessor value 'tag))
+(define value-tag-set! (record-modifier value 'tag))
+(define value-proc (record-accessor value 'proc))
+(define value-proc-set! (record-modifier value 'proc))
 
 (define-syntax lazy
   (syntax-rules ()


Patch to add (define-syntax (foo bar) ...) support

2011-07-03 Thread Chris K. Jester-Young
Hi there,

When writing syntax-case macros, often one would write:

(define-syntax foo
  (lambda (bar)
(syntax-case bar ...)))

This seems overly long-winded; it would be preferable to be able to
write, instead:

(define-syntax (foo bar)
  (syntax-case bar ...))

Attached is a patch that implements that. Note that there is nothing
original in this patch---it's just a straight copy-and-paste of the
define version immediately above, except changing define-form to
define-syntax-form---so there should be nothing controversial from a
correctness and/or copyright point of view.

Let me know what you think.

Many thanks,
Chris.
diff --git a/module/ice-9/psyntax.scm b/module/ice-9/psyntax.scm
index 957a526..e83b3ff 100644
--- a/module/ice-9/psyntax.scm
+++ b/module/ice-9/psyntax.scm
@@ -1168,7 +1168,16 @@
  ((_ name val)
   (id? #'name)
   (values 'define-syntax-form #'name
-  #'val w s mod
+  #'val w s mod))
+ ((_ (name . args) e1 e2 ...)
+  (and (id? #'name)
+   (valid-bound-ids? (lambda-var-list #'args)))
+  ;; need lambda here...
+  (values 'define-syntax-form (wrap #'name w mod)
+  (decorate-source
+   (cons #'lambda (wrap #'(args e1 e2 ...) w mod))
+   s)
+  empty-wrap s mod
   (else
(values 'call #f e w s mod)))
  ((syntax-object? e)


Re: Patch to add (define-syntax (foo bar) ...) support

2011-07-03 Thread Chris K. Jester-Young
On Sun, Jul 03, 2011 at 04:44:46PM -0400, Noah Lavine wrote:
 I agree that this is much shorter, but I'm worried about defining the
 short syntax in a way that forces you to choose between syntax-rules
 and syntax-case.

Except, it doesn't. My version doesn't insert either syntax-case or
syntax-rules; it just inserts the lambda and lets you do whatever.

Granted, in practice that makes the shortcut useful for syntax-case
only, but at least it's highly consistent with how define's shortcut
works, and should therefore be less confusing.

  What I mean is that you could just as easily have
 
 (define-syntax (foo bar)
   ...)
 
 expand to
 
 (define-syntax foo
   (syntax-rules ()
 ((_ bar) ...)))

Racket resolves this by having a macro called define-syntax-rule, which
allows you to define a one-branch syntax-rules macro. Thus these two
macros are identical:

(define-syntax-rule (foo bar baz) (...))

(define-syntax foo
  (syntax-rules ()
((_ bar baz) (...

 It seems to me that this makes a somewhat arbitrary choice, which
 isn't great. I'd rather see some way to unify the two possibilities,
 but I don't know what that would be. There's also the possibility of
 making it expand to
 
 (define-syntax foo
   (syntax-case tmp ...
 ((bar) ...)))
 
 because it is more analogous to how regular procedures work.

The problem with this is that this then favours the one-branch variant,
which is not a common case for syntax-case macros.

Cheers,
Chris.