Прочитать ввод в строку в макросе читателя 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"
Другие вопросы по тегам