reader: repair readtable re-mapping of # comment forms

Thanks to @LiberalArtist for the bug report and examples.
This commit is contained in:
Matthew Flatt 2019-07-11 12:09:21 -06:00
parent bad64945e7
commit ef4eb585d7
5 changed files with 78 additions and 7 deletions

View File

@ -115,7 +115,9 @@ The possible combinations for @racket[key], @racket[mode], and
@item{@racket[(code:line _char _like-char _readtable)] --- causes @item{@racket[(code:line _char _like-char _readtable)] --- causes
@racket[_char] to be parsed in the same way that @racket[_like-char] @racket[_char] to be parsed in the same way that @racket[_like-char]
is parsed in @racket[_readtable], where @racket[_readtable] can be is parsed in @racket[_readtable], where @racket[_readtable] can be
@racket[#f] to indicate the default readtable. Mapping a character to @racket[#f] to indicate the default readtable. (The mapping of
@racket[_char] does not apply after @litchar{#}, which is configured
separately via @racket['dispatch-macro].) Mapping a character to
the same actions as @litchar{|} in the default reader means that the the same actions as @litchar{|} in the default reader means that the
character starts quoting for symbols, and the same character character starts quoting for symbols, and the same character
terminates the quote; in contrast, mapping a character to the same terminates the quote; in contrast, mapping a character to the same

View File

@ -387,7 +387,58 @@
(try #\( #\) #\[ #\]) (try #\( #\) #\[ #\])
(try #\[ #\] #\( #\)) (try #\[ #\] #\( #\))
(try #\{ #\} #\[ #\])) (try #\{ #\} #\[ #\]))
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Check that comment forms can be redirecteed by a readtable
(let ([readstr (lambda (s)
(read (open-input-string s)))])
(define readtable
(make-readtable #f
#\$ #\; #f
#\* #\| #f
#\? #\! #f))
(parameterize ([current-readtable readtable])
(test 'x readstr "$this\nx")
;; char mapping doesn't affect `#...`
(err/rt-test (readstr "#$datum x") exn:fail:read?)
(err/rt-test (readstr "#* ??? *# x") exn:fail:read?)
(err/rt-test (readstr "#?/other\nx") exn:fail:read?)))
(let ([readstr (lambda (s)
(read (open-input-string s)))])
(define saw #f)
(define ((comment->x msg) ch in src line col pos)
(test #f equal? saw msg) ; only once
(set! saw msg)
'x)
(define readtable0
(make-readtable #f
#\; 'terminating-macro (comment->x "line")
#\; 'dispatch-macro (comment->x "s-exp")
#\| 'dispatch-macro (comment->x "block")
#\! 'dispatch-macro (comment->x "unix")))
(define readtable
(make-readtable readtable0
#\$ #\; readtable0
#\* #\| readtable0
#\? #\! readtable0))
(parameterize ([current-readtable readtable])
(for ([str '(";this" "$this" "#;datum" "#$datum" "#|a block|#" "#* x *#" "#!/usr/bin/env racket" "#?/other")]
[kind '("line" "line" "s-exp" error "block" error "unix" error)])
(cond
[(eq? kind 'error)
(err/rt-test (readstr str) exn:fail:read?)]
[else
(set! saw #f)
(test 'x readstr str)
(test kind values saw)]))))
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(report-errs) (report-errs)

View File

@ -13,6 +13,7 @@
readtable-mapping readtable-mapping
current-readtable current-readtable
readtable-effective-char readtable-effective-char
readtable-effective-char/#
effective-char effective-char
readtable-handler readtable-handler
readtable-dispatch-handler readtable-dispatch-handler
@ -136,6 +137,13 @@
[(char? target) target] [(char? target) target]
[else #\x])) ; return some non-special character [else #\x])) ; return some non-special character
;; Similar to `readtable-effective-char`, but for a character after
;; `#` to detect whether it has the usual meaning
(define (readtable-effective-char/# rt c)
(cond
[(and rt (hash-ref (readtable-dispatch-ht rt) c #f)) #f]
[else c]))
(define (effective-char c config) (define (effective-char c config)
(readtable-effective-char (read-config-readtable config) c)) (readtable-effective-char (read-config-readtable config) c))

View File

@ -43,13 +43,13 @@
(result-special-comment) (result-special-comment)
(skip-loop #f))] (skip-loop #f))]
[(and (char=? #\# ec) [(and (char=? #\# ec)
(eqv? #\| (peek-char/special in config 0 source))) (eqv? #\| (readtable-effective-char/# rt (peek-char/special in config 0 source))))
(skip-pipe-comment! c in config) (skip-pipe-comment! c in config)
(if (read-config-keep-comment? config) (if (read-config-keep-comment? config)
(result-special-comment) (result-special-comment)
(skip-loop #f))] (skip-loop #f))]
[(and (char=? #\# ec) [(and (char=? #\# ec)
(eqv? #\! (peek-char/special in config 0 source)) (eqv? #\! (readtable-effective-char/# rt (peek-char/special in config 0 source)))
(let ([c3 (peek-char/special in config 1 source)]) (let ([c3 (peek-char/special in config 1 source)])
(or (eqv? #\space c3) (or (eqv? #\space c3)
(eqv? #\/ c3)))) (eqv? #\/ c3))))
@ -58,7 +58,7 @@
(result-special-comment) (result-special-comment)
(skip-loop #f))] (skip-loop #f))]
[(and (char=? #\# ec) [(and (char=? #\# ec)
(eqv? #\; (peek-char/special in config 0 source))) (eqv? #\; (readtable-effective-char/# rt (peek-char/special in config 0 source))))
(consume-char in #\;) (consume-char in #\;)
(define v (read-one #f in config)) (define v (read-one #f in config))
(when (eof-object? v) (when (eof-object? v)

View File

@ -52860,6 +52860,10 @@ static const char *startup_source =
"(let-values(((target_0)(hash-ref(readtable-char-ht rt_0) c_0 #f)))" "(let-values(((target_0)(hash-ref(readtable-char-ht rt_0) c_0 #f)))"
"(if(not target_0)(let-values() c_0)(if(char? target_0)(let-values() target_0)(let-values() '#\\x)))))))" "(if(not target_0)(let-values() c_0)(if(char? target_0)(let-values() target_0)(let-values() '#\\x)))))))"
"(define-values" "(define-values"
"(readtable-effective-char/#)"
"(lambda(rt_0 c_0)"
"(begin(if(if rt_0(hash-ref(readtable-dispatch-ht rt_0) c_0 #f) #f)(let-values() #f)(let-values() c_0)))))"
"(define-values"
"(effective-char)" "(effective-char)"
"(lambda(c_0 config_0)" "(lambda(c_0 config_0)"
"(begin" "(begin"
@ -53152,6 +53156,8 @@ static const char *startup_source =
"(if(if(char=? '#\\# ec_0)" "(if(if(char=? '#\\# ec_0)"
"(eqv?" "(eqv?"
" '#\\|" " '#\\|"
"(readtable-effective-char/#"
" rt_0"
"(let-values(((in_1) in_0)((skip-count_0) 0)((source_1) source_0))" "(let-values(((in_1) in_0)((skip-count_0) 0)((source_1) source_0))"
"(let-values(((c_1)" "(let-values(((c_1)"
"(peek-char-or-special" "(peek-char-or-special"
@ -53159,7 +53165,7 @@ static const char *startup_source =
" skip-count_0" " skip-count_0"
" 'special" " 'special"
" source_1)))" " source_1)))"
"(if(eq? c_1 'special)(special1.1 'special) c_1))))" "(if(eq? c_1 'special)(special1.1 'special) c_1)))))"
" #f)" " #f)"
"(let-values()" "(let-values()"
"(begin" "(begin"
@ -53170,6 +53176,8 @@ static const char *startup_source =
"(if(if(char=? '#\\# ec_0)" "(if(if(char=? '#\\# ec_0)"
"(if(eqv?" "(if(eqv?"
" '#\\!" " '#\\!"
"(readtable-effective-char/#"
" rt_0"
"(let-values(((in_1) in_0)" "(let-values(((in_1) in_0)"
"((skip-count_0) 0)" "((skip-count_0) 0)"
"((source_1) source_0))" "((source_1) source_0))"
@ -53179,7 +53187,7 @@ static const char *startup_source =
" skip-count_0" " skip-count_0"
" 'special" " 'special"
" source_1)))" " source_1)))"
"(if(eq? c_1 'special)(special1.1 'special) c_1))))" "(if(eq? c_1 'special)(special1.1 'special) c_1)))))"
"(let-values(((c3_0)" "(let-values(((c3_0)"
"(let-values(((in_1) in_0)" "(let-values(((in_1) in_0)"
"((skip-count_0) 1)" "((skip-count_0) 1)"
@ -53206,6 +53214,8 @@ static const char *startup_source =
"(if(if(char=? '#\\# ec_0)" "(if(if(char=? '#\\# ec_0)"
"(eqv?" "(eqv?"
" '#\\;" " '#\\;"
"(readtable-effective-char/#"
" rt_0"
"(let-values(((in_1) in_0)" "(let-values(((in_1) in_0)"
"((skip-count_0) 0)" "((skip-count_0) 0)"
"((source_1) source_0))" "((source_1) source_0))"
@ -53215,7 +53225,7 @@ static const char *startup_source =
" skip-count_0" " skip-count_0"
" 'special" " 'special"
" source_1)))" " source_1)))"
"(if(eq? c_1 'special)(special1.1 'special) c_1))))" "(if(eq? c_1 'special)(special1.1 'special) c_1)))))"
" #f)" " #f)"
"(let-values()" "(let-values()"
"(let-values((()(begin(consume-char in_0 '#\\;)(values))))" "(let-values((()(begin(consume-char in_0 '#\\;)(values))))"