bug#26058: utf16->string and utf32->string don't conform to R6RS
Andy Wingo writes: > Adopting the behavior is more or less fine. If it can be done while > relying on the existing behavior, that is better than something ad-hoc > in a module. You mean somehow leveraging the existing BOM handling code of Guile (found in the ports code) would be preferable to reimplementing it like in this patch, correct? In that light, I had this attempt: (define r6rs-utf16->string (case-lambda ((bv default-endianness) (let* ((binary-port (open-bytevector-input-port bv)) (transcoder (make-transcoder (utf-16-codec))) (utf16-port (transcoded-port binary-port transcoder))) ;; XXX how to set default-endianness for a port? (get-string-all utf16-port))) ((bv endianness endianness-mandatory?) (if endianness-mandatory? (utf16->string bv endianness) (r6rs-utf16->string bv endianness) As commented in the first branch of the case-lambda, this does not yet make use of the 'default-endianness' parameter to tell the port transcoder (or whoever) what to do in case no BOM is found in the stream. >From what I can tell, Guile is currently hardcoded to *transparently* default to big-endian in ports.c, port_clear_stream_start_for_bom_read. Is there a way to detect when Guile was unable to find a BOM? (In that case one could set the endianness explicitly to the desired default.) Or do you see another way to implement this? Thanks for the feedback! Taylan P.S.: Huge congrats on the big release. :-)
bug#26058: utf16->string and utf32->string don't conform to R6RS
Andy Wingo writes: > On Mon 13 Mar 2017 19:10, taylanbayi...@gmail.com (Taylan Ulrich > "Bayırlı/Kammer") writes: > >> If I do binary I/O, the following situations are possible: >> >> 1. I'm guaranteed to get any possible bytes that happen to form a valid >>BOM at the start of the stream as-is in the returned bytevector; the >>binary I/O interface doesn't see such bytes as anything special, as >>it could simply be coincidence that the stream starts with such >>bytes. > > (1). But I thought this bug was about using a bytevector as a source > and then doing textual I/O on it, no? I have a feeling we're somehow talking past each other. :-) As far as I'm concerned, the bug is just that the procedures don't conform to the specification. It would of course be good if the behavior of these procedures was somehow in harmony with the behavior of I/O operations, but I don't see any issues arising from adopting the R6RS behavior of the procedures utf16->string and utf32->string. Do you? Taylan
bug#26058: utf16->string and utf32->string don't conform to R6RS
Andy Wingo writes: > Hi, > > this is a tricky area that is not so amenable to quick patches :) Have > you looked into what Guile already does for byte-order marks? Can you > explain how the R6RS specification relates to this? > > https://www.gnu.org/software/guile/manual/html_node/BOM-Handling.html > > Andy Hmm, interesting. I noticed the utf{16,32}->string procedures ignoring a BOM at the start of the given bytevector, but didn't look at it from a ports perspective. TL;DR of the below though: the R6RS semantics offer a strict enrichment of the feature-set of the utfX->string procedures relative to the Guile semantics, so at most we would end up with spurious features. (The optional ability to handle any possible BOM at the start of the bytevector, with a fall-back endianness in case none is found.) That said, let's see... If I do a textual read from a port, I already get a string and not a bytevector, so the behavior of utfX->string operations is irrelevant. If I do binary I/O, the following situations are possible: 1. I'm guaranteed to get any possible bytes that happen to form a valid BOM at the start of the stream as-is in the returned bytevector; the binary I/O interface doesn't see such bytes as anything special, as it could simply be coincidence that the stream starts with such bytes. 2. I'm guaranteed *not* to get bytes that form a BOM at the start of the stream; instead they're consumed to set the port encoding for any future text I/O. 3. The behavior is unspecified and either of the above may happen. In the case of #1, it's probably good for utfX->string procedures to be able to handle BOMs, but also allow explicitly ignoring any possible BOM. The R6RS semantics cover this. In the case of #2, the utfX->string procedures don't need to be able to handle BOMs as far as we're talking about passing them bytevectors returned by port I/O, but it also doesn't hurt if they optionally support it. The R6RS semantics are fine here as well I think. As for #3... first of all it's bad IMO; the behavior ought to be specified. :-) But in any case, the additional features of the R6RS semantics won't hurt. WDYT? As far as I understand the page you linked, Guile currently implements #3, which I think is unfortunate but can kinda understand too. In any case, the additional R6RS features won't hurt, right? Taylan
bug#26059: Sorry about the duplicate.
Please ignore this, as it's a duplicate of #26058.
bug#26059: utf16->string and utf32->string don't conform to R6RS
See the R6RS Libraries document page 10. The differences: - R6RS supports reading a BOM. - R6RS mandates an endianness argument to specify the behavior at the absence of a BOM. - R6RS allows an optional third argument 'endianness-mandatory' to explicitly ignore any possible BOM. Here's a quick patch on top of master to implement the R6RS procedures in terms of the Guile procedures and export them with a rename from (rnrs bytevectors). ===File /home/taylan/src/guile/guile-master/0001-Fix-R6RS-utf16-string-and-utf32-string.patch=== >From f51cd1d4884caafb1ed0072cd77c0e3145f34576 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Taylan=20Ulrich=20Bay=C4=B1rl=C4=B1/Kammer?= Date: Fri, 10 Mar 2017 22:36:55 +0100 Subject: [PATCH] Fix R6RS utf16->string and utf32->string. * module/rnrs/bytevectors.scm (read-bom16, read-bom32): New procedures. (r6rs-utf16->string, r6rs-utf32->string): Ditto. --- module/rnrs/bytevectors.scm | 52 - 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/module/rnrs/bytevectors.scm b/module/rnrs/bytevectors.scm index 9744359f0..997a8c9cb 100644 --- a/module/rnrs/bytevectors.scm +++ b/module/rnrs/bytevectors.scm @@ -69,7 +69,9 @@ bytevector-ieee-double-native-set! string->utf8 string->utf16 string->utf32 - utf8->string utf16->string utf32->string)) + utf8->string + (r6rs-utf16->string . utf16->string) + (r6rs-utf32->string . utf32->string))) (load-extension (string-append "libguile-" (effective-version)) @@ -80,4 +82,52 @@ `(quote ,sym) (error "unsupported endianness" sym))) +(define (read-bom16 bv) + (let ((c0 (bytevector-u8-ref bv 0)) +(c1 (bytevector-u8-ref bv 1))) +(cond + ((and (= c0 #xFE) (= c1 #xFF)) + 'big) + ((and (= c0 #xFF) (= c1 #xFE)) + 'little) + (else + #f + +(define r6rs-utf16->string + (case-lambda +((bv default-endianness) + (let ((bom-endianness (read-bom16 bv))) + (if (not bom-endianness) + (utf16->string bv default-endianness) + (substring/shared (utf16->string bv bom-endianness) 1 +((bv endianness endianness-mandatory?) + (if endianness-mandatory? + (utf16->string bv endianness) + (r6rs-utf16->string bv endianness) + +(define (read-bom32 bv) + (let ((c0 (bytevector-u8-ref bv 0)) +(c1 (bytevector-u8-ref bv 1)) +(c2 (bytevector-u8-ref bv 2)) +(c3 (bytevector-u8-ref bv 3))) +(cond + ((and (= c0 #x00) (= c1 #x00) (= c2 #xFE) (= c3 #xFF)) + 'big) + ((and (= c0 #xFF) (= c1 #xFE) (= c2 #x00) (= c3 #x00)) + 'little) + (else + #f + +(define r6rs-utf32->string + (case-lambda +((bv default-endianness) + (let ((bom-endianness (read-bom32 bv))) + (if (not bom-endianness) + (utf32->string bv default-endianness) + (substring/shared (utf32->string bv bom-endianness) 1 +((bv endianness endianness-mandatory?) + (if endianness-mandatory? + (utf32->string bv endianness) + (r6rs-utf32->string bv endianness) + ;;; bytevector.scm ends here -- 2.11.0
bug#26058: utf16->string and utf32->string don't conform to R6RS
See the R6RS Libraries document page 10. The differences: - R6RS supports reading a BOM. - R6RS mandates an endianness argument to specify the behavior at the absence of a BOM. - R6RS allows an optional third argument 'endianness-mandatory' to explicitly ignore any possible BOM. Here's a quick patch on top of master. I didn't test it thoroughly... ===File /home/taylan/src/guile/guile-master/0001-Fix-R6RS-utf16-string-and-utf32-string.patch=== >From f51cd1d4884caafb1ed0072cd77c0e3145f34576 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Taylan=20Ulrich=20Bay=C4=B1rl=C4=B1/Kammer?= Date: Fri, 10 Mar 2017 22:36:55 +0100 Subject: [PATCH] Fix R6RS utf16->string and utf32->string. * module/rnrs/bytevectors.scm (read-bom16, read-bom32): New procedures. (r6rs-utf16->string, r6rs-utf32->string): Ditto. --- module/rnrs/bytevectors.scm | 52 - 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/module/rnrs/bytevectors.scm b/module/rnrs/bytevectors.scm index 9744359f0..997a8c9cb 100644 --- a/module/rnrs/bytevectors.scm +++ b/module/rnrs/bytevectors.scm @@ -69,7 +69,9 @@ bytevector-ieee-double-native-set! string->utf8 string->utf16 string->utf32 - utf8->string utf16->string utf32->string)) + utf8->string + (r6rs-utf16->string . utf16->string) + (r6rs-utf32->string . utf32->string))) (load-extension (string-append "libguile-" (effective-version)) @@ -80,4 +82,52 @@ `(quote ,sym) (error "unsupported endianness" sym))) +(define (read-bom16 bv) + (let ((c0 (bytevector-u8-ref bv 0)) +(c1 (bytevector-u8-ref bv 1))) +(cond + ((and (= c0 #xFE) (= c1 #xFF)) + 'big) + ((and (= c0 #xFF) (= c1 #xFE)) + 'little) + (else + #f + +(define r6rs-utf16->string + (case-lambda +((bv default-endianness) + (let ((bom-endianness (read-bom16 bv))) + (if (not bom-endianness) + (utf16->string bv default-endianness) + (substring/shared (utf16->string bv bom-endianness) 1 +((bv endianness endianness-mandatory?) + (if endianness-mandatory? + (utf16->string bv endianness) + (r6rs-utf16->string bv endianness) + +(define (read-bom32 bv) + (let ((c0 (bytevector-u8-ref bv 0)) +(c1 (bytevector-u8-ref bv 1)) +(c2 (bytevector-u8-ref bv 2)) +(c3 (bytevector-u8-ref bv 3))) +(cond + ((and (= c0 #x00) (= c1 #x00) (= c2 #xFE) (= c3 #xFF)) + 'big) + ((and (= c0 #xFF) (= c1 #xFE) (= c2 #x00) (= c3 #x00)) + 'little) + (else + #f + +(define r6rs-utf32->string + (case-lambda +((bv default-endianness) + (let ((bom-endianness (read-bom32 bv))) + (if (not bom-endianness) + (utf32->string bv default-endianness) + (substring/shared (utf32->string bv bom-endianness) 1 +((bv endianness endianness-mandatory?) + (if endianness-mandatory? + (utf32->string bv endianness) + (r6rs-utf32->string bv endianness) + ;;; bytevector.scm ends here -- 2.11.0
bug#21887: 'monitor' form broken
Here's a patch, tested minimally by running (par-for-each (lambda (x) (monitor (sleep 1) (display "foo\n"))) (iota 10)) on a quad-core. Previously it would print the "foo"s in groups of four with a second between each group; now it prints them one by one with a second between each, as should be. >From 08c7f4cd98c86fbb6551c7c0b6f17262c67e7b23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Taylan=20Ulrich=20Bay=C4=B1rl=C4=B1/Kammer?= Date: Sat, 25 Jun 2016 16:43:36 +0200 Subject: [PATCH] Fix 'monitor' macro. * module/ice-9/threads.scm (monitor-mutex-table) (monitor-mutex-table-mutex, monitor-mutex-with-id): New variables. (monitor): Fix it. --- module/ice-9/threads.scm | 21 ++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/module/ice-9/threads.scm b/module/ice-9/threads.scm index 9f9e1bf..14da113 100644 --- a/module/ice-9/threads.scm +++ b/module/ice-9/threads.scm @@ -85,9 +85,24 @@ (lambda () (begin e0 e1 ...)) (lambda () (unlock-mutex x) -(define-syntax-rule (monitor first rest ...) - (with-mutex (make-mutex) -first rest ...)) +(define monitor-mutex-table (make-hash-table)) + +(define monitor-mutex-table-mutex (make-mutex)) + +(define (monitor-mutex-with-id id) + (with-mutex monitor-mutex-table-mutex +(or (hashq-ref monitor-mutex-table id) +(let ((mutex (make-mutex))) + (hashq-set! monitor-mutex-table id mutex) + mutex + +(define-syntax monitor + (lambda (stx) +(syntax-case stx () + ((_ body body* ...) + (let ((id (datum->syntax #'body (gensym + #`(with-mutex (monitor-mutex-with-id '#,id) + body body* ...)) (define (par-mapper mapper cons) (lambda (proc . lists) -- 2.8.4
bug#21613: Include messes up when compiling file in load path
Ping with CC to Andy. :-)
bug#22447: (rnrs hashtables): Mutation of immutable hashtable ignored
Pinging this thread with a (very slightly) updated patch. :-) >From 7f35d515d711e255bba5a89a013d9d92034edf41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Taylan=20Ulrich=20Bay=C4=B1rl=C4=B1/Kammer?= Date: Tue, 21 Jun 2016 00:25:19 +0200 Subject: [PATCH] Hashtable-set! errors on immutable hashtable. * module/rnrs/hashtables.scm (hashtable-set!): Raise an assertion violation error when the hashtable is immutable. * test-suite/tests/r6rs-hashtables.test: Fix accordingly. --- module/rnrs/hashtables.scm| 5 +++-- test-suite/tests/r6rs-hashtables.test | 6 -- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/module/rnrs/hashtables.scm b/module/rnrs/hashtables.scm index 08f37e2..22bae7f 100644 --- a/module/rnrs/hashtables.scm +++ b/module/rnrs/hashtables.scm @@ -127,8 +127,9 @@ (define (hashtable-set! hashtable key obj) (if (r6rs:hashtable-mutable? hashtable) - (hash-table-set! (r6rs:hashtable-wrapped-table hashtable) key obj)) -*unspecified*) +(hash-table-set! (r6rs:hashtable-wrapped-table hashtable) key obj) +(assertion-violation + 'hashtable-set! "Hashtable is immutable." hashtable))) (define (hashtable-delete! hashtable key) (if (r6rs:hashtable-mutable? hashtable) diff --git a/test-suite/tests/r6rs-hashtables.test b/test-suite/tests/r6rs-hashtables.test index fbc50c9..e2cbc2a 100644 --- a/test-suite/tests/r6rs-hashtables.test +++ b/test-suite/tests/r6rs-hashtables.test @@ -20,6 +20,7 @@ (define-module (test-suite test-rnrs-hashtable) :use-module (ice-9 receive) :use-module ((rnrs hashtables) :version (6)) + :use-module ((rnrs exceptions) :version (6)) :use-module (srfi srfi-1) :use-module (test-suite lib)) @@ -130,8 +131,9 @@ (pass-if "hashtable-copy with mutability #f produces immutable copy" (let ((copied-table (hashtable-copy (make-eq-hashtable) #f))) - (hashtable-set! copied-table 'foo 1) - (not (hashtable-ref copied-table 'foo #f) + (guard (exc (else #t)) +(hashtable-set! copied-table 'foo 1) +#f (with-test-prefix "hashtable-clear!" (pass-if "hashtable-clear! removes all values from hashtable" -- 2.8.4
bug#22446: (rnrs hashtables): Hash functions of eq? and eqv? hashtables
Also pinging this thread with a (very slightly) updated patch. :-) >From 17599f6ce7ba0beb100e80455ff99af07333d871 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Taylan=20Ulrich=20Bay=C4=B1rl=C4=B1/Kammer?= Date: Tue, 21 Jun 2016 00:23:29 +0200 Subject: [PATCH] Hashtable-hash-function returns #f on eq and eqv tables. * module/rnrs/hashtables.scm (r6rs:hashtable)[type]: New field. (r6rs:hashtable-type): New procedure. * test-suite/tests/r6rs-hashtables.test: Add related tests. --- module/rnrs/hashtables.scm| 22 +++--- test-suite/tests/r6rs-hashtables.test | 6 +- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/module/rnrs/hashtables.scm b/module/rnrs/hashtables.scm index 98d2d76..08f37e2 100644 --- a/module/rnrs/hashtables.scm +++ b/module/rnrs/hashtables.scm @@ -74,8 +74,9 @@ (make-record-type-descriptor 'r6rs:hashtable #f #f #t #t '#((mutable wrapped-table) - (immutable orig-hash-function) - (immutable mutable +(immutable orig-hash-function) +(immutable mutable) +(immutable type (define hashtable? (record-predicate r6rs:hashtable)) (define make-r6rs-hashtable @@ -85,6 +86,7 @@ (define r6rs:hashtable-set-wrapped-table! (record-mutator r6rs:hashtable 0)) (define r6rs:hashtable-orig-hash-function (record-accessor r6rs:hashtable 1)) (define r6rs:hashtable-mutable? (record-accessor r6rs:hashtable 2)) + (define r6rs:hashtable-type (record-accessor r6rs:hashtable 3)) (define hashtable-mutable? r6rs:hashtable-mutable?) @@ -96,13 +98,15 @@ (make-r6rs-hashtable (if k (make-hash-table eq? hashq k) (make-hash-table eq? symbol-hash)) symbol-hash - #t)) + #t + 'eq)) (define* (make-eqv-hashtable #:optional k) (make-r6rs-hashtable (if k (make-hash-table eqv? hashv k) (make-hash-table eqv? hash-by-value)) hash-by-value - #t)) + #t + 'eqv)) (define* (make-hashtable hash-function equiv #:optional k) (let ((wrapped-hash-function (wrap-hash-function hash-function))) @@ -111,7 +115,8 @@ (make-hash-table equiv wrapped-hash-function k) (make-hash-table equiv wrapped-hash-function)) hash-function - #t))) + #t + 'custom))) (define (hashtable-size hashtable) (hash-table-size (r6rs:hashtable-wrapped-table hashtable))) @@ -143,7 +148,8 @@ (make-r6rs-hashtable (hash-table-copy (r6rs:hashtable-wrapped-table hashtable)) (r6rs:hashtable-orig-hash-function hashtable) - (and mutable #t))) + (and mutable #t) + (r6rs:hashtable-type hashtable))) (define* (hashtable-clear! hashtable #:optional k) (if (r6rs:hashtable-mutable? hashtable) @@ -178,4 +184,6 @@ (hash-table-equivalence-function (r6rs:hashtable-wrapped-table hashtable))) (define (hashtable-hash-function hashtable) -(r6rs:hashtable-orig-hash-function hashtable))) +(case (r6rs:hashtable-type hashtable) + ((eq eqv) #f) + (else (r6rs:hashtable-orig-hash-function hashtable) diff --git a/test-suite/tests/r6rs-hashtables.test b/test-suite/tests/r6rs-hashtables.test index c7812c5..fbc50c9 100644 --- a/test-suite/tests/r6rs-hashtables.test +++ b/test-suite/tests/r6rs-hashtables.test @@ -174,7 +174,11 @@ (with-test-prefix "hashtable-hash-function" (pass-if "hashtable-hash-function returns hash function" (let ((abs-hashtable (make-hashtable abs eqv?))) - (eq? (hashtable-hash-function abs-hashtable) abs + (eq? (hashtable-hash-function abs-hashtable) abs))) + (pass-if "hashtable-hash-function returns #f on eq table" +(eq? #f (hashtable-hash-function (make-eq-hashtable + (pass-if "hashtable-hash-function returns #f on eqv table" +(eq? #f (hashtable-hash-function (make-eqv-hashtable) (with-test-prefix "hashtable-mutable?" (pass-if "hashtable-mutable? is #t on mutable hashtables" -- 2.8.4
bug#22446: (rnrs hashtables): Hash functions of eq? and eqv? hashtables
Here's a patch to fix this. >From a3e5a705aaea725fd75280a27b971d8e45e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Taylan=20Ulrich=20Bay=C4=B1rl=C4=B1/Kammer?= Date: Sun, 24 Jan 2016 12:23:34 +0100 Subject: [PATCH] Hashtable-hash-function returns #f on eq and eqv tables. * module/rnrs/hashtables.scm (r6rs:hashtable)[type]: New field. (r6rs:hashtable-type): New procedure. --- module/rnrs/hashtables.scm| 22 +++--- test-suite/tests/r6rs-hashtables.test | 6 +- 2 files changed, 20 insertions(+), 8 deletions(-) diff --git a/module/rnrs/hashtables.scm b/module/rnrs/hashtables.scm index 5773eb1..22bae7f 100644 --- a/module/rnrs/hashtables.scm +++ b/module/rnrs/hashtables.scm @@ -74,8 +74,9 @@ (make-record-type-descriptor 'r6rs:hashtable #f #f #t #t '#((mutable wrapped-table) - (immutable orig-hash-function) - (immutable mutable +(immutable orig-hash-function) +(immutable mutable) +(immutable type (define hashtable? (record-predicate r6rs:hashtable)) (define make-r6rs-hashtable @@ -85,6 +86,7 @@ (define r6rs:hashtable-set-wrapped-table! (record-mutator r6rs:hashtable 0)) (define r6rs:hashtable-orig-hash-function (record-accessor r6rs:hashtable 1)) (define r6rs:hashtable-mutable? (record-accessor r6rs:hashtable 2)) + (define r6rs:hashtable-type (record-accessor r6rs:hashtable 3)) (define hashtable-mutable? r6rs:hashtable-mutable?) @@ -96,13 +98,15 @@ (make-r6rs-hashtable (if k (make-hash-table eq? hashq k) (make-hash-table eq? symbol-hash)) symbol-hash - #t)) + #t + 'eq)) (define* (make-eqv-hashtable #:optional k) (make-r6rs-hashtable (if k (make-hash-table eqv? hashv k) (make-hash-table eqv? hash-by-value)) hash-by-value - #t)) + #t + 'eqv)) (define* (make-hashtable hash-function equiv #:optional k) (let ((wrapped-hash-function (wrap-hash-function hash-function))) @@ -111,7 +115,8 @@ (make-hash-table equiv wrapped-hash-function k) (make-hash-table equiv wrapped-hash-function)) hash-function - #t))) + #t + 'custom))) (define (hashtable-size hashtable) (hash-table-size (r6rs:hashtable-wrapped-table hashtable))) @@ -144,7 +149,8 @@ (make-r6rs-hashtable (hash-table-copy (r6rs:hashtable-wrapped-table hashtable)) (r6rs:hashtable-orig-hash-function hashtable) - (and mutable #t))) + (and mutable #t) + (r6rs:hashtable-type hashtable))) (define* (hashtable-clear! hashtable #:optional k) (if (r6rs:hashtable-mutable? hashtable) @@ -179,4 +185,6 @@ (hash-table-equivalence-function (r6rs:hashtable-wrapped-table hashtable))) (define (hashtable-hash-function hashtable) -(r6rs:hashtable-orig-hash-function hashtable))) +(case (r6rs:hashtable-type hashtable) + ((eq eqv) #f) + (else (r6rs:hashtable-orig-hash-function hashtable) diff --git a/test-suite/tests/r6rs-hashtables.test b/test-suite/tests/r6rs-hashtables.test index dbf6859..5c48579 100644 --- a/test-suite/tests/r6rs-hashtables.test +++ b/test-suite/tests/r6rs-hashtables.test @@ -176,7 +176,11 @@ (with-test-prefix "hashtable-hash-function" (pass-if "hashtable-hash-function returns hash function" (let ((abs-hashtable (make-hashtable abs eqv?))) - (eq? (hashtable-hash-function abs-hashtable) abs + (eq? (hashtable-hash-function abs-hashtable) abs))) + (pass-if "hashtable-hash-function returns #f on eq table" +(eq? #f (hashtable-hash-function (make-eq-hashtable + (pass-if "hashtable-hash-function returns hash function" +(eq? #f (hashtable-hash-function (make-eqv-hashtable) (with-test-prefix "hashtable-mutable?" (pass-if "hashtable-mutable? is #t on mutable hashtables" -- 2.6.3
bug#22447: (rnrs hashtables): Mutation of immutable hashtable ignored
I forgot to change the test suite accordingly. Here's an updated patch. >From 7483d98cf1e5439ac62ee8da3e216a413853b40c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Taylan=20Ulrich=20Bay=C4=B1rl=C4=B1/Kammer?= Date: Sat, 23 Jan 2016 22:35:24 +0100 Subject: [PATCH 1/2] Hashtable-set! errors on immutable hashtable. * module/rnrs/hashtables.scm (hashtable-set!): Raise an assertion violation error when the hashtable is immutable. --- module/rnrs/hashtables.scm| 5 +++-- test-suite/tests/r6rs-hashtables.test | 6 -- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/module/rnrs/hashtables.scm b/module/rnrs/hashtables.scm index 98d2d76..5773eb1 100644 --- a/module/rnrs/hashtables.scm +++ b/module/rnrs/hashtables.scm @@ -122,8 +122,9 @@ (define (hashtable-set! hashtable key obj) (if (r6rs:hashtable-mutable? hashtable) - (hash-table-set! (r6rs:hashtable-wrapped-table hashtable) key obj)) -*unspecified*) +(hash-table-set! (r6rs:hashtable-wrapped-table hashtable) key obj) +(assertion-violation + 'hashtable-set! "Hashtable is immutable." hashtable))) (define (hashtable-delete! hashtable key) (if (r6rs:hashtable-mutable? hashtable) diff --git a/test-suite/tests/r6rs-hashtables.test b/test-suite/tests/r6rs-hashtables.test index c7812c5..dbf6859 100644 --- a/test-suite/tests/r6rs-hashtables.test +++ b/test-suite/tests/r6rs-hashtables.test @@ -20,6 +20,7 @@ (define-module (test-suite test-rnrs-hashtable) :use-module (ice-9 receive) :use-module ((rnrs hashtables) :version (6)) + :use-module ((rnrs exceptions) :version (6)) :use-module (srfi srfi-1) :use-module (test-suite lib)) @@ -130,8 +131,9 @@ (pass-if "hashtable-copy with mutability #f produces immutable copy" (let ((copied-table (hashtable-copy (make-eq-hashtable) #f))) - (hashtable-set! copied-table 'foo 1) - (not (hashtable-ref copied-table 'foo #f) + (guard (exc (else #t)) +(hashtable-set! copied-table 'foo 1) +#f (with-test-prefix "hashtable-clear!" (pass-if "hashtable-clear! removes all values from hashtable" -- 2.6.3
bug#22447: (rnrs hashtables): Mutation of immutable hashtable ignored
Sorry about the duplicate bug report; I merged it into this one. Here's the patch again. (Merged report seemed invisible in the web interface.) >From dd6c4bbbe85a57fcbb08bdc7847075bddc1f0d87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Taylan=20Ulrich=20Bay=C4=B1rl=C4=B1/Kammer?= Date: Sat, 23 Jan 2016 22:35:24 +0100 Subject: [PATCH] Hashtable-set! errors on immutable hashtable. * module/rnrs/hashtables.scm (hashtable-set!): Raise an assertion violation error when the hashtable is immutable. --- module/rnrs/hashtables.scm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/module/rnrs/hashtables.scm b/module/rnrs/hashtables.scm index 98d2d76..5773eb1 100644 --- a/module/rnrs/hashtables.scm +++ b/module/rnrs/hashtables.scm @@ -122,8 +122,9 @@ (define (hashtable-set! hashtable key obj) (if (r6rs:hashtable-mutable? hashtable) - (hash-table-set! (r6rs:hashtable-wrapped-table hashtable) key obj)) -*unspecified*) +(hash-table-set! (r6rs:hashtable-wrapped-table hashtable) key obj) +(assertion-violation + 'hashtable-set! "Hashtable is immutable." hashtable))) (define (hashtable-delete! hashtable key) (if (r6rs:hashtable-mutable? hashtable) -- 2.6.3
bug#22449: (rnrs hashtables): Mutation of immutable hashtable ignored
I couldn't find explicit wording in R6RS on what should happen, but I would generally expect an attempt to mutate an immutable object to raise an error. In Guile, (hashtable-set! (hashtable-copy (make-eq-hashtable)) 'foo 'bar) is silently ignored. Attached is a simple patch that raises an assertion violation when the hashtable is immutable. Taylan ===File /home/taylan/src/guile/guile-stable-2.0/0001-Hashtable-set-errors-on-immutable-hashtable.patch=== >From dd6c4bbbe85a57fcbb08bdc7847075bddc1f0d87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Taylan=20Ulrich=20Bay=C4=B1rl=C4=B1/Kammer?= Date: Sat, 23 Jan 2016 22:35:24 +0100 Subject: [PATCH] Hashtable-set! errors on immutable hashtable. * module/rnrs/hashtables.scm (hashtable-set!): Raise an assertion violation error when the hashtable is immutable. --- module/rnrs/hashtables.scm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/module/rnrs/hashtables.scm b/module/rnrs/hashtables.scm index 98d2d76..5773eb1 100644 --- a/module/rnrs/hashtables.scm +++ b/module/rnrs/hashtables.scm @@ -122,8 +122,9 @@ (define (hashtable-set! hashtable key obj) (if (r6rs:hashtable-mutable? hashtable) - (hash-table-set! (r6rs:hashtable-wrapped-table hashtable) key obj)) -*unspecified*) +(hash-table-set! (r6rs:hashtable-wrapped-table hashtable) key obj) +(assertion-violation + 'hashtable-set! "Hashtable is immutable." hashtable))) (define (hashtable-delete! hashtable key) (if (r6rs:hashtable-mutable? hashtable) -- 2.6.3
bug#22447: (rnrs hashtables): Mutation of immutable hashtable ignored
I couldn't find explicit wording in R6RS on what should happen, but I would generally expect an attempt to mutate an immutable object to raise an error. In Guile, (hashtable-set! (hashtable-copy (make-eq-hashtable)) 'foo 'bar) is silently ignored. Taylan
bug#22446: (rnrs hashtables): Hash functions of eq? and eqv? hashtables
Per R6RS, the following forms should return #f: (hashtable-hash-function (make-eq-hashtable)) (hashtable-hash-function (make-eqv-hashtable)) but in Guile they return procedures. Taylan
bug#21887: 'monitor' form broken
It seems that the 'monitor' form is currently a no-op. The form (par-for-each (lambda (x) (monitor (foo))) xs) should be functionally equivalent to (let ((mutex (make-mutex))) (par-for-each (lambda (x) (with-mutex mutex (foo))) xs)) but currently becomes (par-for-each (lambda (x) (let ((mutex (make-mutex))) (with-mutex mutex (foo xs) which is ineffective. I don't know what's the best way to fix this. The simplest thing that comes to my mind is something along the lines of: (define-syntax monitor (lambda (stx) (syntax-case stx () ((_ body body* ...) (let ((uuid (generate-uuid))) #`(with-mutex (mutex-with-uuid #,uuid) body body* ...)) where mutex-with-uuid looks it up from a hash table at run-time and instantiates it when it doesn't exist, this operation also being synchronized across threads, like: (define mutex-table (make-hash-table)) (define mutex-table-mutex (make-mutex)) (define (mutex-with-uuid uuid) (with-mutex mutex-table-mutex (or (hash-ref mutex-table uuid) (let ((mutex (make-mutex))) (hash-set! mutex-table uuid mutex) mutex If that looks OK, I can try to make a proper patch from it. I'm not sure what I'd use in place of `generate-uuid' though. Would `gensym' be good enough? Shameless advertisement: with SRFI-126, the (or (hash-ref ...) ...) bit would have been just: (hashtable-intern! mutex-table uuid make-mutex) It's borrowed from MIT/GNU Scheme. Seems pretty useful. Taylan
bug#15602: Possible work-around
A possible work-around seems to be to use 'load' or 'load-compiled' on a module file after compiling it. As far as I understand, the problem is that Guile somehow ends up with a "degenerate" version of the module in the run-time after it's compiled but not fully loaded, so we alleviate that by explicitly loading it. I know near to nothing about the deeper mechanisms at play here though, so I might be off. In any case, changing guile --no-auto-compile -L . -c \ '(use-modules (system base compile)) (for-each compile-file (list "one.scm" "three.scm" "two.scm"))' to guile --no-auto-compile -L . -c \ '(use-modules (system base compile)) (for-each (lambda (file) (compile-file file) (load file)) (list "one.scm" "three.scm" "two.scm"))' alleviates the unbound variable error in this case. Related thread: https://lists.gnu.org/archive/html/guix-devel/2015-11/msg00143.html Taylan
bug#21613: Include messes up when compiling file in load path
taylanbayi...@gmail.com (Taylan Ulrich "Bayırlı/Kammer") writes: > This seems to be related to 'compile-file' setting > '%file-port-name-canonicalization' to 'relative', but I don't know > what the correct fix is. With the following trivial patch changing 'relative' to 'absolute', Guile's test suite passes and the bug seems to be fixed, but I still don't know whether this is the right fix... >From 3e508926631a6fe3d81f6a584352562afc0e96ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Taylan=20Ulrich=20Bay=C4=B1rl=C4=B1/Kammer?= Date: Mon, 5 Oct 2015 00:15:56 +0200 Subject: [PATCH] Fix 'include' for files in load path. Fixes <http://debbugs.gnu.org/21613>. * module/system/base/compile.scm (compile-file): Set %file-port-name-canonicalization to 'absolute by default. (compile-and-load): Ditto. --- module/system/base/compile.scm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module/system/base/compile.scm b/module/system/base/compile.scm index c522b74..66eec44 100644 --- a/module/system/base/compile.scm +++ b/module/system/base/compile.scm @@ -136,7 +136,7 @@ (to 'objcode) (env (default-environment from)) (opts '()) - (canonicalization 'relative)) + (canonicalization 'absolute)) (with-fluids ((%file-port-name-canonicalization canonicalization)) (let* ((comp (or output-file (compiled-file-name file) (error "failed to create path for auto-compiled file" @@ -157,7 +157,7 @@ (define* (compile-and-load file #:key (from (current-language)) (to 'value) (env (current-module)) (opts '()) - (canonicalization 'relative)) + (canonicalization 'absolute)) (with-fluids ((%file-port-name-canonicalization canonicalization)) (read-and-compile (open-input-file file) #:from from #:to to #:opts opts -- 2.5.0
bug#21613: Include messes up when compiling file in load path
When a file to be compiled, A.scm, contains (include "B.scm"), the compiler fails to find B.scm if the directory containing A and B are in Guile's load path. Here's a shell transcript showcasing the bug: --- snip --- $ mkdir test $ echo '(include "test2.scm")' > test/test1.scm $ echo '(display "foo\n")' > test/test2.scm $ pwd /home/taylan $ export GUILE_LOAD_PATH=/home/taylan/test $ unset GUILE_LOAD_COMPILED_PATH $ guile -q GNU Guile 2.0.11 Copyright (C) 1995-2014 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. scheme@(guile-user)> (compile-file "/home/taylan/test/test1.scm") ice-9/boot-9.scm:106:20: In procedure #: ice-9/boot-9.scm:106:20: In procedure open-file: No such file or directory: "./test2.scm" Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue. scheme@(#{ g269}#) [1]> --- snip --- This seems to be related to 'compile-file' setting '%file-port-name-canonicalization' to 'relative', but I don't know what the correct fix is. Taylan
bug#21379: datum->syntax chokes on lists of syntax objects
Mark H Weaver writes: > How about changing the first formal argument name to 'template-id' and > changing the words "syntax object" to "identifier"? > > Thanks! >Mark Sure, updated patch attached. Taylan >From 2ba9474dc8e2a56524d8c6c2f640fb3fb35b2d14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Taylan=20Ulrich=20Bay=C4=B1rl=C4=B1/Kammer?= Date: Sun, 30 Aug 2015 10:24:52 +0200 Subject: [PATCH] Amend datum->syntax documentation. * doc/ref/api-macros.texi (Syntax Case): Make it clear that the first argument to datum->syntax must be an identifier. --- doc/ref/api-macros.texi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/ref/api-macros.texi b/doc/ref/api-macros.texi index c2910a4..a828258 100644 --- a/doc/ref/api-macros.texi +++ b/doc/ref/api-macros.texi @@ -616,9 +616,9 @@ won't have access to the binding of @code{it}. But they can, if we explicitly introduce a binding via @code{datum->syntax}. -@deffn {Scheme Procedure} datum->syntax for-syntax datum +@deffn {Scheme Procedure} datum->syntax template-id datum Create a syntax object that wraps @var{datum}, within the lexical context -corresponding to the syntax object @var{for-syntax}. +corresponding to the identifier @var{template-id}. @end deffn For completeness, we should mention that it is possible to strip the metadata -- 2.5.0
bug#21378: R6RS guard's else chokes on multiple expressions
Please ignore this bug report, since it was my fault. I had a foreign (rnrs exceptions) library in my load-path that took precedence. Sorry about the noise. Taylan
bug#21379: datum->syntax chokes on lists of syntax objects
Apparently there's two ways to represent a list syntax object: (datum->syntax #'x '(a b c)) => #(syntax-object (a b c) ((top)) (hygiene guile-user)) i.e. a syntax object vector with a list payload, and #'(a b c) => (#(syntax-object a ((top)) (hygiene guile-user)) #(syntax-object b ((top)) (hygiene guile-user)) #(syntax-object c ((top)) (hygiene guile-user))) i.e. a list of the elements as syntax objects. Syntax-case and syntax->datum work fine with both. But when the latter form is used as the first argument to a datum->syntax call, it leads to an error: --- snip scheme@(guile-user)> (datum->syntax #'(x) '(a b c)) ice-9/psyntax.scm:467:4: In procedure datum->syntax: ice-9/psyntax.scm:467:4: In procedure vector-ref: Wrong type argument in position 1 (expecting vector): (#(syntax-object x ((top)) (hygiene guile-user))) Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue. scheme@(guile-user) [1]> --- snip I think I understand the problem: in case of a list of syntax objects, it's ambiguous which one's environment should be used for the newly created syntax object, so it requires it to be an "immediately wrapped" syntax object instead. (By the way, the psyntax sources actually call that argument 'id', hinting that perhaps it's expected to be an identifier, though the other representation works fine.) I have no clue what's the best way to solve this, but if my understanding is correct, it's a fundamental issue with datum->syntax and not a bug, so here's a documentation patch that tries to explain the limitation. >From 9578ee36ef005f0b96c1d5b120f11c178e341775 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Taylan=20Ulrich=20Bay=C4=B1rl=C4=B1/Kammer?= Date: Sun, 30 Aug 2015 10:24:52 +0200 Subject: [PATCH] Amend datum->syntax documentation. * doc/ref/api-macros.texi (Syntax Case): Mention that the first argument to datum->syntax is invalid if it's a compound syntax object, except when also created with datum->syntax. --- doc/ref/api-macros.texi | 7 ++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/doc/ref/api-macros.texi b/doc/ref/api-macros.texi index c2910a4..9c1f023 100644 --- a/doc/ref/api-macros.texi +++ b/doc/ref/api-macros.texi @@ -618,7 +618,12 @@ But they can, if we explicitly introduce a binding via @code{datum->syntax}. @deffn {Scheme Procedure} datum->syntax for-syntax datum Create a syntax object that wraps @var{datum}, within the lexical context -corresponding to the syntax object @var{for-syntax}. +corresponding to the syntax object @var{for-syntax}. @var{for-syntax} must +either be an identifier, or a syntax object that was also created with +@var{datum->syntax}; other compound syntax objects may be rejected because they +contain identifiers from different lexical contexts, in which case it would be +ambiguous which one's environment should be used for the newly created syntax +object. @end deffn For completeness, we should mention that it is possible to strip the metadata -- 2.5.0
bug#21378: R6RS guard's else chokes on multiple expressions
It seems that whatever macro tries to match the guard expression's else-clause, fails to do so when the clause contains more than one expression, and so adds a default "else re-raise" clause after the existing else clause. I couldn't figure out where this happens. I grepped the whole source tree for 're-raise' and only found it twice in a comment. Transcript showcasing bug: taylan@T420:~$ guile GNU Guile 2.0.11 Copyright (C) 1995-2014 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. scheme@(guile-user)> ,use (rnrs exceptions) scheme@(guile-user)> (guard (exc (else #f #f)) #f) While compiling expression: ERROR: Syntax error: unknown file:3:12: cond: else must be the last clause in subform (else #f #f) of (cond (else #f #f) (else (re-raise))) scheme@(guile-user)> Taylan
bug#21347: include-from-path and relative paths in load-path
When there are relative paths in the load-path, `include-from-path' seems to always interpret them relative to the directory of the file in which the `include-from-path' is called, instead of relative to the current working directory in effect when Guile is started. Transcript: --- SNIP --- taylan@T420:~$ unset GUILE_LOAD_COMPILED_PATH taylan@T420:~$ unset GUILE_LOAD_PATH taylan@T420:~$ echo '(display "foo\n")' > display.scm taylan@T420:~$ mkdir test taylan@T420:~$ echo '(include-from-path "display.scm")' > test/test.scm taylan@T420:~$ guile -q -L . GNU Guile 2.0.11 Copyright (C) 1995-2014 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. scheme@(guile-user)> (load "test/test.scm") ;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0 ;;; or pass the --no-auto-compile argument to disable. ;;; compiling /home/taylan/test/test.scm ;;; WARNING: compilation of /home/taylan/test/test.scm failed: ;;; ERROR: In procedure open-file: No such file or directory: "/home/taylan/test/./display.scm" ERROR: In procedure open-file: ERROR: In procedure open-file: No such file or directory: "/home/taylan/test/./display.scm" Entering a new prompt. Type `,bt' for a backtrace or `,q' to continue. scheme@(guile-user) [1]> --- SNIP --- Is this behavior desired? I would say not, because when passing "-L ." to guile, one expects the current directory to be added to the load path, not some symbolic "current directory" whose true value changes dynamically. (Well, I could understand if there were an explicit `chdir' call, though even then I think the "." would ideally be evaluated once at startup, if possible.) Taylan
bug#18932: string->number errors on e.g. "1e400xyz"
When string->number is given a number in scientific notation with a very high exponent, it errors with "value out of range." I don't know if that is acceptable, but what seems unacceptable is that it errors even if the string contains further characters and is thus not a valid number; R5RS says that #f should be returned when the string does not contain a syntactically valid number, and R7RS adds explicitly that string->number never signals an error due to the contents of the given string. Apparently MIT/GNU Scheme has the same bug, as reported by 'ecraven' on #scheme. From other systems I tested, Racket, Gauche, Gambit, and Chibi return +inf.0 for numbers with a too high exponent; I'm told Chicken also does so when the "numbers egg" is loaded. Taylan
bug#18914: 2.0.11 REPL server listens on 127.0.0.1 but not "localhost"
writes: > Seems to work fine on master I just built from the master branch to be sure and can still reproduce. > Maybe try strace, possibly limiting it with -e connect, to reveal what > it's actually doing. Not sure what I should be looking for, but there is no connect() call, no occurrence of "localhost" in the whole output, but the following snippet at some point: ... socket(PF_INET, SOCK_STREAM, IPPROTO_IP) = 8 fcntl(8, F_GETFL) = 0x2 (flags O_RDWR) lseek(8, 0, SEEK_CUR) = -1 ESPIPE (Illegal seek) setsockopt(8, SOL_SOCKET, SO_REUSEADDR, [1], 4) = 0 bind(8, {sa_family=AF_INET, sin_port=htons(37146), sin_addr=inet_addr("127.0.0.1")}, 16) = 0 mmap(NULL, 8720384, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK, -1, 0) = 0x7f35aaf81000 mprotect(0x7f35aaf81000, 4096, PROT_NONE) = 0 clone(child_stack=0x7f35ab7d0ff0, flags=CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD|CLONE_SYSVSEM|CLONE_SETTLS|CLONE_PARENT_SETTID|CLONE_CHILD_CLEARTID, parent_tidptr=0x7f35ab7d19d0, tls=0x7f35ab7d1700, child_tidptr=0x7f35ab7d19d0) = 2099 futex(0x7fffd27a33fc, FUTEX_WAIT_PRIVATE, 1, NULL) = 0 ... which is also the sole occurrence of '127.0.0.1'. Seems to come from `make-tcp-server-socket' in module/system/repl/server.scm where it passes INADDR_LOOPBACK, an integer whose value is 127.0.0.1 as a uint32, to bind(). I don't know at what point it's normally supposed to make the association with "localhost". Any further help in how to debug this is appreciated. I have little knowledge of the POSIX networking API. Taylan
bug#18914: 2.0.11 REPL server listens on 127.0.0.1 but not "localhost"
writes: > I wonder, could localhost be resolving to your ethernet IP address? > Or maybe resolving to an IPv6 address? tub@taylan:~$ nslookup localhost Server: 127.0.0.1 Address:127.0.0.1#53 Name: localhost Address: 127.0.0.1 tub@taylan:~$ The local DNS server is dnsmasq. > What does /etc/hosts say? tub@taylan:~$ cat /etc/hosts 127.0.0.1 localhost 127.0.1.1 taylan.uni.cx taylan # The following lines are desirable for IPv6 capable hosts ::1 localhost ip6-localhost ip6-loopback ff02::1 ip6-allnodes ff02::2 ip6-allrouters tub@taylan:~$ This is on Debian and I don't remember manually mucking with the file. Were you not able to reproduce the bug? Taylan
bug#18914: 2.0.11 REPL server listens on 127.0.0.1 but not "localhost"
After starting 'guile --listen', I can connect to it via 127.0.0.1 but not "localhost": "Ncat: Connection refused." I don't know if listening on "localhost" by default has any security implications? Shell 1: tub@taylan:~$ guile --listen GNU Guile 2.0.11 Copyright (C) 1995-2014 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. scheme@(guile-user)> Shell 2: tub@taylan:~$ ncat localhost 37146 Ncat: Connection refused. tub@taylan:~$ ncat 127.0.0.1 37146 GNU Guile 2.0.11 Copyright (C) 1995-2014 Free Software Foundation, Inc. Guile comes with ABSOLUTELY NO WARRANTY; for details type `,show w'. This program is free software, and you are welcome to redistribute it under certain conditions; type `,show c' for details. Enter `,help' for help. scheme@(guile-user)> Taylan