2013-09-02 5 views
6

Perché il seguente non funziona?Perché le estensioni di macro del lettore non si propagano in runtime (leggi)?

;;;; foo.lisp 
(in-package :cl-user) 

(eval-when (:compile-toplevel :load-toplevel :execute) 
    (require :cl-interpol)) 

(cl-interpol:enable-interpol-syntax) 

(defun read-and-eval (s) 
    (eval (read-from-string s))) 

(cl-interpol:disable-interpol-syntax) 

poi:

LISP> (load (compile-file "foo.lisp")) 
=> T 

LISP> (read-and-eval 
     "(let ((a \"foo\")) (prinC#?\"${a}\"))") 
=> no dispatch function defined for #\? 

risposta

8

CL: LEGGI le spedizioni in base al readtable associato a CL: * READTABLE * al momento dell'esecuzione della chiamata a READ. ENABLE-INTERPOL-SYNTAX sta creando un nuovo readtable, impostando CL: * READTABLE * per tenerlo, e nascondendo il vecchio valore di CL: * READTABLE *. DISABLE-INTERPOL-SYNTAX sta rimuovendo il programma precedente e impostando CL: * READTABLE * per trattenerlo nuovamente. Minimamente cambiare la configurazione originale, è possibile organizzare per il comportamento che si voleva dal seguente:

(in-package :cl-user) 

(eval-when (:compile-toplevel :load-toplevel :execute) 
    (require :cl-interpol)) 

(cl-interpol:enable-interpol-syntax) 

(defvar *interpol-reader* *readtable*) 

(cl-interpol:disable-interpol-syntax) 

(defun read-and-eval (s) 
    (let ((*readtable* *interpol-reader*)) 
    (eval (read-from-string s)))) 

La chiamata per disattivare la sintassi potrebbe essere posizionato ovunque dopo la defvar e leggere e-valuta continuerà a funzionare, ma se vuoi inserire direttamente la sintassi di interpol nel file che la sintassi dovrà essere posta tra abilitare e disabilitare le chiamate. Per quest'ultimo scopo è significativo che le chiamate di interpol si espandano in EVAL-WHENs, per la stessa ragione per cui è necessario che la chiamata a REQUIRE sia all'interno di EVAL-WHEN; cioè, gli effetti devono essere già avvenuti quando le ultime forme sono READ. L'interfaccia di

CL-INTERPOL astrae ciò che sta accadendo, quindi vi mostrerà come è possibile creare manualmente e cambiare un readtable:

;; Create a fresh readtable with standard syntax 
(defvar *not-readtable* (copy-readtable nil)) 

;; A simple reader function 
(defun not-reader (stream char &optional count) 
    "Like ' but for (not ...) instead of (quote ...)" 
    (declare (ignore count char)) 
    `(not ,(read stream t nil t))) 

;; Mutate that readtable so that the dispatch character you want 
;; calls the function you want 
(set-macro-character #\! 'not-reader nil *not-readtable*) 

;; Try it out 
(let ((*readtable* *not-readtable*)) 
    (read-from-string "(if !foo bar baz)")) 

=> 
(IF (NOT FOO) 
    BAR 
    BAZ) 
10

Perché c'è un solo lettore, con lo stato globale. Stai effettivamente accendendo e spegnendo i tuoi macronutrienti. In questo caso, le macro del lettore sono abilitate solo per la durata della lettura della funzione read-and-eval in fase di compilazione.

In questo caso è necessario impostare i macro all'interno della funzione read-and-eval per garantire che il lettore sia nello stato appropriato quando necessario.

Problemi correlati