Discussion:
[racket] read-syntax for an entire .rkt file
Thomas Gilray
2015-02-19 03:22:59 UTC
Permalink
Hi everyone,

I am trying to figure out how to use read-syntax on a port for an entire
.rkt file. I then want to call (expand ...) on this and get back a (begin
...) or (module ...) for the entire file in fully expanded form.

If I run (expand #`(define ...)) under a #lang racket, everything works. If
I place this in a file and use read-syntax however, each top-level
expression is returned individually, the language declaration isn't
supported, and without this information the expander complains that
"define" isn't defined. How do I properly read-syntax a whole file at once?

Any ideas would be greatly appreciated.

--
Tom
Sam Tobin-Hochstadt
2015-02-19 03:35:20 UTC
Permalink
Post by Thomas Gilray
Hi everyone,
I am trying to figure out how to use read-syntax on a port for an entire
.rkt file. I then want to call (expand ...) on this and get back a (begin
...) or (module ...) for the entire file in fully expanded form.
If I run (expand #`(define ...)) under a #lang racket, everything works. If
I place this in a file and use read-syntax however, each top-level
expression is returned individually, the language declaration isn't
supported, and without this information the expander complains that "define"
isn't defined. How do I properly read-syntax a whole file at once?
Any ideas would be greatly appreciated.
I've implemented this a couple times recently, probably the best
version is here:
https://github.com/samth/pycket/blob/master/pycket/pycket-lang/expand.rkt

The short answer is that you want to use `read-accept-lang` to enable
#lang, call `read-syntax` once on the port, and the call `expand` in a
new namespace (probably created with `make-base-namespace`).

Sam
____________________
Racket Users list:
http://lists.racket-lang.org/users
Spencer Florence
2015-02-19 03:49:00 UTC
Permalink
There is also a `with-module-reading-parameterization` that sets up the
reader to do this.
Post by Thomas Gilray
Post by Thomas Gilray
Hi everyone,
I am trying to figure out how to use read-syntax on a port for an entire
.rkt file. I then want to call (expand ...) on this and get back a (begin
...) or (module ...) for the entire file in fully expanded form.
If I run (expand #`(define ...)) under a #lang racket, everything works.
If
Post by Thomas Gilray
I place this in a file and use read-syntax however, each top-level
expression is returned individually, the language declaration isn't
supported, and without this information the expander complains that
"define"
Post by Thomas Gilray
isn't defined. How do I properly read-syntax a whole file at once?
Any ideas would be greatly appreciated.
I've implemented this a couple times recently, probably the best
https://github.com/samth/pycket/blob/master/pycket/pycket-lang/expand.rkt
The short answer is that you want to use `read-accept-lang` to enable
#lang, call `read-syntax` once on the port, and the call `expand` in a
new namespace (probably created with `make-base-namespace`).
Sam
____________________
http://lists.racket-lang.org/users
Thomas Gilray
2015-02-20 21:11:56 UTC
Permalink
Thank you both for your help! This is what I ended up with:

(define port (open-input-file "..."))
(with-module-reading-parameterization
(lambda ()
(pretty-print (syntax->datum (parameterize ([current-namespace
(make-base-namespace)])
(expand (read-syntax (object-name port)
port)))))))

I apologize for sending out two different emails on the same question. I
had sent one before subscribing and thought it was discarded when it was
actually only queued for approval.

--
Tom
Post by Spencer Florence
There is also a `with-module-reading-parameterization` that sets up the
reader to do this.
Post by Thomas Gilray
Post by Thomas Gilray
Hi everyone,
I am trying to figure out how to use read-syntax on a port for an entire
.rkt file. I then want to call (expand ...) on this and get back a
(begin
Post by Thomas Gilray
...) or (module ...) for the entire file in fully expanded form.
If I run (expand #`(define ...)) under a #lang racket, everything
works. If
Post by Thomas Gilray
I place this in a file and use read-syntax however, each top-level
expression is returned individually, the language declaration isn't
supported, and without this information the expander complains that
"define"
Post by Thomas Gilray
isn't defined. How do I properly read-syntax a whole file at once?
Any ideas would be greatly appreciated.
I've implemented this a couple times recently, probably the best
https://github.com/samth/pycket/blob/master/pycket/pycket-lang/expand.rkt
The short answer is that you want to use `read-accept-lang` to enable
#lang, call `read-syntax` once on the port, and the call `expand` in a
new namespace (probably created with `make-base-namespace`).
Sam
____________________
http://lists.racket-lang.org/users
Greg Hendershott
2015-02-21 00:38:17 UTC
Permalink
A few more points I've discovered:

- If you might want source position info, you need to use
`port-count-lines!`.

- If the file has relative requires -- e.g. `(require "foo.rkt")` -- you
need to set `current-load-relative-directory`. And you want to do the
`expand` while this is set.

- `with-input-from-file` is handy to close the port for you.

Here's a `file->syntax` function I have in racket-mode:

;; Return a syntax object (or #f) for the contents of `file`.
(define (file->syntax file #:expand? expand?)
(define-values (base _ __) (split-path file))
(parameterize ([current-load-relative-directory base]
[current-namespace (make-base-namespace)])
(define stx (with-handlers ([exn:fail? (const #f)])
(with-module-reading-parameterization
(thunk
(with-input-from-file file read-syntax/count-lines)))))
(if expand?
(expand stx) ;; do this while current-load-relative-directory is set
stx)))

(define (read-syntax/count-lines)
(port-count-lines! (current-input-port))
(read-syntax))
____________________
Racket Users list:
http://lists.racket-lang.org/users

Loading...