Прочитать ввод в строку в макросе читателя Lisp
Я пытаюсь сделать макрос для чтения, который конвертирует @this в "this". Вот что у меня сейчас есть:
(defun string-reader (stream char)
(declare (ignore char))
(format nil "\"~a\"" (read-line stream t nil t))
)
(set-macro-character #\@ #'string-reader )
Проблема в том, что для этого нужно ставить новую строку после @this. Я также попробовал это с (читать), но это просто возвращает переменную test, которая не была установлена. Я не могу просто жестко кодировать количество символов после символа @, потому что я не знаю, сколько их будет. Есть ли способ это исправить?
Редактировать: единственный способ сделать это, чтобы перебирать read-char и peek-char, читая, пока я не доберусь до #),#\space или #\Newline?
1 ответ
Решение
Вы можете попробовать использовать read
а затем посмотрите, что он возвращает:
(defun string-reader (stream char)
(declare (ignore char))
(let ((this (let ((*readtable* (copy-readtable)))
(setf (readtable-case *readtable*) :preserve)
(read stream t nil t))))
(etypecase this
(string this)
(symbol (symbol-name this)))))
(set-macro-character #\@ #'string-reader)
Выше позволит @This
а также @"This"
, но нет @333
,
Эта версия просто читает строку до пробела:
(defun read-as-string-until-whitespace (stream)
(with-output-to-string (out-stream)
(loop for next = (peek-char nil stream t nil t)
until (member next '(#\space #\newline #\tab))
do (write-char (read-char stream t nil t) out-stream))))
(defun string-reader (stream char)
(declare (ignore char))
(read-as-string-until-whitespace stream))
(set-macro-character #\@ #'string-reader)
Пример:
CL-USER 21 > @this
"this"
CL-USER 22 > @42
"42"
CL-USER 23 > @FooBar
"FooBar"