[gambit-list] Readtables in Files
Seth Burleigh
seth at tewebs.com
Tue Jan 12 10:36:51 EST 2010
If anyones interested.
When loading a source, the function
##read-all-as-a-begin-expr-from-psettings is called which reads the whole
file using the reader as if it started with a 'begin' form.
Unlike some common lisp parsers, it does not read a toplevel and then
macroexpand it. But you can evaluate a form during reading using the #.
macro form (well, you
have to enable this. see below).
Unfortunately, ##read-all-as-a-being-expr-from-port (another function in the
chain of calls) makes a copy of the ##current-readtable (the default
readtable)
and then passes it around to other reader macros. So we cant just modify
that.
In _io.scm
(define-prim (##read-all-as-a-begin-expr-from-port
port
readtable
wrap
unwrap
start-syntax
close-port?)
(##with-exception-catcher
(lambda (exc)
(if close-port?
(##close-input-port port))
(macro-raise exc))
(lambda ()
(let ((rt
(##readtable-copy-shallow readtable)))
(macro-readtable-start-syntax-set! rt start-syntax)
(let* ((re
(##make-readenv port rt wrap unwrap 'script))
(head
(##cons (wrap re '##begin)
'())) ;; tail will be replaced with expressions read
(expr
(wrap re head))
(first
(##read-datum-or-eof re))
(script-line
(and (##eq? first (##script-marker))
(##read-line port #\newline #f ##max-fixnum)))
(language-and-tail
(##extract-language-and-tail script-line)))
(if language-and-tail
(let ((language (##car language-and-tail)))
(##readtable-setup-for-language! rt language)))
(let* ((rest
(if (##eof-object? first)
'()
(##read-all re ##read-datum-or-eof)))
(port-name
(##port-name port)))
(if close-port?
(##close-input-port port))
(cond ((##eof-object? first)
(##vector #f expr port-name))
((##eq? first (##script-marker))
(##set-cdr! head rest)
(##vector script-line expr port-name))
(else
(##set-cdr! head (##cons first rest))
(##vector #f expr port-name)))))))))
----------------------------------------------------------------------
So. Solutions to being able to redefine the reader table while the file is
being read.
(1) Redefine ##read-all-as-a-begin-expr-from-psettings to not make a copy of
the readtable. Probably not a good idea.
(2) Create a special reader syntax which imports the current
readtable/environment as a paramter into the special reader when one
loads/compiles a file.
I like this one. So instead of doing #.(begin (func-1) (func-2)) you
redefine #. to behave the same way except (current-file-readtable) now
references the actual
readtable/environment being used.
Note that you can change the current-readtable parameter value as shown
below and thus change the reader macro when loading non scripts (regular
.scm files). I think what
happens if the file is declared to be a script is that first the default
readtable is passed in but is then copied and then modified to fit the
appropriate language.
If it is a regular scheme file, i don't think the default readtable is
modified, but i haven't looked into this.
(parameterize
((current-readtable
(let ((readtab
(readtable-keywords-allowed?-set (readtable-eval-allowed?-set
(current-readtable) #t) #f)))
(##readtable-char-class-set! readtab ;;changing reader macro as a
demonstration. look at _io.scm for more examples
#\; #\t (lambda (re c)
(display c) (display "GOOFY!")
(error "IM NOT a comment!")))
readtab)))
(load "tar.scm")
;....save the current-readtable which has been modified
)
tar.scm:
;'yodel
Output:
;GOOFY!*** ERROR IN ##load -- IM NOT a comment!
OK, but what if we want to change the readtable in the actual file instead
of before loading it?
Well, now all we have to figure out is, given a environment object and
readtable, how do we go about 'injecting' a parameter into the environment?
Well, in _io.scm, heres the definition of the read-sharp-dot macro. And
thats about far as I went. I imagine youde have to find out how to pass a
environment to the #eval.
(define (##read-sharp-dot re next start-pos)
(if (not (macro-readtable-eval-allowed? (macro-readenv-readtable re)))
(begin
(##raise-datum-parsing-exception 'invalid-token re)
(##read-datum-or-label-or-none-or-dot re)) ;; skip error
(begin
(macro-read-next-char-or-eof re) ;; skip char after #\#
(let* ((expr
(##read-expr-from-port
(macro-readenv-port re)))
(val
(##eval expr)))
(macro-readenv-filepos-set! re start-pos) ;; set pos to start of
datum
(macro-readenv-wrap re val)))))
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.iro.umontreal.ca/pipermail/gambit-list/attachments/20100112/996eaf9f/attachment.htm>
More information about the Gambit-list
mailing list