home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-09-27 | 12.2 KB | 468 lines | [TEXT/CCL2] |
- ;;; utils.scm -- utility functions
- ;;;
- ;;; author : Sandra Loosemore
- ;;; date : 18 Nov 1991
- ;;;
- ;;; This file contains miscellaneous functions that are generally useful.
- ;;; If you find some missing feature from the base language, this is
- ;;; a good place to put it. Common Lisp-style sequence functions are
- ;;; an example of the sort of thing found here.
-
-
- ;;;=====================================================================
- ;;; Sequence functions
- ;;;=====================================================================
-
- (define (vector-replace to-vec from-vec to start end)
- (declare (type fixnum to start end)
- (type vector to-vec from-vec))
- (if (and (eq? to-vec from-vec)
- (> to start))
- ;; Right shift in place
- (do ((from (1- end) (1- from))
- (to (1- (+ to (- end start)))))
- ((< from start) to-vec)
- (declare (type fixnum from to))
- (setf (vector-ref to-vec to) (vector-ref from-vec from))
- (decf to))
- ;; Normal case, left-to-right
- (do ((from start (1+ from)))
- ((= from end) to-vec)
- (declare (type fixnum from))
- (setf (vector-ref to-vec to) (vector-ref from-vec from))
- (incf to))))
-
- (define (string-replace to-vec from-vec to start end)
- (declare (type fixnum to start end)
- (type string to-vec from-vec))
- (if (and (eq? to-vec from-vec)
- (> to start))
- ;; Right shift in place
- (do ((from (1- end) (1- from))
- (to (1- (+ to (- end start)))))
- ((< from start) to-vec)
- (declare (type fixnum from to))
- (setf (string-ref to-vec to) (string-ref from-vec from))
- (decf to))
- ;; Normal case, left-to-right
- (do ((from start (1+ from)))
- ((= from end) to-vec)
- (declare (type fixnum from))
- (setf (string-ref to-vec to) (string-ref from-vec from))
- (incf to))))
-
- (define (string-fill string c start end)
- (declare (type fixnum start end)
- (type string string)
- (type char c))
- (do ((i start (1+ i)))
- ((= i end) string)
- (declare (type fixnum i))
- (setf (string-ref string i) c)))
-
- (define (string-position c string start end)
- (declare (type fixnum start end)
- (type string string)
- (type char c))
- (cond ((= start end) '#f)
- ((char=? (string-ref string start) c) start)
- (else
- (string-position c string (1+ start) end))))
-
- (define (string-position-not-from-end c string start end)
- (declare (type fixnum start end)
- (type string string)
- (type char c))
- (cond ((= start end) '#f)
- ((not (char=? (string-ref string (setf end (1- end))) c))
- end)
- (else
- (string-position-not-from-end c string start end))))
-
- (define (string-nreverse string start end)
- (declare (type fixnum start end)
- (type string string))
- (do ((i start (1+ i))
- (j (1- end) (1- j)))
- ((not (< i j)) string)
- (declare (type fixnum i j))
- (let ((c (string-ref string i)))
- (setf (string-ref string i) (string-ref string j))
- (setf (string-ref string j) c))))
-
-
- (define (string-starts? s1 s2) ; true is s1 begins s2
- (and (>= (string-length s2) (string-length s1))
- (string=? s1 (substring s2 0 (string-length s1)))))
-
-
- ;;;=====================================================================
- ;;; Table utilities
- ;;;=====================================================================
-
-
- (define (table->list table)
- (let ((l '()))
- (table-for-each
- (lambda (key val) (push (cons key val) l)) table)
- l))
-
- (define (list->table l)
- (let ((table (make-table)))
- (dolist (p l)
- (setf (table-entry table (car p)) (cdr p)))
- table))
-
-
-
- ;;;=====================================================================
- ;;; Tuple utilities
- ;;;=====================================================================
-
- ;;; For future compatibility with a typed language, define 2 tuples with
- ;;; a few functions: (maybe add 3 tuples someday!)
-
- (define-integrable (tuple x y)
- (cons x y))
-
- (define-integrable (tuple-2-1 x) (car x)) ; Flic-like notation
- (define-integrable (tuple-2-2 x) (cdr x))
-
- (define (map-tuple-2-1 f l)
- (map (lambda (x) (tuple (funcall f (tuple-2-1 x)) (tuple-2-2 x))) l))
-
- (define (map-tuple-2-2 f l)
- (map (lambda (x) (tuple (tuple-2-1 x) (funcall f (tuple-2-2 x)))) l))
-
-
- ;;;=====================================================================
- ;;; List utilities
- ;;;=====================================================================
-
- ;;; This does an assq using the second half of the tuple as the key.
-
- (define (rassq x l)
- (if (null? l)
- '#f
- (if (eq? x (tuple-2-2 (car l)))
- (car l)
- (rassq x (cdr l)))))
-
- ;;; This is an assoc with an explicit test
-
- (define (assoc/test test-fn x l)
- (if (null? l)
- '#f
- (if (funcall test-fn x (tuple-2-1 (car l)))
- (car l)
- (assoc/test test-fn x (cdr l)))))
-
-
-
-
- ;;; Stupid position function works only on lists, uses eqv?
-
- (define (position item list)
- (position-aux item list 0))
-
- (define (position-aux item list index)
- (declare (type fixnum index))
- (cond ((null? list)
- '#f)
- ((eqv? item (car list))
- index)
- (else
- (position-aux item (cdr list) (1+ index)))
- ))
-
-
- ;;; Destructive delete-if function
-
- (define (list-delete-if f l)
- (list-delete-if-aux f l l '#f))
-
- (define (list-delete-if-aux f head next last)
- (cond ((null? next)
- ;; No more elements.
- head)
- ((not (funcall f (car next)))
- ;; Leave this element and do the next.
- (list-delete-if-aux f head (cdr next) next))
- (last
- ;; Delete element from middle of list.
- (setf (cdr last) (cdr next))
- (list-delete-if-aux f head (cdr next) last))
- (else
- ;; Delete element from head of list.
- (list-delete-if-aux f (cdr next) (cdr next) last))))
-
- ;;; filter is a non-destructive version of delete
-
- (define (filter f l)
- (if (null? l)
- '()
- (if (funcall f (car l))
- (cons (car l) (filter f (cdr l)))
- (filter f (cdr l)))))
-
- ;;; Same as the haskell function
-
- (define (concat lists)
- (if (null? lists)
- '()
- (append (car lists) (concat (cdr lists)))))
-
-
- ;;; This is a quick & dirty list sort function.
-
- (define (sort-list l compare-fn)
- (if (or (null? l) (null? (cdr l)))
- l
- (insert-sorted compare-fn (car l) (sort-list (cdr l) compare-fn))))
-
- (define (insert-sorted compare-fn e l)
- (if (null? l)
- (list e)
- (if (funcall compare-fn e (car l))
- (cons e l)
- (cons (car l) (insert-sorted compare-fn e (cdr l))))))
-
- (define (find-duplicates l)
- (cond ((null? l)
- '())
- ((memq (car l) (cdr l))
- (cons (car l)
- (find-duplicates (cdr l))))
- (else (find-duplicates (cdr l)))))
-
- ;;; A simple & slow topsort routine.
- ;;; Input: A list of lists. Each list is a object consed onto the
- ;;; list of objects it preceeds.
- ;;; Output: Two values: SORTED / CYCLIC & a list of either sorted objects
- ;;; or a set of components containing the cycle.
-
- (define (topsort l)
- (let ((changed? '#t)
- (sorted '())
- (next '()))
- (do () ((not changed?)
- (if (null? next)
- (values 'sorted (nreverse sorted))
- (values 'cyclic (map (function car) next))))
- (setf changed? '#f)
- (setf next '())
- (dolist (x l)
- (cond ((topsort-aux (cdr x) sorted)
- (push (car x) sorted)
- (setf changed? '#t))
- (else
- (push x next))))
- (setf l next))))
-
-
- ;;; Returns true if x doesn't contain any elements that aren't in sorted.
- ;;; equivalent to (null? (set-intersection x sorted)), but doesn't cons
- ;;; and doesn't traverse the whole list in the failure case.
-
- (define (topsort-aux x sorted)
- (cond ((null? x)
- '#t)
- ((memq (car x) sorted)
- (topsort-aux (cdr x) sorted))
- (else
- '#f)))
-
- (define (set-intersection s1 s2)
- (if (null? s1)
- '()
- (let ((rest (set-intersection (cdr s1) s2)))
- (if (memq (car s1) s2)
- (cons (car s1) rest)
- rest))))
-
- ;;; remove s2 elements from s1
-
- (define (set-difference s1 s2)
- (if (null? s1)
- '()
- (let ((rest (set-difference (cdr s1) s2)))
- (if (memq (car s1) s2)
- rest
- (cons (car s1) rest)))))
-
-
- (define (set-union s1 s2)
- (if (null? s2)
- s1
- (if (memq (car s2) s1)
- (set-union s1 (cdr s2))
- (cons (car s2) (set-union s1 (cdr s2))))))
-
-
- ;;; Destructive list splitter
-
- (define (split-list list n)
- (declare (type fixnum n))
- (let ((tail1 (list-tail list (1- n))))
- (if (null? tail1)
- (values list '())
- (let ((tail2 (cdr tail1)))
- (setf (cdr tail1) '())
- (values list tail2)))))
-
-
- ;;; Some string utils
-
- (define (mem-string s l)
- (and (not (null? l)) (or (string=? s (car l))
- (mem-string s (cdr l)))))
-
- (define (ass-string k l)
- (cond ((null? l)
- '#f)
- ((string=? k (caar l))
- (car l))
- (else
- (ass-string k (cdr l)))))
-
-
- ;;;=====================================================================
- ;;; Syntax extensions
- ;;;=====================================================================
-
- ;;; The mlet macro combines let* and multiple-value-bind into a single
- ;;; syntax.
-
- (define-syntax (mlet binders . body)
- (mlet-body binders body))
-
- (define (mlet-body binders body)
- (if (null? binders)
- `(begin ,@body)
- (let* ((b (car binders))
- (var (car b))
- (init (cadr b))
- (inner-body (mlet-body (cdr binders) body)))
- (if (pair? var)
- (multiple-value-bind (new-vars ignore-decl)
- (remove-underlines var)
- `(multiple-value-bind ,new-vars
- ,init ,@ignore-decl ,inner-body))
- `(let ((,var ,init)) ,inner-body)))))
-
- (define (remove-underlines vars)
- (if (null? vars)
- (values '() '())
- (multiple-value-bind (rest ignore-decl) (remove-underlines (cdr vars))
- (if (not (eq? (car vars) '_))
- (values (cons (car vars) rest) ignore-decl)
- (let ((var (gensym)))
- (values (cons var rest)
- `((declare (ignore ,var)) ,@ignore-decl)))))))
-
-
-
-
- ;;;=====================================================================
- ;;; Other utilities
- ;;;=====================================================================
-
- (define (add-extension name ext)
- (assemble-filename (filename-place name) (filename-name name) ext))
-
- (define (time-execution thunk)
- (let* ((start-time (get-run-time))
- (res (funcall thunk))
- (end-time (get-run-time)))
- (values res (- end-time start-time))))
-
- (define (pprint-flatten code . maybe-port)
- (pprint-flatten-aux
- code
- (if (null? maybe-port) (current-output-port) (car maybe-port))))
-
- (define (pprint-flatten-aux code port)
- (if (and (pair? code)
- (eq? (car code) 'begin))
- (dolist (c (cdr code))
- (pprint-flatten-aux c port))
- (pprint*-aux code port)))
-
- (define (print-flatten code port)
- (if (and (pair? code)
- (eq? (car code) 'begin))
- (dolist (c (cdr code))
- (print-flatten c port))
- (begin
- (internal-write code port)
- (internal-newline port))))
-
-
- ;;; Like pprint, but print newline after instead of before.
-
- (define (pprint* object . maybe-port)
- (pprint*-aux
- object
- (if (null? maybe-port) (current-output-port) (car maybe-port))))
-
- (define (pprint*-aux object port)
- (dynamic-let ((*print-pretty* '#t))
- (prin1 object port))
- (terpri port))
-
- ;;; This reads stuff from a string. (Better error checks needed!)
-
- (define (read-lisp-object str)
- (call-with-input-string str (lambda (port) (read port))))
-
- ;;; This generates a list of distinct symbols
-
- (define (gen-temp-names l)
- (gen-temp-names-1 l '(A B C D E F G H I J K L M N O P Q R S)))
-
- (define (gen-temp-names-1 l1 l2)
- (if (null? l1)
- '()
- (if (null? l2)
- (gen-temp-names-1 l1 (list (gensym "T")))
- (cons (car l2) (gen-temp-names-1 (cdr l1) (cdr l2))))))
-
- ;;; This is support for printing error messages. This returns a string.
- ;;; If the object cannot be printed within the given width it is surrounded by
- ;;; new-lines.
-
- (define (format-sized obj size nl?)
- (let ((r1 (format '#f (if nl? "~A~%" "~A ") obj)))
- (if (<= (string-length r1) size)
- r1
- (block exit
- (dolist (lev '(#f 4 3 2))
- (let ((r (pretty-print-to-string obj lev)))
- (when (or (eqv? lev 2) (< (string-length r) 300))
- (return-from exit r))))))))
-
- (define (pretty-print-to-string obj lev)
- (dynamic-let ((*print-pretty* '#t)
- (*print-level* lev))
- (format '#f "~%~A~%" obj)))
-
- (define (show-symbol-list l)
- (show-symbol-list-1 l '#f))
-
- (define (show-symbol-list/no-downcase l)
- (show-symbol-list-1 l '#t))
-
- (define (show-symbol-list-1 l dc?)
- (call-with-output-string
- (lambda (p)
- (let ((s '#f))
- (dolist (l1 l)
- (if s
- (write-string ", " p)
- (setf s '#t))
- (write-string
- (if dc? (string-downcase (symbol->string l1)) (symbol->string l1))
- p))))))
-
-
-