Skip to main content

copy-readtable

copy-readtable Function

Syntax:

copy-readtable &optional from-readtable to-readtable → readtable

Arguments and Values:

from-readtable—a readtable designator . The default is the current readtable.

to-readtable—a readtable or nil. The default is nil.

readtable—the to-readtable if it is non-nil, or else a fresh readtable.

Description:

copy-readtable copies from-readtable.

If to-readtable is nil, a new readtable is created and returned. Otherwise the readtable specified by to-readtable is modified and returned.

copy-readtable copies the setting of readtable-case.

Examples:

(setq zvar 123)123 
(set-syntax-from-char #\z #\’ (setq table2 (copy-readtable))) → T
zvar → 123
(copy-readtable table2 \*readtable\*) → #<READTABLE 614000277>

zvar → VAR
(setq \*readtable\* (copy-readtable)) → #<READTABLE 46210223>
zvar → VAR
(setq \*readtable\* (copy-readtable nil)) → #<READTABLE 46302670>
zvar → 123

See Also:

readtable, *readtable*

Notes:

(setq *readtable* (copy-readtable nil))

restores the input syntax to standard Common Lisp syntax, even if the initial readtable has been clobbered (assuming it is not so badly clobbered that you cannot type in the above expression).

On the other hand,

(setq *readtable* (copy-readtable))

replaces the current readtable with a copy of itself. This is useful if you want to save a copy of a readtable for later use, protected from alteration in the meantime. It is also useful if you want to locally bind the readtable to a copy of itself, as in:

(let ((*readtable* (copy-readtable))) ...)

Expanded Reference: copy-readtable

Creating a fresh copy of the current readtable

With no arguments, copy-readtable copies the current readtable (*readtable*) into a new readtable object.

(let ((rt (copy-readtable)))
(readtablep rt))
=> T

;; The copy is a distinct object
(let ((rt (copy-readtable)))
(eq rt *readtable*))
=> NIL

Getting a fresh standard readtable

Passing nil as the first argument copies the standard readtable. This is the standard way to reset to default Common Lisp read syntax.

(let ((*readtable* (copy-readtable nil)))
(readtable-case *readtable*))
=> :UPCASE

Restoring the standard readtable after modifications

If you have modified the current readtable and want to revert to standard syntax, use (copy-readtable nil).

(let ((*readtable* (copy-readtable)))
;; Modify the readtable
(set-macro-character #\! (lambda (s c) (declare (ignore s c)) 'bang))
;; Now restore standard syntax
(setf *readtable* (copy-readtable nil))
;; The ! modification is gone; ! is a normal constituent again
(with-input-from-string (s "hello")
(read s)))
=> HELLO

Copying into an existing readtable

When a second argument is provided, copy-readtable modifies and returns that readtable instead of creating a new one.

(let ((rt1 (copy-readtable))
(rt2 (copy-readtable)))
(set-macro-character #\! (lambda (s c) (declare (ignore s c)) 'bang) nil rt1)
;; Copy rt1 into rt2
(copy-readtable rt1 rt2)
;; rt2 now has the same macro character definitions as rt1
(eq (get-macro-character #\! rt2)
(get-macro-character #\! rt1)))
=> T

Isolating readtable modifications with LET

A common pattern is to locally bind *readtable* to a copy so that modifications do not affect the caller.

(defun read-with-custom-syntax (string)
(let ((*readtable* (copy-readtable)))
(set-macro-character #\! (lambda (s c)
(declare (ignore c))
(list 'not (read s t nil t))))
(read-from-string string)))

(read-with-custom-syntax "!foo")
=> (NOT FOO)
=> 4

;; The original readtable is unaffected
(with-input-from-string (s "!test")
(read s))
=> !TEST