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)))))