- `(prog1
- (svref ,',n-stack ,',n-index)
- (incf ,',n-index)))
- (call-with-popped-things (fun n)
- (let ((n-start (gensym)))
- `(let ((,n-start (+ ,',n-index ,n)))
- (declare (type index ,n-start))
- (setq ,',n-index ,n-start)
- (,fun ,@(make-list n :initial-element
- `(svref ,',n-stack
- (decf ,n-start))))))))
- ,(if pushp
- `(let ((,n-res (progn ,@forms)))
- (when (zerop ,n-index)
- (grow-fop-stack)
- (setq ,n-index *fop-stack-pointer*
- ,n-stack *fop-stack*))
- (decf ,n-index)
- (setq *fop-stack-pointer* ,n-index)
- (setf (svref ,n-stack ,n-index) ,n-res))
- `(prog1
- (progn ,@forms)
- (setq *fop-stack-pointer* ,n-index)))))))
+ `(vector-pop ,',fop-stack))
+ (push-stack (value)
+ `(vector-push-extend ,value ,',fop-stack))
+ (call-with-popped-args (fun n)
+ `(%call-with-popped-args ,fun ,n ,',fop-stack)))
+ ,(if pushp
+ `(vector-push-extend (progn ,@forms) ,fop-stack)
+ `(progn ,@forms))))))
+
+;;; Call FUN with N arguments popped from STACK.
+(defmacro %call-with-popped-args (fun n stack)
+ ;; N's integer value must be known at macroexpansion time.
+ (declare (type index n))
+ (with-unique-names (n-stack old-length new-length)
+ (let ((argtmps (make-gensym-list n)))
+ `(let* ((,n-stack ,stack)
+ (,old-length (fill-pointer ,n-stack))
+ (,new-length (- ,old-length ,n))
+ ,@(loop for i from 0 below n collecting
+ `(,(nth i argtmps)
+ (aref ,n-stack (+ ,new-length ,i)))))
+ (declare (type (vector t) ,n-stack))
+ (setf (fill-pointer ,n-stack) ,new-length)
+ ;; (For some applications it might be appropriate to FILL the
+ ;; popped area with NIL here, to avoid holding onto garbage. For
+ ;; sbcl-0.8.7.something, though, it shouldn't matter, because
+ ;; we're using this only to pop stuff off *FOP-STACK*, and the
+ ;; entire *FOP-STACK* can be GCed as soon as LOAD returns.)
+ (,fun ,@argtmps)))))