- #!+sb-doc
- "DO-ANONYMOUS ({(Var [Init] [Step])}*) (Test Exit-Form*) Declaration* Form*
- Like DO, but has no implicit NIL block. Each Var is initialized in parallel
- to the value of the specified Init form. On subsequent iterations, the Vars
- are assigned the value of the Step form (if any) in parallel. The Test is
- evaluated before each evaluation of the body Forms. When the Test is true,
- the Exit-Forms are evaluated as a PROGN, with the result being the value
- of the DO."
- (do-do-body varlist endlist body 'let 'psetq 'do-anonymous (gensym)))
+ (frob-do-body varlist endlist body 'let 'psetq 'do-anonymous (gensym)))
+\f
+;;;; GENSYM tricks
+
+;;; GENSYM variant for easier debugging and better backtraces: append
+;;; the closest enclosing non-nil block name to the provided stem.
+(defun block-gensym (&optional (name "G") (env (when (boundp 'sb!c::*lexenv*)
+ (symbol-value 'sb!c::*lexenv*))))
+ (let ((block-name (when env
+ (car (find-if #'car (sb!c::lexenv-blocks env))))))
+ (if block-name
+ (sb!xc:gensym (format nil "~A[~A]" name block-name))
+ (sb!xc:gensym name))))
+
+;;; Compile a version of BODY for all TYPES, and dispatch to the
+;;; correct one based on the value of VAR. This was originally used
+;;; only for strings, hence the name. Renaming it to something more
+;;; generic might not be a bad idea.
+(defmacro string-dispatch ((&rest types) var &body body)
+ (let ((fun (sb!xc:gensym "STRING-DISPATCH-FUN")))
+ `(flet ((,fun (,var)
+ ,@body))
+ (declare (inline ,fun))
+ (etypecase ,var
+ ,@(loop for type in types
+ ;; TRULY-THE allows transforms to take advantage of the type
+ ;; information without need for constraint propagation.
+ collect `(,type (,fun (truly-the ,type ,var))))))))
+
+;;; Automate an idiom often found in macros:
+;;; (LET ((FOO (GENSYM "FOO"))
+;;; (MAX-INDEX (GENSYM "MAX-INDEX-")))
+;;; ...)
+;;;
+;;; "Good notation eliminates thought." -- Eric Siggia
+;;;
+;;; Incidentally, this is essentially the same operator which
+;;; _On Lisp_ calls WITH-GENSYMS.
+(defmacro with-unique-names (symbols &body body)
+ `(let ,(mapcar (lambda (symbol)
+ (let* ((symbol-name (symbol-name symbol))
+ (stem (if (every #'alpha-char-p symbol-name)
+ symbol-name
+ (concatenate 'string symbol-name "-"))))
+ `(,symbol (block-gensym ,stem))))
+ symbols)
+ ,@body))
+
+;;; Return a list of N gensyms. (This is a common suboperation in
+;;; macros and other code-manipulating code.)
+(declaim (ftype (function (index) list) make-gensym-list))
+(defun make-gensym-list (n)
+ (loop repeat n collect (block-gensym)))