Re: SETF for functions returning multiple values.

"David McClain (as dbm at refined-audiometrics dot com)" <[email protected]> Tue, 9 Jun 2026 08:10:38 -0700
Newsgroups gmane.lisp.lispworks.general
Message-ID <[email protected]>
In my code, I already know the leading delimiter char. My only question is whether or not the lexeme has been delimited at all? In which case I need the matching closing delim. Or else I let the system readtable tell me when to sense the end of the lexeme.

So I don’t need to return two values.

----------------------------------

(defun get-matching-delim (ch)
  (and (find ch "~`'\":@#$%^&*_=|\\?/.,([{<«")
       (case ch
         (#\(  #\))
         (#\[  #\])
         (#\{  #\})
         (#\<  #\>)
         (#\«  #\»)
         (t    ch))
       ))

(defun |reader-for-#N| (stream sub-char numarg)
  (declare (ignore sub-char numarg))
  (let* ((ch     (read-char stream t nil t))
         (delim  (get-matching-delim ch))
         (str    (if delim
                     (read-chars-till-delim stream delim)
                   (read-chars-to-end-of-token stream ch))))
    (unless *read-suppress*
      (read-accumulated-string-or-fallback str stream))
    ))

—————————————

(defun make-char-buffer (&optional (nel 16))
  (make-array nel :element-type 'character
              :adjustable t :fill-pointer 0))

(defun read-chars-till (stream fn &optional (eof-error-p t) eof-value recursive-p)
  (let ((buffer (make-char-buffer)))
    (prog ()
      again
      (let ((ch  (read-char stream eof-error-p eof-value recursive-p)))
        (unless (funcall fn ch)
          (vector-push-extend ch buffer)
          (go again))
        ))
    (coerce buffer 'string)))

(defun read-chars-till-delim (stream delim)
  (read-chars-till stream (um:curry #'char= delim) t nil t))

———————————————————

(defun token-terminating-char-p (ch)
  (or (null ch)
      (whitespace-char-p ch)
      (multiple-value-bind (fn non-terminating-p)
          (get-macro-character ch)
        (and fn
             (not non-terminating-p)))
      ))

(defun read-chars-to-end-of-token (stream first-char)
  (unread-char first-char stream)
  (with-vanilla-readtable
    (read-chars-till stream (lambda (ch)
                              (when (token-terminating-char-p ch)
                                (when ch
                                  (unread-char ch stream))
                                t))
                     nil nil t)))

——————————————————

> On Jun 9, 2026, at 07:04, Tim Bradshaw (as tfb at cley dot com) <[email protected]> wrote:
> 
> On 9 Jun 2026, at 11:19, Madhu (as enometh at meer dot net) <[email protected]> wrote:
>> I'd just use a cons.  
> 
> In this case the values were handler and right delimiter and the interface needed to be compatible with an earlier one where delimiters always matched (so it supported syntax like #D|...| only).
> 
> Adding a second value seemed like it would enable an entirely compatible interface which exported no new symbols.  But it doesn't, because you want to be able to know what delimiter pairs exist in a handler table.
> 
> I did think about exposing that as an alist but that then means you have to answer questions about duplicate entries, whether modifying the alist modifies the behaviour, whether it's legal to do that & so on.  So it now has an accessor and a mapping function (with the restrictions of maphash, which is what it in fact is inside).
> 
> --tim
> 
> _______________________________________________
> Lisp Hug - the mailing list for LispWorks users
> [email protected]
> http://www.lispworks.com/support/lisp-hug.html