Большинство функций Lisp для чтения текста принимают в качестве аргумента поток ввода. Поток ввода указывает, откуда или как получать символы текста для чтения. Ниже приведены возможные типы потока ввода:
Символы ввода считываются из buffer, начиная с символа, непосредственно следующего за точкой. Точка продвигается по мере считывания символов.
Символы ввода считываются из буфера, в котором находится marker, начиная с символа, непосредственно следующего за маркером. Позиция маркера продвигается по мере считывания символов. Значение точки в буфере не имеет значения, когда поток является маркером.
Символы ввода берутся из string, начиная с первого символа в строке и используя столько символов, сколько требуется.
Символы ввода генерируются function, которая должна поддерживать два типа вызовов:
t ¶t, используемый как поток, означает, что ввод считывается из минибуфера. Фактически, минибуфер вызывается один раз, и текст, предоставленный пользователем, преобразуется в строку, которая затем используется в качестве потока ввода. Если Emacs работает в пакетном режиме (см. Пактовый режим), вместо минибуфера используется стандартный ввод. Например,
(message "%s" (read t))
в пакетном режиме прочитает выражение Lisp из стандартного ввода и выведет результат в стандартный вывод.
nil ¶nil, переданный как поток ввода, означает использование значения standard-input; это значение является потоком ввода по умолчанию, и оно должно быть потоком ввода, не равным nil.
Символ в качестве потока ввода эквивалентен определению функции этого символа (если таковое имеется).
Вот пример чтения из потока, который является буфером, показывающий, где находится точка до и после:
---------- Buffer: foo ---------- This∗ is the contents of foo. ---------- Buffer: foo ----------
(read (get-buffer "foo"))
⇒ is
(read (get-buffer "foo"))
⇒ the
---------- Buffer: foo ---------- This is the∗ contents of foo. ---------- Buffer: foo ----------
Обратите внимание, что первое чтение пропускает пробел. Чтение пропускает любое количество пробельных символов перед значимым текстом.
Вот пример чтения из потока, который является маркером, изначально расположенным в начале показанного буфера. Прочитанное значение — это символ This.
---------- Buffer: foo ---------- This is the contents of foo. ---------- Buffer: foo ----------
(setq m (set-marker (make-marker) 1 (get-buffer "foo")))
⇒ #<marker at 1 in foo>
(read m)
⇒ This
m
⇒ #<marker at 5 in foo> ;; Перед первым пробелом.
Здесь мы читаем из содержимого строки:
(read "(When in) the course")
⇒ (When in)
Следующий пример считывает из минибуфера. Подсказка: ‘Lisp expression: ’. (Это всегда подсказка, используемая при чтении из потока t.) Ввод пользователя показан после подсказки.
(read t)
⇒ 23
---------- Buffer: Minibuffer ----------
Lisp expression: 23 RET
---------- Buffer: Minibuffer ----------
Наконец, вот пример потока, который является функцией, с именем useless-stream. Прежде чем использовать поток, мы инициализируем переменную useless-list списком символов. Затем каждый вызов функции useless-stream получает следующий символ в списке или откатывает символ, добавляя его в начало списка.
(setq useless-list (append "XY()" nil))
⇒ (88 89 40 41)
(defun useless-stream (&optional unread)
(if unread
(setq useless-list (cons unread useless-list))
(prog1 (car useless-list)
(setq useless-list (cdr useless-list)))))
⇒ useless-stream
Теперь мы читаем, используя таким образом сконструированный поток:
(read 'useless-stream)
⇒ XY
useless-list
⇒ (40 41)
Обратите внимание, что открывающая и закрывающая скобки остаются в списке. Парсер Lisp обнаружил открывающую скобку, решил, что она завершает ввод, и откатил ее. Попытка чтения из потока в этой точке прочитает ‘()’ и вернет nil.