1 ;;; -*- Mode: Lisp; Syntax: Common-Lisp; Package: GLISP; -*-
2 ;;; ---------------------------------------------------------------------------
3 ;;; Title: Some common utilities for the Closure browser
4 ;;; Created: 1997-12-27
5 ;;; Author: Gilbert Baumann <gilbert@base-engineering.com>
6 ;;; License: MIT style (see below)
7 ;;; ---------------------------------------------------------------------------
8 ;;; (c) copyright 1997-1999 by Gilbert Baumann
10 ;;; Permission is hereby granted, free of charge, to any person obtaining
11 ;;; a copy of this software and associated documentation files (the
12 ;;; "Software"), to deal in the Software without restriction, including
13 ;;; without limitation the rights to use, copy, modify, merge, publish,
14 ;;; distribute, sublicense, and/or sell copies of the Software, and to
15 ;;; permit persons to whom the Software is furnished to do so, subject to
16 ;;; the following conditions:
18 ;;; The above copyright notice and this permission notice shall be
19 ;;; included in all copies or substantial portions of the Software.
21 ;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 ;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 ;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 ;;; IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
25 ;;; CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26 ;;; TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27 ;;; SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 ;; ----------------------------------------------------------------------------
33 ;; 1999-08-24 GB = fixed MULTIPLE-VALUE-OR it now takes any number of
39 (defun neq (x y
) (not (eq x y
)))
41 (define-compiler-macro neq
(x y
)
44 (defmacro defsubst
(name args
&body body
)
45 `(runes:definline
,name
,args
,@body
))
47 ;;; --------------------------------------------------------------------------------
50 (defun curry (fun &rest args
)
51 #'(lambda (&rest more
)
52 (apply fun
(append args more
))))
54 (defun rcurry (fun &rest args
)
55 #'(lambda (&rest more
)
56 (apply fun
(append more args
))))
59 #'(lambda (&rest args
)
60 (funcall f
(apply g args
))))
63 #'(lambda (&rest args
)
64 (declare (ignore args
))
71 (defun false (&rest x
)
75 ;;; --------------------------------------------------------------------------------
78 (defstruct (promise (:print-function print-promise
))
81 (defun print-promise (self sink depth
)
82 (declare (ignore depth
))
83 (if (promise-forced? self
)
84 (format sink
"#<~S ~S ~S>" 'promise
:forced
(promise-value self
))
85 (format sink
"#<~S ~S>" 'promise
:lazy
)))
87 (defmacro promise
(form)
88 `(make-promise :forced? nil
:fun
#'(lambda () ,form
)))
91 (if (promise-forced? x
)
93 (setf (promise-forced? x
) t
94 (promise-value x
) (funcall (promise-fun x
)))))
96 ;;; --------------------------------------------------------------------------------
97 ;;; Some additional <op>f macros
99 (define-modify-macro maxf
(&rest nums
) max
)
100 (define-modify-macro minf
(&rest nums
) min
)
101 (define-modify-macro nconcf
(&rest args
) nconc
)
103 ;; Man sollte mal ein generelles <op>f macro definieren, in etwa so
104 ;; (funcallf #'nconc x 10)
106 ;;; Modifizierte Version von max / min.
108 (defun max* (&rest nums
)
109 (reduce (lambda (x y
)
113 nums
:initial-value nil
))
115 (defun min* (&rest nums
)
116 (reduce (lambda (x y
)
120 nums
:initial-value nil
))
122 ;;; --------------------------------------------------------------------------------
125 (defmacro show
(&rest exprs
)
126 `(format T
"~&** [~S]~{~#[~:; ~] ~A = ~S~}." ',(current-function-name)
127 (list ,@(mapcan (lambda (x)
128 (list (let ((*print-case
* :downcase
))
134 (defun current-function-name ()
135 (car COMPILER
::.FUNCTIONS-DEFINED.
))
138 (defun current-function-name ()
141 ;;; --------------------------------------------------------------------------------
144 (defmacro multiple-value-or
(&rest xs
)
151 `(LET ((,g
(MULTIPLE-VALUE-LIST ,(car xs
))))
154 (MULTIPLE-VALUE-OR ,@(cdr xs
))))))))
156 (defun multiple-value-some (predicate &rest sequences
)
158 (apply #'some
(lambda (&rest args
)
159 (let ((res (multiple-value-list (apply predicate args
))))
165 ;;; --------------------------------------------------------------------------------
168 (defmacro while
(test &body body
)
169 `(until (not ,test
) ,@body
))
171 (defmacro until
(test &body body
)
172 `(do () (,test
) ,@body
))
174 ;;; --------------------------------------------------------------------------------
177 (defun split-by-if (predicate seq
&key
(start 0) (nuke-empty-p nil
))
178 (let ((p0 (position-if predicate seq
:start start
)))
180 (if (and nuke-empty-p
(= start p0
))
181 (split-by-if predicate seq
:start
(+ p0
1) :nuke-empty-p nuke-empty-p
)
182 (cons (subseq seq start p0
)
183 (split-by-if predicate seq
:start
(+ p0
1) :nuke-empty-p nuke-empty-p
)))
184 (if (and nuke-empty-p
(= start
(length seq
)))
186 (list (subseq seq start
))))))
188 (defun split-by (item &rest args
)
189 (apply #'split-by-if
(curry #'eql item
) args
))
191 (defun split-by-member (items &rest args
)
192 (apply #'split-by-if
(rcurry #'member items
) args
))
194 ;;; --------------------------------------------------------------------------------
197 (defun white-space-p (ch)
198 ;;(declare #.cl-user:+optimize-very-fast-trusted+)
205 (define-compiler-macro white-space-p
(ch)
206 `(member ,ch
'(#\Return
#\Newline
#\Space
#\Tab
#\Page
)) )
208 (defun sanify-string (string &optional
(begin? t
) (end? t
)
210 (let ((i (position-if #'white-space-p string
:start start
)))
212 (let ((j (position-if-not #'white-space-p string
:start i
)))
214 (concatenate 'string
(subseq string start i
)
215 (if (and (= i start
) begin?
) "" " ")
216 (sanify-string string nil end? j
))
217 (concatenate 'string
(subseq string start i
)
218 (if (not end?
) " " "")))))
219 (t (subseq string start
)))))
221 (defun sanify-rod (string &optional
(begin? t
) (end? t
) (start 0))
222 (let ((i (position-if #'runes
:white-space-rune-p string
:start start
)))
224 (let ((j (position-if-not #'runes
:white-space-rune-p
228 (concatenate 'runes
:rod
(subseq string start i
)
229 (if (and (= i start
) begin?
) '#() '#(32))
230 (sanify-rod string nil end? j
))
231 (concatenate 'runes
:rod
(subseq string start i
)
232 (if (not end?
) '#(32) '#())))))
233 (t (subseq string start
)))))
235 (defun split-string (bag string
)
236 (setq string
(string-trim bag string
))
237 (cond ((= (length string
) 0) nil
)
239 (let ((p (position bag string
:test
#'(lambda (x y
) (member y x
)))))
241 (cons (subseq string
0 p
) (split-string bag
(subseq string p
)))
244 (defun string-begin-equal (a b
)
245 "Returns non-NIL if the beginning of 'a' matches 'b'"
246 (and (>= (length a
) (length b
))
247 (string-equal a b
:end1
(length b
))) )
249 (defun string-begin= (a b
)
250 "Returns non-NIL if the beginning of 'a' matches 'b'"
251 (and (>= (length a
) (length b
))
252 (string= a b
:end1
(length b
))) )
255 ;;; ------------------------------------------------------------------------------------------
260 (defstruct (future (:print-function print-future
))
261 (read-lock (mp/make-lock
))
262 (guess-lock (mp/make-lock
))
265 (defun print-future (self sink depth
)
266 (if (future-guess-lock self
)
267 (format sink
"#<~S unpredicted>" (type-of self
))
268 (if (and *print-level
* (>= depth
*print-level
*))
269 (format sink
"#<~S predicted as ...>" (type-of self
))
270 (format sink
"#<~S predicted as ~S>" (type-of self
) (future-value self
)))))
273 (let ((res (make-future)))
274 (mp/seize-lock
(future-guess-lock res
))
277 (defun guess (future)
278 (mp/with-lock
((future-read-lock future
))
279 (let ((lock (future-guess-lock future
)))
281 (mp/seize-lock lock
))
282 (future-value future
))))
284 (defun predict (future value
)
285 (setf (future-value future
) value
)
286 (let ((lock (future-guess-lock future
)))
287 (setf (future-guess-lock future
) nil
)
288 (mp/release-lock lock
))
293 (defun fcar (x) (car (guess x
)))
294 (defun fcdr (x) (cdr (guess x
)))
295 (defun fnull (x) (null (guess x
)))
296 (defun fendp (x) (endp (guess x
)))
298 (defmacro doflist
((var list
&optional res
) &body body
)
299 (let ((q (make-symbol "Q")))
300 `(do ((,q
,list
(fcdr ,q
)))
302 (let ((,var
(fcar ,q
)))
305 (defun mapfcar (fun flist
)
306 (cond ((fendp flist
) nil
)
307 ((cons (funcall fun
(fcar flist
)) (mapfcar fun
(fcdr flist
))))))
316 ;; (doflist (k f) (print k))
319 ;; (setq f (cdr (predict f (cons 'foo (future)))))
320 ;; (setq f (cdr (predict f (cons 'bar (future)))))
324 ;;;; -----------------------------------------------------------------------------------------
325 ;;;; Homebrew stream classes
328 ;; I am really tired of standard Common Lisp streams and thier incompatible
331 ;; A gstream is an objects with obeys to the following protocol:
333 ;; g/read-byte stream &optional (eof-error-p t) eof-value
334 ;; g/unread-byte byte stream
335 ;; g/read-char stream &optional (eof-error-p t) eof-value
336 ;; g/unread-char char stream
337 ;; g/write-char char stream
338 ;; g/write-byte byte stream
339 ;; g/finish-output stream
340 ;; g/close stream &key abort
342 ;; Additionally the follwing generic functions are implemented based
343 ;; on the above protocol and may be reimplemented for any custom
344 ;; stream class for performance.
346 ;; g/write-string string stream &key start end
347 ;; g/read-line stream &optional (eof-error-p t) eof-value
348 ;; g/read-line* stream &optional (eof-error-p t) eof-value
349 ;; g/read-byte-sequence sequence stream &key start end
350 ;; g/read-char-sequence sequence stream &key start end
351 ;; g/write-byte-sequence sequence stream &key start end
352 ;; g/write-char-sequence sequence stream &key start end
355 ;; The following classes exists
358 ;; use-char-for-byte-stream-flavour
359 ;; use-byte-for-char-stream-flavour
364 (defclass gstream
() ())
366 ;;; use-char-for-byte-stream-flavour
368 (defclass use-char-for-byte-stream-flavour
() ())
370 (defmethod g/read-byte
((self use-char-for-byte-stream-flavour
) &optional
(eof-error-p t
) eof-value
)
371 (let ((r (g/read-char self eof-error-p
:eof
)))
376 (defmethod g/unread-byte
(byte (self use-char-for-byte-stream-flavour
))
377 (g/unread-char
(or (and #+CMU
(<= byte char-code-limit
) (code-char byte
))
378 (error "Cannot stuff ~D. into a character." byte
))
381 (defmethod g/write-byte
(byte (self use-char-for-byte-stream-flavour
))
382 (g/write-char
(or (and #+CMU
(<= byte char-code-limit
) (code-char byte
))
383 (error "Cannot stuff ~D. into a character." byte
))
386 ;;; use-byte-for-char-stream-flavour
388 (defclass use-byte-for-char-stream-flavour
() ())
390 (defmethod g/read-char
((self use-byte-for-char-stream-flavour
) &optional
(eof-error-p t
) eof-value
)
391 (let ((byte (g/read-byte self eof-error-p
:eof
)))
394 (let ((res (and #+CMU
(<= byte char-code-limit
) (code-char byte
))))
396 (error "The byte ~D. could not been represented as character in your LISP implementation." byte
))))))
398 (defmethod g/unread-char
(char (self use-byte-for-char-stream-flavour
))
399 (g/unread-byte
(char-code char
) self
))
401 (defmethod g/write-char
(char (self use-byte-for-char-stream-flavour
))
402 (g/write-byte
(char-code char
) self
))
404 ;;; ------------------------------------------------------------
405 ;;; Streams made up out of Common Lisp streams
409 (defclass cl-stream
(gstream)
410 ((cl-stream :initarg
:cl-stream
)))
412 (defmethod g/finish-output
((self cl-stream
))
413 (with-slots (cl-stream) self
414 (finish-output cl-stream
)))
416 (defmethod g/close
((self cl-stream
) &key abort
)
417 (with-slots (cl-stream) self
418 (close cl-stream
:abort abort
)))
422 (defclass cl-byte-stream
(use-byte-for-char-stream-flavour cl-stream
)
423 ((lookahead :initform nil
)))
425 (defmethod g/read-byte
((self cl-byte-stream
) &optional
(eof-error-p t
) eof-value
)
426 (with-slots (cl-stream lookahead
) self
429 (setf lookahead nil
))
430 (read-byte cl-stream eof-error-p eof-value
))))
432 (defmethod g/unread-byte
(byte (self cl-byte-stream
))
433 (with-slots (cl-stream lookahead
) self
435 (error "You cannot unread twice.")
436 (setf lookahead byte
))))
438 (defmethod g/write-byte
(byte (self cl-byte-stream
))
439 (with-slots (cl-stream) self
440 (write-byte byte cl-stream
)))
442 (defmethod g/read-byte-sequence
(sequence (input cl-byte-stream
) &key
(start 0) (end (length sequence
)))
443 (with-slots (cl-stream) input
444 (read-byte-sequence sequence cl-stream
:start start
:end end
)))
446 (defmethod g/write-byte-sequence
(sequence (sink cl-byte-stream
) &key
(start 0) (end (length sequence
)))
447 (with-slots (cl-stream) sink
448 (cl:write-sequence sequence cl-stream
:start start
:end end
)))
452 (defclass cl-char-stream
(use-char-for-byte-stream-flavour cl-stream
)
455 (defmethod g/read-char
((self cl-char-stream
) &optional
(eof-error-p t
) eof-value
)
456 (with-slots (cl-stream) self
457 (read-char cl-stream eof-error-p eof-value
)))
459 (defmethod g/unread-char
(char (self cl-char-stream
))
460 (with-slots (cl-stream) self
461 (unread-char char cl-stream
)))
463 (defmethod g/write-char
(char (self cl-char-stream
))
464 (with-slots (cl-stream) self
465 (write-char char cl-stream
)))
467 ;;; ------------------------------------------------------------
468 ;;; General or fall back stream methods
470 (defmethod g/write-string
(string (stream t
) &key
(start 0) (end (length string
)))
471 (do ((i start
(+ i
1)))
473 (g/write-char
(char string i
) stream
)))
475 (defmethod g/read-line
((stream t
) &optional
(eof-error-p t
) eof-value
)
477 (do ((c (g/read-char stream eof-error-p
:eof
)
478 (g/read-char stream nil
:eof
)))
479 ((or (eq c
:eof
) (char= c
#\newline
))
481 (values (if (null res
) eof-value
(coerce (nreverse res
) 'string
))
484 (values (coerce (nreverse res
) 'string
)
488 (defmethod g/read-line
* ((stream t
) &optional
(eof-error-p t
) eof-value
)
489 ;; Like read-line, but accepts CRNL, NL, CR as line termination
491 (do ((c (g/read-char stream eof-error-p
:eof
)
492 (g/read-char stream nil
:eof
)))
493 ((or (eq c
:eof
) (char= c
#\newline
) (char= c
#\return
))
495 (values (if (null res
) eof-value
(coerce (nreverse res
) 'string
))
498 (when (char= c
#\return
)
499 (let ((d (g/read-char stream nil
:eof
)))
500 (unless (or (eq d
:eof
) (char= d
#\newline
))
501 (g/unread-char d stream
))))
502 (values (coerce (nreverse res
) 'string
)
506 (defmethod g/read-byte-sequence
(sequence (input t
) &key
(start 0) (end (length sequence
)))
511 (setf c
(g/read-byte input nil
:eof
))
514 (setf (elt sequence i
) c
)
517 (defmethod g/read-char-sequence
(sequence (input t
) &key
(start 0) (end (length sequence
)))
522 (setf c
(g/read-char input nil
:eof
))
525 (setf (elt sequence i
) c
)
528 (defmethod g/write-byte-sequence
(sequence (sink t
) &key
(start 0) (end (length sequence
)))
529 (do ((i start
(+ i
1)))
531 (g/write-byte
(aref sequence i
) sink
)))
533 ;;; ----------------------------------------------------------------------------------------------------
539 (defclass vector-output-stream
(use-byte-for-char-stream-flavour)
540 ((buffer :initarg
:buffer
)))
542 (defun g/make-vector-output-stream
(&key
(initial-size 100))
543 (make-instance 'vector-output-stream
544 :buffer
(make-array initial-size
:element-type
'(unsigned-byte 8)
548 (defmethod g/close
((self vector-output-stream
) &key abort
)
549 (declare (ignorable self abort
))
552 (defmethod g/finish-output
((self vector-output-stream
))
555 (defmethod g/write-byte
(byte (self vector-output-stream
))
556 (with-slots (buffer) self
557 (vector-push-extend byte buffer
100)))
559 (defmethod g/write-byte-sequence
(sequence (self vector-output-stream
) &key
(start 0) (end (length sequence
)))
560 (with-slots (buffer) self
561 (adjust-array buffer
(+ (length buffer
) (- end start
)))
562 (replace buffer sequence
:start1
(length buffer
) :start2 start
:end2 end
)
563 (setf (fill-pointer buffer
) (+ (length buffer
) (- end start
)))
566 ;;; ----------------------------------------------------------------------------------------------------
570 (defclass echo-stream
(use-byte-for-char-stream-flavour)
571 ((echoed-to :initarg
:echoed-to
)))
573 (defun g/make-echo-stream
(echoed-to)
574 (make-instance 'echo-stream
:echoed-to echoed-to
))
579 Hmm unter PCL geht das nicht
;-(
581 (defmethod g/read-byte
((stream stream
) &optional
(eof-error-p t
) eof-value
)
582 (read-byte stream eof-error-p eof-value
))
584 (defmethod g/read-char
((stream stream
) &optional
(eof-error-p t
) eof-value
)
585 (read-char stream eof-error-p eof-value
))
587 (defmethod g/unread-char
(char (stream stream
))
588 (unread-char char stream
))
590 (defmethod g/write-char
(char (stream stream
))
591 (write-char char stream
))
593 (defmethod g/write-byte
(byte (stream stream
))
594 (write-byte byte stream
))
596 (defmethod g/finish-output
((stream stream
))
597 (finish-output stream
))
599 (defmethod g/close
((stream stream
) &key abort
)
600 (close stream
:abort abort
))
604 ;;;; ----------------------------------------------------------------------------------------------------
607 (let ((null (make-symbol "NULL")))
609 (defstruct (future (:print-function print-future
))
613 (defun print-future (self sink depth
)
614 (if (eq (future-value self
) null
)
615 (format sink
"#<~S unpredicted>" (type-of self
))
616 (if (and *print-level
* (>= depth
*print-level
*))
617 (format sink
"#<~S predicted as ...>" (type-of self
))
618 (format sink
"#<~S predicted as ~S>" (type-of self
) (future-value self
)))))
623 (defun guess (future)
624 (when (eq (future-value future
) null
)
625 (setf (future-awaited-by future
) (mp/current-process
))
626 (mp/process-wait
"Awaiting future" (lambda () (not (eq (future-value future
) null
))))
627 (setf (future-awaited-by future
) nil
))
628 (future-value future
))
630 (defun predict (future value
)
631 (setf (future-value future
) value
)
632 (let ((aw (future-awaited-by future
)))
633 (when aw
(mp/process-allow-schedule aw
)))
638 (defun map-array (fun array
&rest make-array-options
)
639 (let ((res (apply #'make-array
(array-dimensions array
) make-array-options
)))
640 (dotimes (i (array-total-size array
))
641 (setf (row-major-aref res i
) (funcall fun
(row-major-aref array i
))))
644 ;;----------------------------------------------------------------------------------------------------
646 (defun g/peek-char
(&optional
(peek-type nil
) (source *standard-input
*)
647 (eof-error-p T
) eof-value
)
648 (cond ((eq peek-type T
)
649 (do ((ch (g/read-char source eof-error-p
'%the-eof-object%
)
650 (g/read-char source eof-error-p
'%the-eof-object%
)))
651 ((or (eq ch
'%the-eof-object%
)
652 (not (white-space-p ch
)))
653 (cond ((eq ch
'%the-eof-object%
) eof-value
)
654 (t (g/unread-char ch source
) ch
)) )))
656 (let ((ch (g/read-char source eof-error-p
'%the-eof-object%
)))
657 (cond ((eq ch
'%the-eof-object%
) eof-value
)
658 (t (g/unread-char ch source
)
660 ((characterp peek-type
)
661 (do ((ch (g/read-char source eof-error-p
'%the-eof-object%
)
662 (g/read-char source eof-error-p
'%the-eof-object%
)))
663 ((or (eq ch
'%the-eof-object%
) (eql ch peek-type
))
664 (cond ((eq ch
'%the-eof-object%
) eof-value
)
665 (t (g/unread-char ch source
) ch
)) )) ) ))
669 (defun cl-byte-stream->gstream
(stream)
670 (make-instance 'cl-byte-stream
:cl-stream stream
))
672 (defun cl-char-stream->gstream
(stream)
673 (make-instance 'cl-char-stream
:cl-stream stream
))
675 ;;; ----------------------------------------------------------------------------------------------------
677 (defvar *all-temporary-files
* nil
678 "List of all temporary files.")
680 (defun find-temporary-file (&key
(type nil
))
681 (let ((temp-dir "/tmp/*") ;since Motif is only available on unix, we subtly assume a unix host.
683 (labels ((invent-name ()
684 (merge-pathnames (make-pathname
687 (let ((*print-base
* 35))
688 (format nil
"ws_~S" (random (expt 36 7)))))
691 (do ((name (invent-name) (invent-name)))
692 ((setq stream
(open name
:direction
:output
:if-exists nil
))
693 (push name
*all-temporary-files
*) ;remember this file
698 (defun delete-temporary-file (filename)
699 (setf *all-temporary-files
* (delete filename
*all-temporary-files
*))
700 (ignore-errors (delete-file filename
)))
702 (defmacro with-temporary-file
((name-var &key type
) &body body
)
703 (let ((name (gensym)))
704 `(let* ((,name
(find-temporary-file :type
,type
))
708 (when (open ,name
:direction
:probe
)
709 (delete-temporary-file ,name
)))) ))
713 (defun set-equal (x y
&rest options
)
714 (null (apply #'set-exclusive-or x y options
)))
718 (defun maybe-parse-integer (string &key
(radix 10))
719 (cond ((not (stringp string
)) nil
)
721 (let ((len (length string
)))
722 (cond ((= len
0) nil
)
727 (cond ((and (> len
1) (char= (char string
0) #\
+))
729 ((and (> len
1) (char= (char string
0) #\-
))
732 (do ((i start
(+ i
1)))
733 ((= i len
) (* vz res
))
734 (let ((d (digit-char-p (char string i
) radix
)))
736 (setf res
(+ (* radix res
) d
))
737 (return nil
)))))))))))
741 (defun nop (&rest ignore
)
742 (declare (ignore ignore
))
745 (defmacro with-structure-slots
((type &rest slots
) obj
&body body
)
746 ;; Something like 'with-slots' but for structures. Assumes that the structure
747 ;; slot accessors have the default name. Note that the structure type must
749 (let ((obj-var (make-symbol "OBJ")))
750 `(LET ((,obj-var
,obj
))
751 (SYMBOL-MACROLET ,(mapcar (lambda (slot)
753 `(,(intern (concatenate 'string
(symbol-name type
) "-" (symbol-name slot
))
754 (symbol-package type
))
759 ;;;; ----------------------------------------------------------------------------------------------------
761 ;; Wir helfen den Compiler mal etwas auf die Spruenge ...
762 (defun compile-funcall (fn args
)
763 (cond ((eq fn
'#'identity
)
767 ((and (consp fn
) (eq (car fn
) 'function
))
768 `(,(cadr fn
) .
,args
))
769 ((and (consp fn
) (eq (car fn
) 'lambda
))
771 ((and (consp fn
) (eq (car fn
) 'curry
))
772 (compile-funcall (cadr fn
) (append (cddr fn
) args
)))
773 ((and (consp fn
) (eq (car fn
) 'rcurry
))
774 (compile-funcall (cadr fn
) (append args
(cddr fn
))))
776 (warn "Unable to inline funcall to ~S." fn
)
777 `(funcall ,fn .
,args
)) ))
779 (defmacro funcall
* (fn &rest args
)
780 (compile-funcall fn args
))
782 ;; Ich mag mapc viel lieber als dolist, nur viele Compiler optimieren
783 ;; das nicht, deswegen das Macro hier. Einige Compiler haben auch kein
784 ;; DEFINE-COMPILER-MACRO :-(
786 (defmacro mapc
* (fn list
)
789 ,(compile-funcall fn
(list g
)))))
791 ;; Das gleiche mit REDUCE und MAPCAR.
793 ;; REDUCE arbeitet sowohl fuer Vectoren als auch fuer Listen. Wir
794 ;; haben allerdings leider keinen vernuenftigen Zugriff auf
795 ;; Deklarationen; Man koennte mit TYPEP herangehen und hoffen, dass
796 ;; der Compiler das optimiert, ich fuerchte aber dass das nicht
797 ;; funktionieren wird. Und CLISP verwirft Deklarationen ja total. Also
798 ;; zwei Versionen: LREDUCE* und VREDUCE*
800 (defmacro vreduce
* (fun seq
&rest rest
&key
(key '#'identity
) from-end start end
801 (initial-value nil initial-value?
))
802 (declare (ignore rest
))
803 (let (($start
(make-symbol "start"))
804 ($end
(make-symbol "end"))
805 ($i
(make-symbol "i"))
806 ($accu
(make-symbol "accu"))
807 ($seq
(make-symbol "seq")))
809 (cond (initial-value?
811 (,$start
,(or start
0))
812 (,$end
,(or end
`(LENGTH ,$seq
)))
813 (,$accu
,initial-value
))
814 (DECLARE (TYPE FIXNUM
,$start
,$end
))
815 (DO ((,$i
(- ,$end
1) (THE FIXNUM
(- ,$i
1))))
816 ((< ,$i
,$start
) ,$accu
)
817 (DECLARE (TYPE FIXNUM
,$i
))
818 (SETF ,$accu
(FUNCALL* ,fun
(FUNCALL* ,key
(AREF ,$seq
,$i
)) ,$accu
)) )))
821 (,$start
,(or start
0))
822 (,$end
,(or end
`(LENGTH ,$seq
))))
823 (DECLARE (TYPE FIXNUM
,$start
,$end
))
824 (COND ((= 0 (- ,$end
,$start
))
827 (LET ((,$accu
(FUNCALL* ,key
(AREF ,$seq
(- ,$end
1)))))
828 (DO ((,$i
(- ,$end
2) (THE FIXNUM
(- ,$i
1))))
829 ((< ,$i
,$start
) ,$accu
)
830 (DECLARE (TYPE FIXNUM
,$i
))
831 (SETF ,$accu
(FUNCALL* ,fun
(FUNCALL* ,key
(AREF ,$seq
,$i
)) ,$accu
)))))))) ))
833 (cond (initial-value?
835 (,$start
,(or start
0))
836 (,$end
,(or end
`(LENGTH ,$seq
)))
837 (,$accu
,initial-value
))
838 (DECLARE (TYPE FIXNUM
,$start
,$end
))
839 (DO ((,$i
,$start
(THE FIXNUM
(+ ,$i
1))))
840 ((>= ,$i
,$end
) ,$accu
)
841 (DECLARE (TYPE FIXNUM
,$i
))
842 (SETF ,$accu
(FUNCALL* ,fun
,$accu
(FUNCALL* ,key
(AREF ,$seq
,$i
)))) )))
845 (,$start
,(or start
0))
846 (,$end
,(or end
`(LENGTH ,$seq
))))
847 (DECLARE (TYPE FIXNUM
,$start
,$end
))
848 (COND ((= 0 (- ,$end
,$start
))
851 (LET ((,$accu
(FUNCALL* ,key
(AREF ,$seq
,$start
))))
852 (DO ((,$i
(+ ,$start
1) (+ ,$i
1)))
853 ((>= ,$i
,$end
) ,$accu
)
854 (DECLARE (TYPE FIXNUM
,$i
))
855 (SETF ,$accu
(FUNCALL* ,fun
,$accu
(FUNCALL* ,key
(AREF ,$seq
,$i
)))))))))))))))
857 (defmacro lreduce
* (fun seq
&rest rest
&key
(key '#'identity
) from-end start end
858 (initial-value nil initial-value?
))
859 (cond ((or start end from-end
)
860 `(reduce ,fun
,seq .
,rest
))
862 (cond (initial-value?
863 (let (($accu
(make-symbol "accu"))
864 ($k
(make-symbol "k")))
865 `(LET* ((,$accu
,initial-value
))
866 (DOLIST (,$k
,seq
,$accu
)
867 (SETF ,$accu
(FUNCALL* ,fun
,$accu
(FUNCALL* ,key
,$k
)))))))
869 (let (($accu
(make-symbol "accu"))
870 ($seq
(make-symbol "seq"))
871 ($k
(make-symbol "k")))
872 `(LET* ((,$seq
,seq
))
875 (LET ((,$accu
(FUNCALL* ,key
(CAR ,$seq
))))
876 (DOLIST (,$k
(CDR ,$seq
) ,$accu
)
877 (SETF ,$accu
(FUNCALL* ,fun
,$accu
(FUNCALL* ,key
,$k
)))))))) ))) ))
880 ;;; Wenn wir so weiter machen, koennen wir bald gleich unseren eigenen
881 ;;; Compiler schreiben ;-)
884 (defmacro lreduce
* (fun seq
&rest x
&key key
&allow-other-keys
)
885 (let ((q (copy-list x
)))
888 `(reduce ,fun
(map 'vector
,key
,seq
) .
,q
))
890 `(reduce ,fun
,seq .
,q
)))))
892 (defmacro vreduce
* (fun seq
&rest x
&key key
&allow-other-keys
)
893 (let ((q (copy-list x
)))
896 `(reduce ,fun
(map 'vector
,key
,seq
) .
,q
))
898 `(reduce ,fun
,seq .
,q
)))))
902 ;; Stolen from Eclipse (http://elwoodcorp.com/eclipse/unique.htm
904 (defmacro with-unique-names
((&rest names
) &body body
)
905 `(let (,@(mapcar (lambda (x) (list x
`(gensym ',(concatenate 'string
(symbol-name x
) "-")))) names
))
909 (defun gstream-as-string (gstream &optional
(buffer-size 4096))
910 (let ((buffer (g/make-string buffer-size
:adjustable t
)))
912 (j (g/read-char-sequence buffer gstream
:start
0 :end buffer-size
)
913 (g/read-char-sequence buffer gstream
:start i
:end
(+ i buffer-size
)) ))
914 ((= j i
) (subseq buffer
0 j
))
915 (adjust-array buffer
(list (+ j buffer-size
))) )))
917 ;;;; Generic hash tables
920 ;; - automatic size adjustment
921 ;; - sensible printer
922 ;; - make-load-form?!
924 (defstruct g
/hash-table
925 hash-function
;hash function
926 compare-function
;predicate to test for equality
927 table
;simple vector of chains
928 size
;size of hash table
929 (nitems 0)) ;number of items
931 (defun g/make-hash-table
(&key
(size 100) (hash-function #'sxhash
) (compare-function #'eql
))
932 "Creates a generic hashtable;
933 `size' is the default size of the table.
934 `hash-function' (default #'sxhash) is a specific hash function
935 `compare-function' (default #'eql) is a predicate to test for equality."
936 (setf size
(nearest-greater-prime size
))
937 (make-g/hash-table
:hash-function hash-function
938 :compare-function compare-function
939 :table
(make-array size
:initial-element nil
)
943 (defun g/hashget
(hashtable key
&optional
(default nil
))
944 "Looks up the key `key' in the generic hash table `hashtable'.
945 Returns three values:
946 value - value, which as associated with the key, or `default' is no value
948 successp - true, iff the key was found.
949 key - the original key in the hash table."
950 ;; -> value ; successp ; key
951 (let ((j (mod (funcall (g/hash-table-hash-function hashtable
) key
)
952 (g/hash-table-size hashtable
))))
953 (let ((q (assoc key
(aref (g/hash-table-table hashtable
) j
)
954 :test
(g/hash-table-compare-function hashtable
))))
956 (values (cdr q
) t
(car q
))
957 (values default nil
)))))
959 (defun (setf g
/hashget
) (new-value hashtable key
&optional
(default nil
))
960 (declare (ignore default
))
961 (let ((j (mod (funcall (g/hash-table-hash-function hashtable
) key
)
962 (g/hash-table-size hashtable
))))
963 (let ((q (assoc key
(aref (g/hash-table-table hashtable
) j
)
964 :test
(g/hash-table-compare-function hashtable
))))
965 (cond ((not (null q
))
966 (setf (cdr q
) new-value
))
968 (push (cons key new-value
)
969 (aref (g/hash-table-table hashtable
) j
))
970 (incf (g/hash-table-nitems hashtable
))))))
973 (defun resize-hash-table (hashtable new-size
)
974 "Adjust the size of a generic hash table. (the size is round to the next greater prime number)."
975 (setf new-size
(nearest-greater-prime new-size
))
976 (let ((new-table (make-array new-size
:initial-element nil
)))
977 (dotimes (i (g/hash-table-size hashtable
))
978 (dolist (k (aref (g/hash-table-table hashtable
) i
))
979 (push k
(aref new-table
980 (mod (funcall (g/hash-table-hash-function hashtable
) (car k
))
982 (setf (g/hash-table-table hashtable
) new-table
983 (g/hash-table-size hashtable
) new-size
)
986 (defun g/clrhash
(hashtable)
987 "Clears a generic hash table."
988 (dotimes (i (g/hash-table-size hashtable
))
989 (setf (aref (g/hash-table-table hashtable
) i
) nil
))
990 (setf (g/hash-table-nitems hashtable
) nil
)
993 ;; hash code utilities
995 (defconstant +fixnum-bits
+
996 (1- (integer-length most-positive-fixnum
))
997 "Pessimistic approximation of the number of bits of fixnums.")
999 (defconstant +fixnum-mask
+
1000 (1- (expt 2 +fixnum-bits
+))
1001 "Pessimistic approximation of the largest bit-mask, still being a fixnum.")
1003 (defun stir-hash-codes (a b
)
1004 "Stirs two hash codes together; always returns a fixnum.
1005 When applied sequenitally the first argument should be used as accumulator."
1006 ;; ich mach das mal wie Bruno
1007 (logand +fixnum-mask
+
1008 (logxor (logior (logand +fixnum-mask
+ (ash a
5))
1009 (logand +fixnum-mask
+ (ash a
(- 5 +fixnum-bits
+))))
1012 (defun hash-sequence (sequence hash-function
&optional
(accu 0))
1013 "Applies the hash function `hash-function' to each element of `sequence' and
1014 stirs the resulting hash codes together using STIR-HASH-CODE starting from
1016 (map nil
(lambda (item)
1017 (setf accu
(stir-hash-codes accu
(funcall hash-function item
))))
1021 ;; some specific hash functions
1023 (defun hash/string-equal
(string)
1024 "Hash function compatible with STRING-EQUAL."
1025 (hash-sequence string
(lambda (char)
1026 (sxhash (char-upcase char
)))))
1028 ;; some specific hash tables
1030 (defun make-string-equal-hash-table (&rest options
)
1031 "Constructs a new generic hash table using STRING-EQUAL as predicate."
1032 (apply #'g
/make-hash-table
1033 :hash-function
#'hash
/string-equal
1034 :compare-function
#'string-equal
1040 "Returns true, iff `n' is prime."
1044 (cond ((zerop (mod n i
)) (return nil
))))))
1046 (defun nearest-greater-prime (n)
1047 "Returns the smallest prime number no less than `n'."
1048 (cond ((primep n
) n
)
1049 ((nearest-greater-prime (+ n
1)))))
1054 (defun grind-documentation-string (string &optional
(sink *standard-output
*))
1058 ;; frobinates its two arguments.")
1062 ;; frobinates its two arguments.")
1064 (let ((min-indention nil
))
1065 ;; We sort this out by finding the minimum indent in all but the first line.
1066 (with-input-from-string (in string
)
1067 (read-line in nil nil
) ;ignore first line
1068 (do ((x (read-line in nil nil
) (read-line in nil nil
)))
1070 (let ((p (position-if-not (curry #'char
= #\space
) x
)))
1072 (setf min-indention
(min* min-indention p
))))))
1073 (setf min-indention
(or min-indention
0))
1074 ;; Now we could dump the string
1075 (with-input-from-string (in string
)
1076 ;; first line goes unindented
1077 (let ((x (read-line in nil nil
)))
1080 (write-string x sink
)))
1081 (do ((x (read-line in nil nil
) (read-line in nil nil
)))
1084 (when (< min-indention
(length x
))
1085 (write-string x sink
:start min-indention
)))))
1088 (defun ap (&rest strings
)
1091 (do-all-symbols (symbol)
1092 (unless (member symbol res
)
1093 (when (every (lambda (string)
1094 (search string
(symbol-name symbol
)))
1096 (push symbol res
))))
1100 (princ ", function"))
1102 (princ ", variable"))