X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fcode%2Fearly-extensions.lisp;h=68cf7c5f48430534d568015e50432a6b1243d4b6;hb=127fd3d2fb843c6bb7ad0763e143d81877e760e8;hp=c3f2474359ca59d915547548e5ffde8871901417;hpb=906ecd4ef2d10aca23e1081f03c13fe2f932ed89;p=sbcl.git diff --git a/src/code/early-extensions.lisp b/src/code/early-extensions.lisp index c3f2474..68cf7c5 100644 --- a/src/code/early-extensions.lisp +++ b/src/code/early-extensions.lisp @@ -920,75 +920,24 @@ (def-constantly-fun constantly-nil nil) (def-constantly-fun constantly-0 0)) -;;; If X is an atom, see whether it is present in *FEATURES*. Also +;;; If X is a symbol, see whether it is present in *FEATURES*. Also ;;; handle arbitrary combinations of atoms using NOT, AND, OR. (defun featurep (x) - (if (consp x) - (case (car x) - ((:not not) - (if (cddr x) - (error "too many subexpressions in feature expression: ~S" x) - (not (featurep (cadr x))))) - ((:and and) (every #'featurep (cdr x))) - ((:or or) (some #'featurep (cdr x))) - (t - (error "unknown operator in feature expression: ~S." x))) - (not (null (memq x *features*))))) - -;;; Given a list of keyword substitutions `(,OLD ,NEW), and a -;;; &KEY-argument-list-style list of alternating keywords and -;;; arbitrary values, return a new &KEY-argument-list-style list with -;;; all substitutions applied to it. -;;; -;;; Note: If efficiency mattered, we could do less consing. (But if -;;; efficiency mattered, why would we be using &KEY arguments at -;;; all, much less renaming &KEY arguments?) -;;; -;;; KLUDGE: It would probably be good to get rid of this. -- WHN 19991201 -(defun rename-key-args (rename-list key-args) - (declare (type list rename-list key-args)) - ;; Walk through RENAME-LIST modifying RESULT as per each element in - ;; RENAME-LIST. - (do ((result (copy-list key-args))) ; may be modified below - ((null rename-list) result) - (destructuring-bind (old new) (pop rename-list) - ;; ANSI says &KEY arg names aren't necessarily KEYWORDs. - (declare (type symbol old new)) - ;; Walk through RESULT renaming any OLD key argument to NEW. - (do ((in-result result (cddr in-result))) - ((null in-result)) - (declare (type list in-result)) - (when (eq (car in-result) old) - (setf (car in-result) new)))))) - -;;; ANSI Common Lisp's READ-SEQUENCE function, unlike most of the -;;; other ANSI input functions, is defined to communicate end of file -;;; status with its return value, not by signalling. That is not the -;;; behavior that we usually want. This function is a wrapper which -;;; restores the behavior that we usually want, causing READ-SEQUENCE -;;; to communicate end-of-file status by signalling. -(defun read-sequence-or-die (sequence stream &key start end) - ;; implementation using READ-SEQUENCE - #-no-ansi-read-sequence - (let ((read-end (read-sequence sequence - stream - :start start - :end end))) - (unless (= read-end end) - (error 'end-of-file :stream stream)) - (values)) - ;; workaround for broken READ-SEQUENCE - #+no-ansi-read-sequence - (progn - (aver (<= start end)) - (let ((etype (stream-element-type stream))) - (cond ((equal etype '(unsigned-byte 8)) - (do ((i start (1+ i))) - ((>= i end) - (values)) - (setf (aref sequence i) - (read-byte stream)))) - (t (error "unsupported element type ~S" etype)))))) + (etypecase x + (cons + (case (car x) + ((:not not) + (cond + ((cddr x) + (error "too many subexpressions in feature expression: ~S" x)) + ((null (cdr x)) + (error "too few subexpressions in feature expression: ~S" x)) + (t (not (featurep (cadr x)))))) + ((:and and) (every #'featurep (cdr x))) + ((:or or) (some #'featurep (cdr x))) + (t + (error "unknown operator in feature expression: ~S." x)))) + (symbol (not (null (memq x *features*)))))) ;;;; utilities for two-VALUES predicates @@ -1257,3 +1206,53 @@ an implementation of EVAL that calls the compiler will be used. If set to :INTERPRET, an interpreter will be used.") +;;; Helper for making the DX closure allocation in macros expanding +;;; to CALL-WITH-FOO less ugly. +;;; +;;; This expands to something like +;;; +;;; (flet ((foo (...) )) +;;; (declare (optimize stack-allocate-dynamic-extent)) +;;; (flet ((foo (...) +;;; (foo ...)) +;;; (declare (dynamic-extent #'foo)) +;;; ))) +;;; +;;; The outer FLETs are inlined into the inner ones, and the inner ones +;;; are DX-allocated. The double-fletting is done to keep the bodies of +;;; the functions in an environment with correct policy: we don't want +;;; to force DX allocation in their bodies, which would be bad eg. +;;; in safe code. +(defmacro dx-flet (functions &body forms) + (let ((names (mapcar #'car functions))) + `(flet ,functions + #-sb-xc-host + (declare (optimize sb!c::stack-allocate-dynamic-extent)) + (flet ,(mapcar + (lambda (f) + (let ((args (cadr f)) + (name (car f))) + (when (intersection args lambda-list-keywords) + ;; No fundamental reason not to support them, but we + ;; don't currently need them here. + (error "Non-required arguments not implemented for DX-FLET.")) + `(,name ,args + (,name ,@args)))) + functions) + (declare (dynamic-extent ,@(mapcar (lambda (x) `(function ,x)) names))) + ,@forms)))) + +;;; Another similar one -- but actually touches the policy of the body, +;;; so take care with this one... +(defmacro dx-let (bindings &body forms) + `(locally + #-sb-xc-host + (declare (optimize sb!c::stack-allocate-dynamic-extent)) + (let ,bindings + (declare (dynamic-extent ,@(mapcar (lambda (bind) + (if (consp bind) + (car bind) + bind)) + bindings))) + ,@forms))) +