2013-09-02 4 views
6

なぜ以下は機能しませんか?その後、リーダーのマクロ拡張が実行時に伝播しないのはなぜですか(読み取り)?

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

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

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

答えて

8

CL:READへの呼び出しが実行されるときに、CL:* READTABLE *にバインドされた読み取り可能テーブルに基づいて、READが送出します。フードの下で、ENABLE-INTERPOL-SYNTAXは、CL:* READTABLE *を設定してそれを保持し、CL:* READTABLE *の古い値を隠す新しい読み取り可能テーブルを作成しています。 DISABLE-INTERPOL-SYNTAXは以前の読込み可能なテーブルをアンスタッシュし、CL:* READTABLE *を設定して再度保持します。 defvarの後にどこにでも配置することができる

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

コールを構文を無効にすると、読み取りと-evalのはまだ動作しますが、場合:最低限、あなたのオリジナルの設定を変更し、あなたは以下のことによりたかった行動を手配することができますファイルにinterpol構文を直接入力して、有効と無効の呼び出しの間に構文を配置する必要があります。その後者の目的のためには、REQUIREへの呼び出しがEVAL-WHEN内にある必要があるのと同じ理由で、補間呼び出しがEVAL-WHENに展開されることが重要です。つまり、後者の書式がREADのときに、その効果が既に発生している必要があります。

CL-インターポールのインターフェースは何が起こっているかを抽象化し、私はあなたが手動で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

グローバルな状態でのみシングルリーダー、がありますので。効果的にマクロをオン/オフしています。この場合、リーダーマクロは、コンパイル時に関数read-and-evalが読み込まれる間だけ有効になります。

この場合、read-and-eval関数内のマクロを設定して、必要なときにリーダーが適切な状態になるようにする必要があります。

関連する問題