macrosracketreader-macro

Creating a readtable with a disabled dispatch reader macro


I am creating a new language based on Racket and I don't want certain #x macros to work, such as the syntax-quote #'. How do I remove it so that #' does not do a syntax quote, but does whatever an unbound dispatch macro-char does?

I can do that with single-char macros by doing

(make-readtable (current-readtable)
                #\' #\a #f) ; set ' to be the same as a normal character

but I don't know how to do this for dispatch macros.


Solution

  • Assuming you want #' to be treated as ':

    Provide a reader-proc that simply calls the normal read-syntax:

    #lang racket/base
    
    (define (reader-proc ch in src line col pos)
      (read-syntax src in))
    
    (define our-readtable (make-readtable (current-readtable)
                                          #\'
                                          'dispatch-macro
                                          reader-proc))
    
    ;; A `#:wrapper1` for `syntax/module-reader`, i.e. to use in your
    ;; lang/reader.rkt
    (define (wrapper1 thk)
      (parameterize ([current-readtable our-readtable])
        (thk)))
    (provide wrapper1)
    
    ;; tests
    (module+ test
      (require rackunit
               racket/port)
      (parameterize ([current-readtable our-readtable])
        (check-equal? (with-input-from-string "#'foo" read)
                      'foo)
        (check-equal? (with-input-from-string "#'(foo)" read)
                      '(foo))
        (check-equal? (with-input-from-string "#'(foo #'(bar))" read)
                      '(foo (bar)))))
    

    A slightly more complicated example of working with 'dispatch-macro is the lambda reader literal support I just recently added to #lang rackjure.


    UPDATED

    Assuming you want #' to cause a read error, "bad syntax: #'":

    #lang racket/base
    
    (require syntax/readerr)
    
    (define (reader-proc ch in src line col pos)
      (raise-read-error (format "bad syntax: #~a" ch)
                        src line col pos 2))
    
    (define our-readtable (make-readtable (current-readtable)
                                          #\'
                                          'dispatch-macro
                                          reader-proc))
    
    ;; A `#:wrapper1` for `syntax/module-reader`, i.e. to use in your
    ;; lang/reader.rkt
    (define (wrapper1 thk)
      (parameterize ([current-readtable our-readtable])
        (thk)))
    (provide wrapper1)
    
    ;; tests
    (module+ test
      (require rackunit
               racket/port)
      (parameterize ([current-readtable our-readtable])
        (check-exn exn:fail? (λ () (with-input-from-string "#'foo" read)))))