~ chicken-core (chicken-5) 296874e523a6bcbd157b8112d59919f0eba76b2c
commit 296874e523a6bcbd157b8112d59919f0eba76b2c Author: felix <felix@call-with-current-continuation.org> AuthorDate: Wed Sep 28 12:25:53 2011 +0200 Commit: felix <felix@call-with-current-continuation.org> CommitDate: Wed Sep 28 12:25:53 2011 +0200 push exactness check into ##sys#string->number to catch superfluous base/exactness prefixes in numbers parsing; added tests (developed in collaboration with sjamaan) Signed-off-by: felix <felix@call-with-current-continuation.org> diff --git a/library.scm b/library.scm index d84c8053..4cf975cd 100644 --- a/library.scm +++ b/library.scm @@ -1070,8 +1070,12 @@ EOF (##sys#lcm head n2) (##sys#slot next 1)) #f) ) ) ) ) ) ) -(define (##sys#string->number str #!optional (radix 10)) - (##core#inline_allocate ("C_a_i_string_to_number" 4) str radix)) +(define (##sys#string->number str #!optional (radix 10) exactness) + (let ((num (##core#inline_allocate ("C_a_i_string_to_number" 4) str radix))) + (case exactness + ((i) (##core#inline_allocate ("C_a_i_exact_to_inexact" 4) num)) + ((e) (##core#inline "C_i_inexact_to_exact" num)) + (else num)))) (define string->number ##sys#string->number) (define ##sys#number->string (##core#primitive "C_number_to_string")) @@ -2526,20 +2530,25 @@ EOF (##sys#list->vector lst) (##sys#read-error port "invalid vector syntax" lst) ) ) ) - (define (r-number radix) + (define (r-number radix exactness) (set! rat-flag #f) (let ([tok (r-token)]) - (if (string=? tok ".") - (##sys#read-error port "invalid use of `.'") - (let ([val (##sys#string->number tok (or radix 10))] ) + (cond + [(string=? tok ".") + (##sys#read-error port "invalid use of `.'")] + [(and (fx> (##sys#size tok) 0) (char=? (string-ref tok 0) #\#)) + (##sys#read-error port "unexpected prefix in number syntax" tok)] + [else + (let ([val (##sys#string->number tok (or radix 10) exactness)] ) (cond [val + ;;XXX move this into ##sys#string->number ? (when (and (##sys#inexact? val) rat-flag) (##sys#read-warning port "cannot represent exact fraction - coerced to flonum" tok) ) val] [radix (##sys#read-error port "illegal number syntax" tok)] - [else (build-symbol tok)] ) ) ) ) ) + [else (build-symbol tok)] ) ) ] ) ) ) (define (r-number-with-exactness radix) (cond [(char=? #\# (##sys#peek-char-0 port)) @@ -2547,25 +2556,25 @@ EOF (let ([c2 (##sys#read-char-0 port)]) (cond [(eof-object? c2) (##sys#read-error port "unexpected end of numeric literal")] - [(char=? c2 #\i) (##sys#exact->inexact (r-number radix))] - [(char=? c2 #\e) (##sys#inexact->exact (r-number radix))] + [(char=? c2 #\i) (r-number radix 'i)] + [(char=? c2 #\e) (r-number radix 'e)] [else (##sys#read-error port "illegal number syntax - invalid exactness prefix" c2)] ) ) ] - [else (r-number radix)] ) ) + [else (r-number radix #f)] ) ) - (define (r-number-with-radix) + (define (r-number-with-radix exactness) (cond [(char=? #\# (##sys#peek-char-0 port)) (##sys#read-char-0 port) (let ([c2 (##sys#read-char-0 port)]) (cond [(eof-object? c2) (##sys#read-error port "unexpected end of numeric literal")] - [(char=? c2 #\x) (r-number 16)] - [(char=? c2 #\d) (r-number 10)] - [(char=? c2 #\o) (r-number 8)] - [(char=? c2 #\b) (r-number 2)] + [(char=? c2 #\x) (r-number 16 exactness)] + [(char=? c2 #\d) (r-number 10 exactness)] + [(char=? c2 #\o) (r-number 8 exactness)] + [(char=? c2 #\b) (r-number 2 exactness)] [else (##sys#read-error port "illegal number syntax - invalid radix" c2)] ) ) ] - [else (r-number 10)] ) ) + [else (r-number 10 exactness)] ) ) (define (r-token) (let loop ((c (##sys#peek-char-0 port)) (lst '())) @@ -2783,8 +2792,8 @@ EOF ((#\d) (##sys#read-char-0 port) (r-number-with-exactness 10)) ((#\o) (##sys#read-char-0 port) (r-number-with-exactness 8)) ((#\b) (##sys#read-char-0 port) (r-number-with-exactness 2)) - ((#\i) (##sys#read-char-0 port) (##sys#exact->inexact (r-number-with-radix))) - ((#\e) (##sys#read-char-0 port) (##sys#inexact->exact (r-number-with-radix))) + ((#\i) (##sys#read-char-0 port) (r-number-with-radix 'i)) + ((#\e) (##sys#read-char-0 port) (r-number-with-radix 'e)) ((#\c) (##sys#read-char-0 port) (let ([c (##sys#read-char-0 port)]) @@ -2852,11 +2861,11 @@ EOF ((#\() (r-list #\( #\))) ((#\)) (##sys#read-char-0 port) (container c)) ((#\") (##sys#read-char-0 port) (r-string #\")) - ((#\.) (r-number #f)) - ((#\- #\+) (r-number #f)) + ((#\.) (r-number #f #f)) + ((#\- #\+) (r-number #f #f)) (else (cond [(eof-object? c) c] - [(char-numeric? c) (r-number #f)] + [(char-numeric? c) (r-number #f #f)] ((memq c reserved-characters) (reserved-character c)) (else diff --git a/tests/numbers-string-conversion-tests.scm b/tests/numbers-string-conversion-tests.scm index ca5c2e7a..c1b9d675 100644 --- a/tests/numbers-string-conversion-tests.scm +++ b/tests/numbers-string-conversion-tests.scm @@ -41,8 +41,39 @@ (write `(str value ...)) (display " => ") (write re-str) (newline) (set! total-errors (+ total-errors 1))) - (begin (display "OK ") - (write '(str value ...)) (newline)))))) + (and (handle-exceptions exn + (if res + (begin (display "READBACK EXN ERROR ") + (write `(str value ...)) + (display " => ") (write exn) (newline) + (set! total-errors (+ total-errors 1)) + #f) + #t) + (let ((re-read (with-input-from-string str read))) + (if (and (not (symbol? re-read)) + (not (eof-object? re-read)) + (or (not res) + (and (not (and (nan? res) (nan? re-read))) + (not (equal? res re-read))))) + (begin (display "READBACK ERROR ") + (write `(str value ...)) + (display " => ") (write re-read) (newline) + (set! total-errors (+ total-errors 1)) + #f) + #t))) + (let ((written&read (with-input-from-string + (with-output-to-string + (lambda () (write res))) + read))) + (if (not (or (and (nan? res) (nan? written&read)) + (equal? res written&read))) + (begin (display "R/W VARIANCE ERROR ") + (write `(str value ...)) + (display " => ") + (write written&read) (newline) + (set! total-errors (+ total-errors 1))) + (begin (display "OK ") + (write '(str value ...)) (newline))))))))) (test-numbers rest ...))) ((_ "no-totals") #f) ((_ x rest ...)Trap