[racket] Passing info from reader level

From: Matthew Flatt (mflatt at cs.utah.edu)
Date: Sun Dec 16 12:08:25 EST 2012

At Sat, 15 Dec 2012 13:12:50 -0800, Rajah Mahsohn Omega wrote:
> So from what I'm gathering the only way to share data with the reader and
> expander layer is to add the reader as a submodue in the main.rkt file.

No, I don't think that works. It might work under some circumstances,
but I think you should imagine that a program is read and compiled on a
different machine where it is run, and so you can't directly share
state between the reader and run-time code. (Ideally, Racket would
enforce that separation, but it currently doesn't.)

Instead, I meant instead that the reader needs to produce module that
has a submodule.

> So
> I've done that and it works but now I have a new problem, provide doesn't
> seem to be providing anything. Here is an example main.rkt file that
> provides meta-count.

The module that your reader produces uses the language `racket' (as
specified after the `syntax/module-reader' language), which doesn't
export `meta-count'.

More generally, I think you will need to use `#:wrapper2' so that you
get control over the whole `module' form to add a nested `module' form
to hold metadata. Here's an example, based on your code.

------------------------------------------------------------
"meta-count.rkt"
------------------------------------------------------------
#lang racket

(module* reader syntax/module-reader
  racket
  #:wrapper2 wrapper2
  (require syntax/readerr)

  (define meta-count 0)

  (define (wrapper2 in f)
    (define mod
      (parameterize ([current-readtable (make-meta-readtable)])
        (f in)))
    (define new-mod
      (syntax-case mod ()
        [(_mod _name _lang (_mb body ...))
         (quasisyntax/loc (if (syntax? mod) mod #'here)
           (_mod _name _lang 
                 (_mb (module meta-count racket/base #,meta-count) 
                      body ...)))]))
    (if (syntax? mod)
        new-mod
        (syntax->datum new-mod)))

  (define (make-meta-readtable)
    (make-readtable (current-readtable)
                    #\^ 'terminating-macro read-meta))
  (define read-meta
    (case-lambda
     [(ch in)
      (rread (object-name in) in)]
     [(ch in src line col pos)
      (rread src in)]))

  (define (rread src in)
    (define-values (line col pos) (port-next-location in))
    (let ([meta (regexp-match #rx"[^ (['`#]+" in)])
      (if meta
          (begin
            (set! meta-count (add1 meta-count))
            (make-special-comment meta))
          (raise-read-error "expected a metadata name" src line col pos 1)))))

------------------------------------------------------------
"m.rkt":
------------------------------------------------------------
#lang reader (submod "meta-count.rkt" reader)
^meta (+ ^meta1 1 2)

------------------------------------------------------------
Comamnd line, looking at the expanded form of "m.rkt":
------------------------------------------------------------
% raco expand m.rkt
(module m racket
  (#%module-begin
   (module meta-count racket/base
     (#%module-begin (#%app call-with-values (lambda () '2) print-values)))
   (#%app call-with-values (lambda () (#%app + '1 '2)) print-values)))

------------------------------------------------------------
REPL:
------------------------------------------------------------
> (require "m.rkt")
3
> (require (submod "m.rkt" meta-count))
2


Posted on the users mailing list.