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)))))
Afficher les réponses par date