X-Git-Url: https://git.distorted.org.uk/~mdw/lisp/blobdiff_plain/a035dd4a8175317f19a35cd04568d1655fb8d417..53e95db096ab58c3acbf176f4c671cb612d832ae:/mdw-base.lisp diff --git a/mdw-base.lisp b/mdw-base.lisp index c4c3e17..88ef8ba 100644 --- a/mdw-base.lisp +++ b/mdw-base.lisp @@ -34,7 +34,7 @@ #:stringify #:mappend #:listify #:fix-pair #:pairify #:parse-body #:whitespace-char-p #:slot-uninitialized - #:nlet #:while #:until #:case2 #:ecase2 + #:nlet #:while #:until #:case2 #:ecase2 #:setf-default #:with-gensyms #:let*/gensyms #:with-places #:locp #:locf #:ref #:with-locatives #:update-place #:update-place-after @@ -57,7 +57,7 @@ (defmacro compile-time-defun (name args &body body) "Define a function which can be used by macros during the compilation process." - `(eval-when (:compile-toplevel :load-toplevel) + `(eval-when (:compile-toplevel :load-toplevel :execute) (defun ,name ,args ,@body))) (defmacro show (x) @@ -80,8 +80,7 @@ (typecase str (string str) (symbol (symbol-name str)) - (t (with-output-to-string (s) - (princ str s))))) + (t (princ-to-string str)))) (defun mappend (function list &rest more-lists) "Apply FUNCTION to corresponding elements of LIST and MORE-LISTS, yielding @@ -119,7 +118,12 @@ (defun whitespace-char-p (ch) "Return whether CH is a whitespace character or not." (case ch - ((#\space #\tab #\newline #\return #\vt #\formfeed) t) + (#.(loop for i below char-code-limit + for ch = (code-char i) + unless (with-input-from-string (in (string ch)) + (peek-char t in nil)) + collect ch) + t) (t nil))) (declaim (ftype (function nil ()) slot-unitialized)) @@ -237,6 +241,31 @@ "Like `case2', but signals an error if no clause matches the SCRUTINEE." (do-case2-like 'ecase vform clauses)) +(defmacro setf-default (&rest specs &environment env) + "Like setf, but only sets places which are currently nil. + + The arguments are an alternating list of PLACEs and DEFAULTs. If a PLACE + is nil, the DEFAULT is evaluated and stored in the PLACE; otherwise the + default is /not/ stored. The result is the (new) value of the last + PLACE." + (labels ((doit (specs) + (cond ((null specs) nil) + ((null (cdr specs)) + (error "Odd number of arguments for SETF-DEFAULT.")) + (t + (let ((place (car specs)) + (default (cadr specs)) + (rest (cddr specs))) + (multiple-value-bind + (vars vals store-vals writer reader) + (get-setf-expansion place env) + `(let* ,(mapcar #'list vars vals) + (or ,reader + (multiple-value-bind ,store-vals ,default + ,writer)) + ,@(and rest (list (doit rest)))))))))) + (doit specs))) + ;;;-------------------------------------------------------------------------- ;;; with-places