/[meta-cvs]/meta-cvs/F-5AD8C72020BEB5748163790EE9832EC7.lisp
ViewVC logotype

Contents of /meta-cvs/F-5AD8C72020BEB5748163790EE9832EC7.lisp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.13 - (show annotations)
Sun Jul 14 19:47:41 2002 UTC (11 years, 9 months ago) by kaz
Branch: MAIN
CVS Tags: mcvs-0-24, mcvs-0-20, symlink-branch~branch-point, mcvs-0-22, mcvs-0-23, mcvs-0-21, mcvs-0-95, mcvs-0-96, mcvs-0-19, symlink-branch~merged-to-HEAD-0
Branch point for: symlink-branch
Changes since 1.12: +0 -5 lines
Get rid of unused struct type fb-match-info.
1 ;;; This source file is part of the Meta-CVS program,
2 ;;; which is distributed under the GNU license.
3 ;;; Copyright 2002 Kaz Kylheku
4
5 (provide "find-bind")
6
7 (defmacro vector-bind (vars vec &rest forms)
8 (do ((i 0 (1+ i))
9 (var vars (rest var))
10 (list))
11 ((null var) `(let ,(nreverse list) ,@forms))
12 (push `(,(first var) (aref ,vec ,i)) list)))
13
14 (defun find-bind-extract-vals (key-vec default-vec sequence
15 test-func key-func take-func
16 &key remainder-p)
17 "This is an internal function that performs the sequence processing
18 that underlies the find-bind macro."
19 (let ((unique '#:unique)
20 (remainder))
21 (macrolet ((process-item (item-place remainder-save-form)
22 `(let* ((item (funcall key-func ,item-place))
23 (match (position item key-vec
24 :test (lambda (x y)
25 (cond
26 ((eq x unique) nil)
27 ((eq y unique) nil)
28 (t (funcall test-func
29 x y)))))))
30 (cond
31 (match
32 (setf (aref default-vec match)
33 (funcall take-func ,item-place))
34 (setf (aref key-vec match) unique))
35 (t (when remainder-p ,remainder-save-form))))))
36 (typecase sequence
37 (list
38 (dolist (element sequence)
39 (process-item element (push element remainder)))
40 (setf remainder (nreverse remainder)))
41 (vector
42 (setf remainder (make-array (list (length sequence)) :fill-pointer 0))
43 (dotimes (i (length sequence))
44 (process-item (aref sequence i)
45 (vector-push (aref sequence i) remainder))))
46 (otherwise
47 (error "FIND-BIND: value ~s specified as SEQUENCE parameter.~%"
48 sequence))))
49 (values default-vec remainder)))
50
51 (defmacro find-bind ((&key (test '#'eql)
52 (key '#'values)
53 (take '#'values))
54 (remainder &rest var-specs)
55 sequence &body forms)
56 "Slick macro for binding variables to elements of a sequence
57 by matching keys.
58
59 Syntax:
60
61 find-bind ({:test test-func} {:key key-func} {:take take-func})
62 ({rem-var} {(var key {default-value})}*)
63 sequence {decl}* {form}*
64
65 Arguments:
66
67 var A symbol naming a variable to be bound.
68 key A value to be sought after in the input sequence.
69 default-value Optional value to bind to the variable if a match
70 is not found, or the variable would otherwise be
71 bound to the value NIL.
72 rem-var A symbol naming the variable to be bound to
73 a new sequence that has only the unmatched elements
74 from the original sequence.
75 test-func A dyadic comparison function, used to compare
76 elements from the input sequence. Default is #'eql.
77 key-func A monadic function, used to select what part of
78 the sequence elements to compare. Default is to
79 compare the elements themselves.
80 take-func A monadic function, specifies what part of elements
81 to bind to variables (other than rem-var). Default
82 is to take the entire element.
83 sequence The input sequence.
84
85 Semantics:
86
87 The specified keys are looked up in the sequence and their corresponding
88 variables are bound to the values that are found, or else to their
89 default value, or NIL if there is no default value. If NIL happens
90 to be the result of an explict match, the default value is substituted,
91 if specified.
92
93 The rem-var variable is bound to a new sequence that is stripped of
94 these previously located elements. The declarations and forms are
95 then evaluated in the lexical environment thus formed.
96
97 The binding occurs left to right. The first occurence of a value
98 name in the binding list matches the first occurence of the value
99 name in the input sequence. A second occurence of the same value
100 matches a second occurence and so on."
101 (when (consp remainder)
102 (push remainder var-specs)
103 (setf remainder nil))
104 (let ((vars (mapcar #'first var-specs))
105 (keys (mapcar #'second var-specs))
106 (defaults (mapcar #'third var-specs))
107 (val-sym (gensym "VALS-"))
108 (rem-sym (gensym "REM-")))
109 `(multiple-value-bind (,val-sym ,rem-sym)
110 (find-bind-extract-vals (vector ,@keys)
111 (vector ,@defaults)
112 ,sequence
113 ,test ,key ,take
114 :remainder-p
115 ,(not (null remainder)))
116 (declare (ignorable ,rem-sym))
117 ,(if remainder
118 `(let ((,remainder ,rem-sym)) (vector-bind (,@vars) ,val-sym ,@forms))
119 `(vector-bind (,@vars) ,val-sym ,@forms)))))

  ViewVC Help
Powered by ViewVC 1.1.5