Re: [gambit-list] Readtables in Files
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
participants (1)
-
Seth Burleigh