~ubuntu-branches/ubuntu/quantal/gclcvs/quantal

« back to all changes in this revision

Viewing changes to mod/gcl_loop.lsp

  • Committer: Bazaar Package Importer
  • Author(s): Camm Maguire
  • Date: 2004-06-24 15:13:46 UTC
  • Revision ID: james.westby@ubuntu.com-20040624151346-xh0xaaktyyp7aorc
Tags: 2.7.0-26
C_GC_OFFSET is 2 on m68k-linux

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
;;;   -*- Mode: LISP; Package: ANSI-LOOP; Syntax: Common-lisp; Base: 10; Lowercase:T -*-
 
2
;;;>
 
3
;;;> Portions of LOOP are Copyright (c) 1986 by the Massachusetts Institute of Technology.
 
4
;;;> All Rights Reserved.
 
5
;;;> 
 
6
;;;> Permission to use, copy, modify and distribute this software and its
 
7
;;;> documentation for any purpose and without fee is hereby granted,
 
8
;;;> provided that the M.I.T. copyright notice appear in all copies and that
 
9
;;;> both that copyright notice and this permission notice appear in
 
10
;;;> supporting documentation.  The names "M.I.T." and "Massachusetts
 
11
;;;> Institute of Technology" may not be used in advertising or publicity
 
12
;;;> pertaining to distribution of the software without specific, written
 
13
;;;> prior permission.  Notice must be given in supporting documentation that
 
14
;;;> copying distribution is by permission of M.I.T.  M.I.T. makes no
 
15
;;;> representations about the suitability of this software for any purpose.
 
16
;;;> It is provided "as is" without express or implied warranty.
 
17
;;;> 
 
18
;;;>      Massachusetts Institute of Technology
 
19
;;;>      77 Massachusetts Avenue
 
20
;;;>      Cambridge, Massachusetts  02139
 
21
;;;>      United States of America
 
22
;;;>      +1-617-253-1000
 
23
;;;>
 
24
;;;> Portions of LOOP are Copyright (c) 1989, 1990, 1991, 1992 by Symbolics, Inc.
 
25
;;;> All Rights Reserved.
 
26
;;;> 
 
27
;;;> Permission to use, copy, modify and distribute this software and its
 
28
;;;> documentation for any purpose and without fee is hereby granted,
 
29
;;;> provided that the Symbolics copyright notice appear in all copies and
 
30
;;;> that both that copyright notice and this permission notice appear in
 
31
;;;> supporting documentation.  The name "Symbolics" may not be used in
 
32
;;;> advertising or publicity pertaining to distribution of the software
 
33
;;;> without specific, written prior permission.  Notice must be given in
 
34
;;;> supporting documentation that copying distribution is by permission of
 
35
;;;> Symbolics.  Symbolics makes no representations about the suitability of
 
36
;;;> this software for any purpose.  It is provided "as is" without express
 
37
;;;> or implied warranty.
 
38
;;;> 
 
39
;;;> Symbolics, CLOE Runtime, and Minima are trademarks, and CLOE, Genera,
 
40
;;;> and Zetalisp are registered trademarks of Symbolics, Inc.
 
41
;;;>
 
42
;;;>      Symbolics, Inc.
 
43
;;;>      8 New England Executive Park, East
 
44
;;;>      Burlington, Massachusetts  01803
 
45
;;;>      United States of America
 
46
;;;>      +1-617-221-1000
 
47
 
 
48
;; $aclHeader: loop.cl,v 1.5 91/12/04 01:13:48 cox acl4_1 $
 
49
 
 
50
#+cmu
 
51
(ext:file-comment
 
52
 "$Header: /cvsroot/gcl/gcl/mod/gcl_loop.lsp,v 1.1 2003/09/23 20:30:25 camm Exp $")
 
53
 
 
54
;;;; LOOP Iteration Macro
 
55
 
 
56
#+allegro
 
57
(in-package :excl)
 
58
#-allegro
 
59
(in-package :ansi-loop)
 
60
 
 
61
(export '(loop loop-finish))
 
62
(provide :loop)
 
63
 
 
64
#+Cloe-Runtime                                  ;Don't ask.
 
65
(car (push "%Z% %M% %I% %E% %U%" system::*module-identifications*))
 
66
 
 
67
;;; Technology.
 
68
;;;
 
69
;;; The LOOP iteration macro is one of a number of pieces of code
 
70
;;; originally developed at MIT for which free distribution has been
 
71
;;; permitted, as long as the code is not sold for profit, and as long
 
72
;;; as notification of MIT's interest in the code is preserved.
 
73
;;;
 
74
;;; This version of LOOP, which is almost entirely rewritten both as
 
75
;;; clean-up and to conform with the ANSI Lisp LOOP standard, started
 
76
;;; life as MIT LOOP version 829 (which was a part of NIL, possibly
 
77
;;; never released).
 
78
;;;
 
79
;;; A "light revision" was performed by me (Glenn Burke) while at
 
80
;;; Palladian Software in April 1986, to make the code run in Common
 
81
;;; Lisp.  This revision was informally distributed to a number of
 
82
;;; people, and was sort of the "MIT" version of LOOP for running in
 
83
;;; Common Lisp.
 
84
;;;
 
85
;;; A later more drastic revision was performed at Palladian perhaps a
 
86
;;; year later.  This version was more thoroughly Common Lisp in style,
 
87
;;; with a few miscellaneous internal improvements and extensions.  I
 
88
;;; have lost track of this source, apparently never having moved it to
 
89
;;; the MIT distribution point.  I do not remember if it was ever
 
90
;;; distributed.
 
91
;;;
 
92
;;; This revision for the ANSI standard is based on the code of my April
 
93
;;; 1986 version, with almost everything redesigned and/or rewritten.
 
94
 
 
95
 
 
96
;;; The design of this LOOP is intended to permit, using mostly the same
 
97
;;; kernel of code, up to three different "loop" macros:
 
98
;;; 
 
99
;;; (1) The unextended, unextensible ANSI standard LOOP;
 
100
;;;
 
101
;;; (2) A clean "superset" extension of the ANSI LOOP which provides
 
102
;;; functionality similar to that of the old LOOP, but "in the style of"
 
103
;;; the ANSI LOOP.  For instance, user-definable iteration paths, with a
 
104
;;; somewhat cleaned-up interface.
 
105
;;;
 
106
;;; (3) Extensions provided in another file which can make this LOOP
 
107
;;; kernel behave largely compatibly with the Genera-vintage LOOP macro,
 
108
;;; with only a small addition of code (instead of two whole, separate,
 
109
;;; LOOP macros).
 
110
;;;
 
111
;;; Each of the above three LOOP variations can coexist in the same LISP
 
112
;;; environment.
 
113
;;; 
 
114
 
 
115
 
 
116
;;;; Miscellaneous Environment Things
 
117
 
 
118
 
 
119
 
 
120
;;;@@@@The LOOP-Prefer-POP feature makes LOOP generate code which "prefers" to use POP or
 
121
;;; its obvious expansion (prog1 (car x) (setq x (cdr x))).  Usually this involves
 
122
;;; shifting fenceposts in an iteration or series of carcdr operations.  This is
 
123
;;; primarily recognized in the list iterators (FOR .. {IN,ON}), and LOOP's
 
124
;;; destructuring setq code.
 
125
(eval-when (compile load eval)
 
126
  #+(or Genera Minima) (pushnew :LOOP-Prefer-POP *features*)
 
127
  )
 
128
 
 
129
 
 
130
;;; The uses of this macro are retained in the CL version of loop, in
 
131
;;; case they are needed in a particular implementation.  Originally
 
132
;;; dating from the use of the Zetalisp COPYLIST* function, this is used
 
133
;;; in situations where, were cdr-coding in use, having cdr-NIL at the
 
134
;;; end of the list might be suboptimal because the end of the list will
 
135
;;; probably be RPLACDed and so cdr-normal should be used instead.
 
136
(defmacro loop-copylist* (l)
 
137
  #+Genera `(lisp:copy-list ,l nil t)           ; arglist = (list &optional area force-dotted)
 
138
  ;;@@@@Explorer??
 
139
  #-Genera `(copy-list ,l)
 
140
  )
 
141
 
 
142
 
 
143
(defvar *loop-gentemp*
 
144
        nil)
 
145
 
 
146
(defun loop-gentemp (&optional (pref 'loopvar-))
 
147
  (if *loop-gentemp*
 
148
      (gensym (string pref))
 
149
      (gensym)))
 
150
 
 
151
 
 
152
 
 
153
(defvar *loop-real-data-type* 'real)
 
154
 
 
155
 
 
156
(defun loop-optimization-quantities (env)
 
157
  ;;@@@@ The ANSI conditionalization here is for those lisps that implement
 
158
  ;; DECLARATION-INFORMATION (from cleanup SYNTACTIC-ENVIRONMENT-ACCESS).
 
159
  ;; It is really commentary on how this code could be written.  I don't
 
160
  ;; actually expect there to be an ANSI #+-conditional -- it should be
 
161
  ;; replaced with the appropriate conditional name for your
 
162
  ;; implementation/dialect.
 
163
  (declare #-ANSI (ignore env)
 
164
           #+Genera (values speed space safety compilation-speed debug))
 
165
  #+ANSI (let ((stuff (declaration-information 'optimize env)))
 
166
           (values (or (cdr (assoc 'speed stuff)) 1)
 
167
                   (or (cdr (assoc 'space stuff)) 1)
 
168
                   (or (cdr (assoc 'safety stuff)) 1)
 
169
                   (or (cdr (assoc 'compilation-speed stuff)) 1)
 
170
                   (or (cdr (assoc 'debug stuff)) 1)))
 
171
  #+CLOE-Runtime (values compiler::time compiler::space
 
172
                         compiler::safety compiler::compilation-speed 1)
 
173
  #-(or ANSI CLOE-Runtime) (values 1 1 1 1 1))
 
174
 
 
175
 
 
176
;;;@@@@ The following form takes a list of variables and a form which presumably
 
177
;;; references those variables, and wraps it somehow so that the compiler does not
 
178
;;; consider those variables have been referenced.  The intent of this is that
 
179
;;; iteration variables can be flagged as unused by the compiler, e.g. I in
 
180
;;; (loop for i from 1 to 10 do (print t)), since we will tell it when a usage
 
181
;;; of it is "invisible" or "not to be considered".
 
182
;;;We implicitly assume that a setq does not count as a reference.  That is, the
 
183
;;; kind of form generated for the above loop construct to step I, simplified, is
 
184
;;; `(SETQ I ,(HIDE-VARIABLE-REFERENCES '(I) '(1+ I))).
 
185
(defun hide-variable-references (variable-list form)
 
186
  (declare #-Genera (ignore variable-list))
 
187
  #+Genera (if variable-list `(compiler:invisible-references ,variable-list ,form) form)
 
188
  #-Genera form)
 
189
 
 
190
 
 
191
;;;@@@@ The following function takes a flag, a variable, and a form which presumably
 
192
;;; references that variable, and wraps it somehow so that the compiler does not
 
193
;;; consider that variable to have been referenced.  The intent of this is that
 
194
;;; iteration variables can be flagged as unused by the compiler, e.g. I in
 
195
;;; (loop for i from 1 to 10 do (print t)), since we will tell it when a usage
 
196
;;; of it is "invisible" or "not to be considered".
 
197
;;;We implicitly assume that a setq does not count as a reference.  That is, the
 
198
;;; kind of form generated for the above loop construct to step I, simplified, is
 
199
;;; `(SETQ I ,(HIDE-VARIABLE-REFERENCES T 'I '(1+ I))).
 
200
;;;Certain cases require that the "invisibility" of the reference be conditional upon
 
201
;;; something.  This occurs in cases of "named" variables (the USING clause).  For instance,
 
202
;;; we want IDX in (LOOP FOR E BEING THE VECTOR-ELEMENTS OF V USING (INDEX IDX) ...)
 
203
;;; to be "invisible" when it is stepped, so that the user gets informed if IDX is
 
204
;;; not referenced.  However, if no USING clause is present, we definitely do not
 
205
;;; want to be informed that some random gensym is not used.
 
206
;;;It is easier for the caller to do this conditionally by passing a flag (which
 
207
;;; happens to be the second value of NAMED-VARIABLE, q.v.) to this function than
 
208
;;; for all callers to contain the conditional invisibility construction.
 
209
(defun hide-variable-reference (really-hide variable form)
 
210
  (declare #-Genera (ignore really-hide variable))
 
211
  #+Genera (if (and really-hide variable (atom variable))       ;Punt on destructuring patterns
 
212
               `(compiler:invisible-references (,variable) ,form)
 
213
               form)
 
214
  #-Genera form)
 
215
 
 
216
 
 
217
;;;; List Collection Macrology
 
218
 
 
219
 
 
220
(defmacro with-loop-list-collection-head ((head-var tail-var &optional user-head-var)
 
221
                                          &body body)
 
222
  ;;@@@@ TI? Exploder?
 
223
  #+LISPM (let ((head-place (or user-head-var head-var)))
 
224
            `(let* ((,head-place nil)
 
225
                    (,tail-var
 
226
                      ,(hide-variable-reference
 
227
                         user-head-var user-head-var
 
228
                         `(progn #+Genera (scl:locf ,head-place)
 
229
                                 #-Genera (system:variable-location ,head-place)))))
 
230
               ,@body))
 
231
  #-LISPM (let ((l (and user-head-var (list (list user-head-var nil)))))
 
232
            #+CLOE `(sys::with-stack-list* (,head-var nil nil)
 
233
                      (let ((,tail-var ,head-var) ,@l)
 
234
                        ,@body))
 
235
            #-CLOE `(let* ((,head-var (list nil)) (,tail-var ,head-var) ,@l)
 
236
                      ,@body)))
 
237
 
 
238
 
 
239
(defmacro loop-collect-rplacd (&environment env
 
240
                               (head-var tail-var &optional user-head-var) form)
 
241
  (declare
 
242
    #+LISPM (ignore head-var user-head-var)     ;use locatives, unconditionally update through the tail.
 
243
    )
 
244
  (setq form (macroexpand form env))
 
245
  (flet ((cdr-wrap (form n)
 
246
           (declare (fixnum n))
 
247
           (do () ((<= n 4) (setq form `(,(case n
 
248
                                            (1 'cdr)
 
249
                                            (2 'cddr)
 
250
                                            (3 'cdddr)
 
251
                                            (4 'cddddr))
 
252
                                         ,form)))
 
253
             (setq form `(cddddr ,form) n (- n 4)))))
 
254
    (let ((tail-form form) (ncdrs nil))
 
255
      ;;Determine if the form being constructed is a list of known length.
 
256
      (when (consp form)
 
257
        (cond ((eq (car form) 'list)
 
258
               (setq ncdrs (1- (length (cdr form))))
 
259
               ;;@@@@ Because the last element is going to be RPLACDed,
 
260
               ;; we don't want the cdr-coded implementations to use
 
261
               ;; cdr-nil at the end (which would just force copying
 
262
               ;; the whole list again).
 
263
               #+LISPM (setq tail-form `(list* ,@(cdr form) nil)))
 
264
              ((member (car form) '(list* cons))
 
265
               (when (and (cddr form) (member (car (last form)) '(nil 'nil)))
 
266
                 (setq ncdrs (- (length (cdr form)) 2))))))
 
267
      (let ((answer
 
268
              (cond ((null ncdrs)
 
269
                     `(when (setf (cdr ,tail-var) ,tail-form)
 
270
                        (setq ,tail-var (last (cdr ,tail-var)))))
 
271
                    ((< ncdrs 0) (return-from loop-collect-rplacd nil))
 
272
                    ((= ncdrs 0)
 
273
                     ;;@@@@ Here we have a choice of two idioms:
 
274
                     ;; (rplacd tail (setq tail tail-form))
 
275
                     ;; (setq tail (setf (cdr tail) tail-form)).
 
276
                     ;;Genera and most others I have seen do better with the former.
 
277
                     `(rplacd ,tail-var (setq ,tail-var ,tail-form)))
 
278
                    (t `(setq ,tail-var ,(cdr-wrap `(setf (cdr ,tail-var) ,tail-form)
 
279
                                                   ncdrs))))))
 
280
        ;;If not using locatives or something similar to update the user's
 
281
        ;; head variable, we've got to set it...  It's harmless to repeatedly set it
 
282
        ;; unconditionally, and probably faster than checking.
 
283
        #-LISPM (when user-head-var
 
284
                  (setq answer `(progn ,answer (setq ,user-head-var (cdr ,head-var)))))
 
285
        answer))))
 
286
 
 
287
 
 
288
(defmacro loop-collect-answer (head-var &optional user-head-var)
 
289
  (or user-head-var
 
290
      (progn
 
291
        ;;If we use locatives to get tail-updating to update the head var,
 
292
        ;; then the head var itself contains the answer.  Otherwise we
 
293
        ;; have to cdr it.
 
294
        #+LISPM head-var
 
295
        #-LISPM `(cdr ,head-var))))
 
296
 
 
297
 
 
298
;;;; Maximization Technology
 
299
 
 
300
 
 
301
#|
 
302
The basic idea of all this minimax randomness here is that we have to
 
303
have constructed all uses of maximize and minimize to a particular
 
304
"destination" before we can decide how to code them.  The goal is to not
 
305
have to have any kinds of flags, by knowing both that (1) the type is
 
306
something which we can provide an initial minimum or maximum value for
 
307
and (2) know that a MAXIMIZE and MINIMIZE are not being combined.
 
308
 
 
309
SO, we have a datastructure which we annotate with all sorts of things,
 
310
incrementally updating it as we generate loop body code, and then use
 
311
a wrapper and internal macros to do the coding when the loop has been
 
312
constructed.
 
313
|#
 
314
 
 
315
 
 
316
(defstruct (loop-minimax
 
317
             (:constructor make-loop-minimax-internal)
 
318
             (:copier nil)
 
319
             (:predicate nil))
 
320
  answer-variable
 
321
  type
 
322
  temp-variable
 
323
  flag-variable
 
324
  operations
 
325
  infinity-data)
 
326
 
 
327
 
 
328
(defvar *loop-minimax-type-infinities-alist*
 
329
        ;;@@@@ This is the sort of value this should take on for a Lisp that has
 
330
        ;; "eminently usable" infinities.  n.b. there are neither constants nor
 
331
        ;; printed representations for infinities defined by CL.
 
332
        ;;@@@@ This grotesque read-from-string below is to help implementations
 
333
        ;; which croak on the infinity character when it appears in a token, even
 
334
        ;; conditionalized out.
 
335
        #+Genera
 
336
          '#.(read-from-string
 
337
              "((fixnum         most-positive-fixnum     most-negative-fixnum)
 
338
                (short-float    +1s                     -1s)
 
339
                (single-float   +1f                     -1f)
 
340
                (double-float   +1d                     -1d)
 
341
                (long-float     +1l                     -1l))")
 
342
        ;;This is how the alist should look for a lisp that has no infinities.  In
 
343
        ;; that case, MOST-POSITIVE-x-FLOAT really IS the most positive.
 
344
        #+(or CLOE-Runtime Minima)
 
345
          '((fixnum             most-positive-fixnum            most-negative-fixnum)
 
346
            (short-float        most-positive-short-float       most-negative-short-float)
 
347
            (single-float       most-positive-single-float      most-negative-single-float)
 
348
            (double-float       most-positive-double-float      most-negative-double-float)
 
349
            (long-float         most-positive-long-float        most-negative-long-float))
 
350
        ;; CMUCL has infinities so let's use them.
 
351
        #+CMU
 
352
          '((fixnum             most-positive-fixnum                    most-negative-fixnum)
 
353
            (short-float        ext:single-float-positive-infinity      ext:single-float-negative-infinity)
 
354
            (single-float       ext:single-float-positive-infinity      ext:single-float-negative-infinity)
 
355
            (double-float       ext:double-float-positive-infinity      ext:double-float-negative-infinity)
 
356
            (long-float         ext:long-float-positive-infinity        ext:long-float-negative-infinity))
 
357
        ;; If we don't know, then we cannot provide "infinite" initial values for any of the
 
358
        ;; types but FIXNUM:
 
359
        #-(or Genera CLOE-Runtime Minima CMU)
 
360
          '((fixnum             most-positive-fixnum            most-negative-fixnum))
 
361
          )
 
362
 
 
363
 
 
364
(defun make-loop-minimax (answer-variable type)
 
365
  (let ((infinity-data (cdr (assoc type *loop-minimax-type-infinities-alist* :test #'subtypep))))
 
366
    (make-loop-minimax-internal
 
367
      :answer-variable answer-variable
 
368
      :type type
 
369
      :temp-variable (loop-gentemp 'loop-maxmin-temp-)
 
370
      :flag-variable (and (not infinity-data) (loop-gentemp 'loop-maxmin-flag-))
 
371
      :operations nil
 
372
      :infinity-data infinity-data)))
 
373
 
 
374
 
 
375
(defun loop-note-minimax-operation (operation minimax)
 
376
  (pushnew (the symbol operation) (loop-minimax-operations minimax))
 
377
  (when (and (cdr (loop-minimax-operations minimax))
 
378
             (not (loop-minimax-flag-variable minimax)))
 
379
    (setf (loop-minimax-flag-variable minimax) (loop-gentemp 'loop-maxmin-flag-)))
 
380
  operation)
 
381
 
 
382
 
 
383
(defmacro with-minimax-value (lm &body body)
 
384
  (let ((init (loop-typed-init (loop-minimax-type lm)))
 
385
        (which (car (loop-minimax-operations lm)))
 
386
        (infinity-data (loop-minimax-infinity-data lm))
 
387
        (answer-var (loop-minimax-answer-variable lm))
 
388
        (temp-var (loop-minimax-temp-variable lm))
 
389
        (flag-var (loop-minimax-flag-variable lm))
 
390
        (type (loop-minimax-type lm)))
 
391
    (if flag-var
 
392
        `(let ((,answer-var ,init) (,temp-var ,init) (,flag-var nil))
 
393
           (declare (type ,type ,answer-var ,temp-var))
 
394
           ,@body)
 
395
        `(let ((,answer-var ,(if (eq which 'min) (first infinity-data) (second infinity-data)))
 
396
               (,temp-var ,init))
 
397
           (declare (type ,type ,answer-var ,temp-var))
 
398
           ,@body))))
 
399
 
 
400
 
 
401
(defmacro loop-accumulate-minimax-value (lm operation form)
 
402
  (let* ((answer-var (loop-minimax-answer-variable lm))
 
403
         (temp-var (loop-minimax-temp-variable lm))
 
404
         (flag-var (loop-minimax-flag-variable lm))
 
405
         (test
 
406
           (hide-variable-reference
 
407
             t (loop-minimax-answer-variable lm)
 
408
             `(,(ecase operation
 
409
                  (min '<)
 
410
                  (max '>))
 
411
               ,temp-var ,answer-var))))
 
412
    `(progn
 
413
       (setq ,temp-var ,form)
 
414
       (when ,(if flag-var `(or (not ,flag-var) ,test) test)
 
415
         (setq ,@(and flag-var `(,flag-var t))
 
416
               ,answer-var ,temp-var)))))
 
417
 
 
418
 
 
419
 
 
420
;;;; Loop Keyword Tables
 
421
 
 
422
 
 
423
#|
 
424
LOOP keyword tables are hash tables string keys and a test of EQUAL.
 
425
 
 
426
The actual descriptive/dispatch structure used by LOOP is called a "loop
 
427
universe" contains a few tables and parameterizations.  The basic idea is
 
428
that we can provide a non-extensible ANSI-compatible loop environment,
 
429
an extensible ANSI-superset loop environment, and (for such environments
 
430
as CLOE) one which is "sufficiently close" to the old Genera-vintage
 
431
LOOP for use by old user programs without requiring all of the old LOOP
 
432
code to be loaded.
 
433
|#
 
434
 
 
435
 
 
436
;;;; Token Hackery
 
437
 
 
438
 
 
439
;;;Compare two "tokens".  The first is the frob out of *LOOP-SOURCE-CODE*,
 
440
;;; the second a symbol to check against.
 
441
(defun loop-tequal (x1 x2)
 
442
  (and (symbolp x1) (string= x1 x2)))
 
443
 
 
444
 
 
445
(defun loop-tassoc (kwd alist)
 
446
  (and (symbolp kwd) (assoc kwd alist :test #'string=)))
 
447
 
 
448
 
 
449
(defun loop-tmember (kwd list)
 
450
  (and (symbolp kwd) (member kwd list :test #'string=)))
 
451
 
 
452
 
 
453
(defun loop-lookup-keyword (loop-token table)
 
454
  (and (symbolp loop-token)
 
455
       (values (gethash (symbol-name loop-token) table))))
 
456
 
 
457
 
 
458
(defmacro loop-store-table-data (symbol table datum)
 
459
  `(setf (gethash (symbol-name ,symbol) ,table) ,datum))
 
460
 
 
461
 
 
462
(defstruct (loop-universe
 
463
             (:print-function print-loop-universe)
 
464
             (:copier nil)
 
465
             (:predicate nil))
 
466
  keywords                                      ;hash table, value = (fn-name . extra-data).
 
467
  iteration-keywords                            ;hash table, value = (fn-name . extra-data).
 
468
  for-keywords                                  ;hash table, value = (fn-name . extra-data).
 
469
  path-keywords                                 ;hash table, value = (fn-name . extra-data).
 
470
  type-symbols                                  ;hash table of type SYMBOLS, test EQ, value = CL type specifier.
 
471
  type-keywords                                 ;hash table of type STRINGS, test EQUAL, value = CL type spec.
 
472
  ansi                                          ;NIL, T, or :EXTENDED.
 
473
  implicit-for-required                         ;see loop-hack-iteration
 
474
  )
 
475
 
 
476
 
 
477
(defun print-loop-universe (u stream level)
 
478
  (declare (ignore level))
 
479
  (let ((str (case (loop-universe-ansi u)
 
480
               ((nil) "Non-ANSI")
 
481
               ((t) "ANSI")
 
482
               (:extended "Extended-ANSI")
 
483
               (t (loop-universe-ansi u)))))
 
484
    ;;Cloe could be done with the above except for bootstrap lossage...
 
485
    #+CLOE
 
486
    (format stream "#<~S ~A ~X>" (type-of u) str (sys::address-of u))
 
487
    #+(or Genera cmu)                                   ;@@@@ This is reallly the ANSI definition.
 
488
    (print-unreadable-object (u stream :type t :identity t)
 
489
      (princ str stream))
 
490
    #-(or Genera CLOE cmu)
 
491
    (format stream "#<~S ~A>" (type-of u) str)
 
492
    ))
 
493
 
 
494
 
 
495
;;;This is the "current" loop context in use when we are expanding a
 
496
;;;loop.  It gets bound on each invocation of LOOP.
 
497
(defvar *loop-universe*)
 
498
 
 
499
 
 
500
(defun make-standard-loop-universe (&key keywords for-keywords iteration-keywords path-keywords
 
501
                                    type-keywords type-symbols ansi)
 
502
  #-(and CLOE Source-Bootstrap) (check-type ansi (member nil t :extended))
 
503
  (flet ((maketable (entries)
 
504
           (let* ((size (length entries))
 
505
                  (ht (make-hash-table :size (if (< size 10) 10 size) :test #'equal)))
 
506
             (dolist (x entries) (setf (gethash (symbol-name (car x)) ht) (cadr x)))
 
507
             ht)))
 
508
    (make-loop-universe
 
509
      :keywords (maketable keywords)
 
510
      :for-keywords (maketable for-keywords)
 
511
      :iteration-keywords (maketable iteration-keywords)
 
512
      :path-keywords (maketable path-keywords)
 
513
      :ansi ansi
 
514
      :implicit-for-required (not (null ansi))
 
515
      :type-keywords (maketable type-keywords)
 
516
      :type-symbols (let* ((size (length type-symbols))
 
517
                           (ht (make-hash-table :size (if (< size 10) 10 size) :test #'eq)))
 
518
                      (dolist (x type-symbols)
 
519
                        (if (atom x) (setf (gethash x ht) x) (setf (gethash (car x) ht) (cadr x))))
 
520
                      ht)))) 
 
521
 
 
522
 
 
523
;;;; Setq Hackery
 
524
 
 
525
 
 
526
(defvar *loop-destructuring-hooks*
 
527
        nil
 
528
  "If not NIL, this must be a list of two things:
 
529
a LET-like macro, and a SETQ-like macro, which perform LOOP-style destructuring.")
 
530
 
 
531
 
 
532
(defun loop-make-psetq (frobs)
 
533
  (and frobs
 
534
       (loop-make-desetq
 
535
         (list (car frobs)
 
536
               (if (null (cddr frobs)) (cadr frobs)
 
537
                   `(prog1 ,(cadr frobs)
 
538
                           ,(loop-make-psetq (cddr frobs))))))))
 
539
 
 
540
 
 
541
(defun loop-make-desetq (var-val-pairs)
 
542
  (if (null var-val-pairs)
 
543
      nil
 
544
      (cons (if *loop-destructuring-hooks*
 
545
                (cadr *loop-destructuring-hooks*)
 
546
                'loop-really-desetq)
 
547
            var-val-pairs)))
 
548
 
 
549
 
 
550
(defvar *loop-desetq-temporary*
 
551
        (make-symbol "LOOP-DESETQ-TEMP"))
 
552
 
 
553
 
 
554
(defmacro loop-really-desetq (&environment env &rest var-val-pairs)
 
555
  (labels ((find-non-null (var)
 
556
             ;; see if there's any non-null thing here
 
557
             ;; recurse if the list element is itself a list
 
558
             (do ((tail var)) ((not (consp tail)) tail)
 
559
               (when (find-non-null (pop tail)) (return t))))
 
560
           (loop-desetq-internal (var val &optional temp)
 
561
             ;; returns a list of actions to be performed
 
562
             (typecase var
 
563
               (null
 
564
                 (when (consp val)
 
565
                   ;; don't lose possible side-effects
 
566
                   (if (eq (car val) 'prog1)
 
567
                       ;; these can come from psetq or desetq below.
 
568
                       ;; throw away the value, keep the side-effects.
 
569
                       ;;Special case is for handling an expanded POP.
 
570
                       (mapcan #'(lambda (x)
 
571
                                   (and (consp x)
 
572
                                        (or (not (eq (car x) 'car))
 
573
                                            (not (symbolp (cadr x)))
 
574
                                            (not (symbolp (setq x (macroexpand x env)))))
 
575
                                        (cons x nil)))
 
576
                               (cdr val))
 
577
                       `(,val))))
 
578
               (cons
 
579
                 (let* ((car (car var))
 
580
                        (cdr (cdr var))
 
581
                        (car-non-null (find-non-null car))
 
582
                        (cdr-non-null (find-non-null cdr)))
 
583
                   (when (or car-non-null cdr-non-null)
 
584
                     (if cdr-non-null
 
585
                         (let* ((temp-p temp)
 
586
                                (temp (or temp *loop-desetq-temporary*))
 
587
                                (body #+LOOP-Prefer-POP `(,@(loop-desetq-internal
 
588
                                                              car
 
589
                                                              `(prog1 (car ,temp)
 
590
                                                                      (setq ,temp (cdr ,temp))))
 
591
                                                          ,@(loop-desetq-internal cdr temp temp))
 
592
                                      #-LOOP-Prefer-POP `(,@(loop-desetq-internal car `(car ,temp))
 
593
                                                          (setq ,temp (cdr ,temp))
 
594
                                                          ,@(loop-desetq-internal cdr temp temp))))
 
595
                           (if temp-p
 
596
                               `(,@(unless (eq temp val)
 
597
                                     `((setq ,temp ,val)))
 
598
                                 ,@body)
 
599
                               `((let ((,temp ,val))
 
600
                                   ,@body))))
 
601
                         ;; no cdring to do
 
602
                         (loop-desetq-internal car `(car ,val) temp)))))
 
603
               (otherwise
 
604
                 (unless (eq var val)
 
605
                   `((setq ,var ,val)))))))
 
606
    (do ((actions))
 
607
        ((null var-val-pairs)
 
608
         (if (null (cdr actions)) (car actions) `(progn ,@(nreverse actions))))
 
609
      (setq actions (revappend
 
610
                      (loop-desetq-internal (pop var-val-pairs) (pop var-val-pairs))
 
611
                      actions)))))
 
612
 
 
613
 
 
614
;;;; LOOP-local variables
 
615
 
 
616
;;;This is the "current" pointer into the LOOP source code.
 
617
(defvar *loop-source-code*)
 
618
 
 
619
 
 
620
;;;This is the pointer to the original, for things like NAMED that
 
621
;;;insist on being in a particular position
 
622
(defvar *loop-original-source-code*)
 
623
 
 
624
 
 
625
;;;This is *loop-source-code* as of the "last" clause.  It is used
 
626
;;;primarily for generating error messages (see loop-error, loop-warn).
 
627
(defvar *loop-source-context*)
 
628
 
 
629
 
 
630
;;;List of names for the LOOP, supplied by the NAMED clause.
 
631
(defvar *loop-names*)
 
632
 
 
633
;;;The macroexpansion environment given to the macro.
 
634
(defvar *loop-macro-environment*)
 
635
 
 
636
;;;This holds variable names specified with the USING clause.
 
637
;;; See LOOP-NAMED-VARIABLE.
 
638
(defvar *loop-named-variables*)
 
639
 
 
640
;;; LETlist-like list being accumulated for one group of parallel bindings.
 
641
(defvar *loop-variables*)
 
642
 
 
643
;;;List of declarations being accumulated in parallel with
 
644
;;;*loop-variables*.
 
645
(defvar *loop-declarations*)
 
646
 
 
647
;;;Used by LOOP for destructuring binding, if it is doing that itself.
 
648
;;; See loop-make-variable.
 
649
(defvar *loop-desetq-crocks*)
 
650
 
 
651
;;; List of wrapping forms, innermost first, which go immediately inside
 
652
;;; the current set of parallel bindings being accumulated in
 
653
;;; *loop-variables*.  The wrappers are appended onto a body.  E.g.,
 
654
;;; this list could conceivably has as its value ((with-open-file (g0001
 
655
;;; g0002 ...))), with g0002 being one of the bindings in
 
656
;;; *loop-variables* (this is why the wrappers go inside of the variable
 
657
;;; bindings).
 
658
(defvar *loop-wrappers*)
 
659
 
 
660
;;;This accumulates lists of previous values of *loop-variables* and the
 
661
;;;other lists  above, for each new nesting of bindings.  See
 
662
;;;loop-bind-block.
 
663
(defvar *loop-bind-stack*)
 
664
 
 
665
;;;This is a LOOP-global variable for the (obsolete) NODECLARE clause
 
666
;;;which inhibits  LOOP from actually outputting a type declaration for
 
667
;;;an iteration (or any) variable.
 
668
(defvar *loop-nodeclare*)
 
669
 
 
670
;;;This is simply a list of LOOP iteration variables, used for checking
 
671
;;;for duplications.
 
672
(defvar *loop-iteration-variables*)
 
673
 
 
674
 
 
675
;;;List of prologue forms of the loop, accumulated in reverse order.
 
676
(defvar *loop-prologue*)
 
677
 
 
678
(defvar *loop-before-loop*)
 
679
(defvar *loop-body*)
 
680
(defvar *loop-after-body*)
 
681
 
 
682
;;;This is T if we have emitted any body code, so that iteration driving
 
683
;;;clauses can be disallowed.   This is not strictly the same as
 
684
;;;checking *loop-body*, because we permit some clauses  such as RETURN
 
685
;;;to not be considered "real" body (so as to permit the user to "code"
 
686
;;;an  abnormal return value "in loop").
 
687
(defvar *loop-emitted-body*)
 
688
 
 
689
 
 
690
;;;List of epilogue forms (supplied by FINALLY generally), accumulated
 
691
;;; in reverse order.
 
692
(defvar *loop-epilogue*)
 
693
 
 
694
;;;List of epilogue forms which are supplied after the above "user"
 
695
;;;epilogue.  "normal" termination return values are provide by putting
 
696
;;;the return form in here.  Normally this is done using
 
697
;;;loop-emit-final-value, q.v.
 
698
(defvar *loop-after-epilogue*)
 
699
 
 
700
;;;The "culprit" responsible for supplying a final value from the loop.
 
701
;;;This  is so loop-emit-final-value can moan about multiple return
 
702
;;;values being supplied.
 
703
(defvar *loop-final-value-culprit*)
 
704
 
 
705
;;;If not NIL, we are in some branch of a conditional.  Some clauses may
 
706
;;;be disallowed.
 
707
(defvar *loop-inside-conditional*)
 
708
 
 
709
;;;If not NIL, this is a temporary bound around the loop for holding the
 
710
;;;temporary  value for "it" in things like "when (f) collect it".  It
 
711
;;;may be used as a supertemporary by some other things.
 
712
(defvar *loop-when-it-variable*)
 
713
 
 
714
;;;Sometimes we decide we need to fold together parts of the loop, but
 
715
;;;some part of the generated iteration  code is different for the first
 
716
;;;and remaining iterations.  This variable will be the temporary which 
 
717
;;;is the flag used in the loop to tell whether we are in the first or
 
718
;;;remaining iterations.
 
719
(defvar *loop-never-stepped-variable*)
 
720
 
 
721
;;;List of all the value-accumulation descriptor structures in the loop.
 
722
;;; See loop-get-collection-info.
 
723
(defvar *loop-collection-cruft*)                ; for multiple COLLECTs (etc)
 
724
 
 
725
 
 
726
;;;; Code Analysis Stuff
 
727
 
 
728
 
 
729
(defun loop-constant-fold-if-possible (form &optional expected-type)
 
730
  #+Genera (declare (values new-form constantp constant-value))
 
731
  (let ((new-form form) (constantp nil) (constant-value nil))
 
732
    #+Genera (setq new-form (compiler:optimize-form form *loop-macro-environment*
 
733
                                                    :repeat t
 
734
                                                    :do-macro-expansion t
 
735
                                                    :do-named-constants t
 
736
                                                    :do-inline-forms t
 
737
                                                    :do-optimizers t
 
738
                                                    :do-constant-folding t
 
739
                                                    :do-function-args t)
 
740
                   constantp (constantp new-form *loop-macro-environment*)
 
741
                   constant-value (and constantp (lt:evaluate-constant new-form *loop-macro-environment*)))
 
742
    #-Genera (when (setq constantp (constantp new-form))
 
743
               (setq constant-value (eval new-form)))
 
744
    (when (and constantp expected-type)
 
745
      (unless (typep constant-value expected-type)
 
746
        (loop-warn "The form ~S evaluated to ~S, which was not of the anticipated type ~S."
 
747
                   form constant-value expected-type)
 
748
        (setq constantp nil constant-value nil)))
 
749
    (values new-form constantp constant-value)))
 
750
 
 
751
 
 
752
(defun loop-constantp (form)
 
753
  #+Genera (constantp form *loop-macro-environment*)
 
754
  #-Genera (constantp form))
 
755
 
 
756
 
 
757
;;;; LOOP Iteration Optimization
 
758
 
 
759
(defvar *loop-duplicate-code*
 
760
        nil)
 
761
 
 
762
 
 
763
(defvar *loop-iteration-flag-variable*
 
764
        (make-symbol "LOOP-NOT-FIRST-TIME"))
 
765
 
 
766
 
 
767
(defun loop-code-duplication-threshold (env)
 
768
  (multiple-value-bind (speed space) (loop-optimization-quantities env)
 
769
    (+ 40 (* (- speed space) 10))))
 
770
 
 
771
 
 
772
(defmacro loop-body (&environment env
 
773
                     prologue
 
774
                     before-loop
 
775
                     main-body
 
776
                     after-loop
 
777
                     epilogue
 
778
                     &aux rbefore rafter flagvar)
 
779
  (unless (= (length before-loop) (length after-loop))
 
780
    (error "LOOP-BODY called with non-synched before- and after-loop lists."))
 
781
  ;;All our work is done from these copies, working backwards from the end:
 
782
  (setq rbefore (reverse before-loop) rafter (reverse after-loop))
 
783
  (labels ((psimp (l)
 
784
             (let ((ans nil))
 
785
               (dolist (x l)
 
786
                 (when x
 
787
                   (push x ans)
 
788
                   (when (and (consp x) (member (car x) '(go return return-from)))
 
789
                     (return nil))))
 
790
               (nreverse ans)))
 
791
           (pify (l) (if (null (cdr l)) (car l) `(progn ,@l)))
 
792
           (makebody ()
 
793
             (let ((form `(tagbody
 
794
                            ,@(psimp (append prologue (nreverse rbefore)))
 
795
                         next-loop
 
796
                            ,@(psimp (append main-body (nreconc rafter `((go next-loop)))))
 
797
                         end-loop
 
798
                            ,@(psimp epilogue))))
 
799
               (if flagvar `(let ((,flagvar nil)) ,form) form))))
 
800
    (when (or *loop-duplicate-code* (not rbefore))
 
801
      (return-from loop-body (makebody)))
 
802
    ;; This outer loop iterates once for each not-first-time flag test generated
 
803
    ;; plus once more for the forms that don't need a flag test
 
804
    (do ((threshold (loop-code-duplication-threshold env))) (nil)
 
805
      (declare (fixnum threshold))
 
806
      ;; Go backwards from the ends of before-loop and after-loop merging all the equivalent
 
807
      ;; forms into the body.
 
808
      (do () ((or (null rbefore) (not (equal (car rbefore) (car rafter)))))
 
809
        (push (pop rbefore) main-body)
 
810
        (pop rafter))
 
811
      (unless rbefore (return (makebody)))
 
812
      ;; The first forms in rbefore & rafter (which are the chronologically
 
813
      ;; last forms in the list) differ, therefore they cannot be moved
 
814
      ;; into the main body.  If everything that chronologically precedes
 
815
      ;; them either differs or is equal but is okay to duplicate, we can
 
816
      ;; just put all of rbefore in the prologue and all of rafter after
 
817
      ;; the body.  Otherwise, there is something that is not okay to
 
818
      ;; duplicate, so it and everything chronologically after it in
 
819
      ;; rbefore and rafter must go into the body, with a flag test to
 
820
      ;; distinguish the first time around the loop from later times.
 
821
      ;; What chronologically precedes the non-duplicatable form will
 
822
      ;; be handled the next time around the outer loop.
 
823
      (do ((bb rbefore (cdr bb)) (aa rafter (cdr aa)) (lastdiff nil) (count 0) (inc nil))
 
824
          ((null bb) (return-from loop-body (makebody)))        ;Did it.
 
825
        (cond ((not (equal (car bb) (car aa))) (setq lastdiff bb count 0))
 
826
              ((or (not (setq inc (estimate-code-size (car bb) env)))
 
827
                   (> (incf count inc) threshold))
 
828
               ;; Ok, we have found a non-duplicatable piece of code.  Everything
 
829
               ;; chronologically after it must be in the central body.
 
830
               ;; Everything chronologically at and after lastdiff goes into the
 
831
               ;; central body under a flag test.
 
832
               (let ((then nil) (else nil))
 
833
                 (do () (nil)
 
834
                   (push (pop rbefore) else)
 
835
                   (push (pop rafter) then)
 
836
                   (when (eq rbefore (cdr lastdiff)) (return)))
 
837
                 (unless flagvar
 
838
                   (push `(setq ,(setq flagvar *loop-iteration-flag-variable*) t) else))
 
839
                 (push `(if ,flagvar ,(pify (psimp then)) ,(pify (psimp else)))
 
840
                       main-body))
 
841
               ;; Everything chronologically before lastdiff until the non-duplicatable form (car bb) 
 
842
               ;; is the same in rbefore and rafter so just copy it into the body
 
843
               (do () (nil)
 
844
                 (pop rafter)
 
845
                 (push (pop rbefore) main-body)
 
846
                 (when (eq rbefore (cdr bb)) (return)))
 
847
               (return)))))))
 
848
 
 
849
 
 
850
 
 
851
(defun duplicatable-code-p (expr env)
 
852
  (if (null expr) 0
 
853
      (let ((ans (estimate-code-size expr env)))
 
854
        (declare (fixnum ans))
 
855
        ;;@@@@ Use (DECLARATION-INFORMATION 'OPTIMIZE ENV) here to get an alist of
 
856
        ;; optimize quantities back to help quantify how much code we are willing to
 
857
        ;; duplicate.
 
858
        ans)))
 
859
 
 
860
 
 
861
(defvar *special-code-sizes*
 
862
        '((return 0) (progn 0)
 
863
          (null 1) (not 1) (eq 1) (car 1) (cdr 1)
 
864
          (when 1) (unless 1) (if 1)
 
865
          (caar 2) (cadr 2) (cdar 2) (cddr 2)
 
866
          (caaar 3) (caadr 3) (cadar 3) (caddr 3) (cdaar 3) (cdadr 3) (cddar 3) (cdddr 3)
 
867
          (caaaar 4) (caaadr 4) (caadar 4) (caaddr 4)
 
868
          (cadaar 4) (cadadr 4) (caddar 4) (cadddr 4)
 
869
          (cdaaar 4) (cdaadr 4) (cdadar 4) (cdaddr 4)
 
870
          (cddaar 4) (cddadr 4) (cdddar 4) (cddddr 4)))
 
871
 
 
872
 
 
873
(defvar *estimate-code-size-punt*
 
874
        '(block
 
875
           do do* dolist
 
876
           flet
 
877
           labels lambda let let* locally
 
878
           macrolet multiple-value-bind
 
879
           prog prog*
 
880
           symbol-macrolet
 
881
           tagbody
 
882
           unwind-protect
 
883
           with-open-file))
 
884
 
 
885
 
 
886
(defun destructuring-size (x)
 
887
  (do ((x x (cdr x)) (n 0 (+ (destructuring-size (car x)) n)))
 
888
      ((atom x) (+ n (if (null x) 0 1)))))
 
889
 
 
890
 
 
891
(defun estimate-code-size (x env)
 
892
  (catch 'estimate-code-size
 
893
    (estimate-code-size-1 x env)))
 
894
 
 
895
 
 
896
(defun estimate-code-size-1 (x env)
 
897
  (flet ((list-size (l)
 
898
           (let ((n 0))
 
899
             (declare (fixnum n))
 
900
             (dolist (x l n) (incf n (estimate-code-size-1 x env))))))
 
901
    ;;@@@@ ???? (declare (function list-size (list) fixnum))
 
902
    (cond ((constantp x #+Genera env) 1)
 
903
          ((symbolp x) (multiple-value-bind (new-form expanded-p) (macroexpand-1 x env)
 
904
                         (if expanded-p (estimate-code-size-1 new-form env) 1)))
 
905
          ((atom x) 1)                          ;??? self-evaluating???
 
906
          ((symbolp (car x))
 
907
           (let ((fn (car x)) (tem nil) (n 0))
 
908
             (declare (symbol fn) (fixnum n))
 
909
             (macrolet ((f (overhead &optional (args nil args-p))
 
910
                          `(the fixnum (+ (the fixnum ,overhead)
 
911
                                          (the fixnum (list-size ,(if args-p args '(cdr x))))))))
 
912
               (cond ((setq tem (get fn 'estimate-code-size))
 
913
                      (typecase tem
 
914
                        (fixnum (f tem))
 
915
                        (t (funcall tem x env))))
 
916
                     ((setq tem (assoc fn *special-code-sizes*)) (f (second tem)))
 
917
                     #+Genera
 
918
                     ((eq fn 'compiler:invisible-references) (list-size (cddr x)))
 
919
                     ((eq fn 'cond)
 
920
                      (dolist (clause (cdr x) n) (incf n (list-size clause)) (incf n)))
 
921
                     ((eq fn 'desetq)
 
922
                      (do ((l (cdr x) (cdr l))) ((null l) n)
 
923
                        (setq n (+ n (destructuring-size (car l)) (estimate-code-size-1 (cadr l) env)))))
 
924
                     ((member fn '(setq psetq))
 
925
                      (do ((l (cdr x) (cdr l))) ((null l) n)
 
926
                        (setq n (+ n (estimate-code-size-1 (cadr l) env) 1))))
 
927
                     ((eq fn 'go) 1)
 
928
                     ((eq fn 'function)
 
929
                      ;;This skirts the issue of implementationally-defined lambda macros
 
930
                      ;; by recognizing CL function names and nothing else.
 
931
                      (if t;(ext:valid-function-name-p (cadr x))
 
932
                          1
 
933
                          (throw 'duplicatable-code-p nil)))
 
934
                     ((eq fn 'multiple-value-setq) (f (length (second x)) (cddr x)))
 
935
                     ((eq fn 'return-from) (1+ (estimate-code-size-1 (third x) env)))
 
936
                     ((or (special-operator-p fn) (member fn *estimate-code-size-punt*))
 
937
                      (throw 'estimate-code-size nil))
 
938
                     (t (multiple-value-bind (new-form expanded-p) (macroexpand-1 x env)
 
939
                          (if expanded-p
 
940
                              (estimate-code-size-1 new-form env)
 
941
                              (f 3))))))))
 
942
          (t (throw 'estimate-code-size nil)))))
 
943
 
 
944
 
 
945
;;;; Loop Errors
 
946
 
 
947
 
 
948
(defun loop-context ()
 
949
  (do ((l *loop-source-context* (cdr l)) (new nil (cons (car l) new)))
 
950
      ((eq l (cdr *loop-source-code*)) (nreverse new))))
 
951
 
 
952
 
 
953
(defun loop-error (format-string &rest format-args)
 
954
  #+(or Genera CLOE) (declare (dbg:error-reporter))
 
955
  #+Genera (setq format-args (copy-list format-args))   ;Don't ask.
 
956
  (specific-error :invalid-form  "~?~%Current LOOP context:~{ ~S~}."
 
957
                               format-string format-args (loop-context)))
 
958
 
 
959
 
 
960
(defun loop-warn (format-string &rest format-args)
 
961
  (warn "~?~%Current LOOP context:~{ ~S~}." format-string format-args (loop-context)))
 
962
 
 
963
 
 
964
(defun loop-check-data-type (specified-type required-type
 
965
                             &optional (default-type required-type))
 
966
  (if (null specified-type)
 
967
      default-type
 
968
      (multiple-value-bind (a b) (subtypep specified-type required-type)
 
969
        (cond ((not b)
 
970
               (loop-warn "LOOP couldn't verify that ~S is a subtype of the required type ~S."
 
971
                          specified-type required-type))
 
972
              ((not a)
 
973
               (loop-error "Specified data type ~S is not a subtype of ~S."
 
974
                           specified-type required-type)))
 
975
        specified-type)))
 
976
 
 
977
 
 
978
;;;INTERFACE: Traditional, ANSI, Lucid.
 
979
(defmacro loop-finish () 
 
980
  "Causes the iteration to terminate \"normally\", the same as implicit
 
981
termination by an iteration driving clause, or by use of WHILE or
 
982
UNTIL -- the epilogue code (if any) will be run, and any implicitly
 
983
collected result will be returned as the value of the LOOP."
 
984
  '(go end-loop))
 
985
 
 
986
 
 
987
 
 
988
(defun subst-gensyms-for-nil (tree)
 
989
  (declare (special *ignores*))
 
990
  (cond
 
991
    ((null tree) (car (push (loop-gentemp) *ignores*)))
 
992
    ((atom tree) tree)
 
993
    (t (cons (subst-gensyms-for-nil (car tree))
 
994
             (subst-gensyms-for-nil (cdr tree))))))
 
995
 
 
996
(defun loop-build-destructuring-bindings (crocks forms)
 
997
  (if crocks
 
998
      (let ((*ignores* ()))
 
999
        (declare (special *ignores*))
 
1000
        `((destructuring-bind ,(subst-gensyms-for-nil (car crocks))
 
1001
              ,(cadr crocks)
 
1002
            (declare (ignore ,@*ignores*))
 
1003
            ,@(loop-build-destructuring-bindings (cddr crocks) forms))))
 
1004
      forms))
 
1005
 
 
1006
(defun loop-translate (*loop-source-code* *loop-macro-environment* *loop-universe*)
 
1007
  (let ((*loop-original-source-code* *loop-source-code*)
 
1008
        (*loop-source-context* nil)
 
1009
        (*loop-iteration-variables* nil)
 
1010
        (*loop-variables* nil)
 
1011
        (*loop-nodeclare* nil)
 
1012
        (*loop-named-variables* nil)
 
1013
        (*loop-declarations* nil)
 
1014
        (*loop-desetq-crocks* nil)
 
1015
        (*loop-bind-stack* nil)
 
1016
        (*loop-prologue* nil)
 
1017
        (*loop-wrappers* nil)
 
1018
        (*loop-before-loop* nil)
 
1019
        (*loop-body* nil)
 
1020
        (*loop-emitted-body* nil)
 
1021
        (*loop-after-body* nil)
 
1022
        (*loop-epilogue* nil)
 
1023
        (*loop-after-epilogue* nil)
 
1024
        (*loop-final-value-culprit* nil)
 
1025
        (*loop-inside-conditional* nil)
 
1026
        (*loop-when-it-variable* nil)
 
1027
        (*loop-never-stepped-variable* nil)
 
1028
        (*loop-names* nil)
 
1029
        (*loop-collection-cruft* nil))
 
1030
    (loop-iteration-driver)
 
1031
    (loop-bind-block)
 
1032
    (let ((answer `(loop-body
 
1033
                     ,(nreverse *loop-prologue*)
 
1034
                     ,(nreverse *loop-before-loop*)
 
1035
                     ,(nreverse *loop-body*)
 
1036
                     ,(nreverse *loop-after-body*)
 
1037
                     ,(nreconc *loop-epilogue* (nreverse *loop-after-epilogue*)))))
 
1038
      (dolist (entry *loop-bind-stack*)
 
1039
        (let ((vars (first entry))
 
1040
              (dcls (second entry))
 
1041
              (crocks (third entry))
 
1042
              (wrappers (fourth entry)))
 
1043
          (dolist (w wrappers)
 
1044
            (setq answer (append w (list answer))))
 
1045
          (when (or vars dcls crocks)
 
1046
            (let ((forms (list answer)))
 
1047
              ;;(when crocks (push crocks forms))
 
1048
              (when dcls (push `(declare ,@dcls) forms))
 
1049
              (setq answer `(,(cond ((not vars) 'locally)
 
1050
                                    (*loop-destructuring-hooks* (first *loop-destructuring-hooks*))
 
1051
                                    (t 'let))
 
1052
                             ,vars
 
1053
                             ,@(loop-build-destructuring-bindings crocks forms)))))))
 
1054
      (if *loop-names*
 
1055
          (do () ((null (car *loop-names*)) answer)
 
1056
            (setq answer `(block ,(pop *loop-names*) ,answer)))
 
1057
          `(block nil ,answer)))))
 
1058
 
 
1059
 
 
1060
(defun loop-iteration-driver ()
 
1061
  (do () ((null *loop-source-code*))
 
1062
    (let ((keyword (car *loop-source-code*)) (tem nil))
 
1063
      (cond ((not (symbolp keyword))
 
1064
             (loop-error "~S found where LOOP keyword expected." keyword))
 
1065
            (t (setq *loop-source-context* *loop-source-code*)
 
1066
               (loop-pop-source)
 
1067
               (cond ((setq tem (loop-lookup-keyword keyword (loop-universe-keywords *loop-universe*)))
 
1068
                      ;;It's a "miscellaneous" toplevel LOOP keyword (do, collect, named, etc.)
 
1069
                      (apply (symbol-function (first tem)) (rest tem)))
 
1070
                     ((setq tem (loop-lookup-keyword keyword (loop-universe-iteration-keywords *loop-universe*)))
 
1071
                      (loop-hack-iteration tem))
 
1072
                     ((loop-tmember keyword '(and else))
 
1073
                      ;; Alternative is to ignore it, ie let it go around to the next keyword...
 
1074
                      (loop-error "Secondary clause misplaced at top level in LOOP macro: ~S ~S ~S ..."
 
1075
                                  keyword (car *loop-source-code*) (cadr *loop-source-code*)))
 
1076
                     (t (loop-error "~S is an unknown keyword in LOOP macro." keyword))))))))
 
1077
 
 
1078
 
 
1079
 
 
1080
(defun loop-pop-source ()
 
1081
  (if *loop-source-code*
 
1082
      (pop *loop-source-code*)
 
1083
      (loop-error "LOOP source code ran out when another token was expected.")))
 
1084
 
 
1085
 
 
1086
(defun loop-get-compound-form ()
 
1087
  (let ((form (loop-get-form)))
 
1088
    (unless (consp form)
 
1089
      (loop-error "Compound form expected, but found ~A." form))
 
1090
    form))
 
1091
 
 
1092
(defun loop-get-progn ()
 
1093
  (do ((forms (list (loop-get-compound-form))
 
1094
              (cons (loop-get-compound-form) forms))
 
1095
       (nextform (car *loop-source-code*)
 
1096
                 (car *loop-source-code*)))
 
1097
      ((atom nextform)
 
1098
       (if (null (cdr forms)) (car forms) (cons 'progn (nreverse forms))))))
 
1099
 
 
1100
 
 
1101
(defun loop-get-form ()
 
1102
  (if *loop-source-code*
 
1103
      (loop-pop-source)
 
1104
      (loop-error "LOOP code ran out where a form was expected.")))
 
1105
 
 
1106
 
 
1107
(defun loop-construct-return (form)
 
1108
  `(return-from ,(car *loop-names*) ,form))
 
1109
 
 
1110
 
 
1111
(defun loop-pseudo-body (form)
 
1112
  (cond ((or *loop-emitted-body* *loop-inside-conditional*) (push form *loop-body*))
 
1113
        (t (push form *loop-before-loop*) (push form *loop-after-body*))))
 
1114
 
 
1115
(defun loop-emit-body (form)
 
1116
  (setq *loop-emitted-body* t)
 
1117
  (loop-pseudo-body form))
 
1118
 
 
1119
(defun loop-emit-final-value (&optional (form nil form-supplied-p))
 
1120
  (when form-supplied-p
 
1121
    (push (loop-construct-return form) *loop-after-epilogue*))
 
1122
  (when *loop-final-value-culprit*
 
1123
    (loop-warn "LOOP clause is providing a value for the iteration,~@
 
1124
                however one was already established by a ~S clause."
 
1125
               *loop-final-value-culprit*))
 
1126
  (setq *loop-final-value-culprit* (car *loop-source-context*)))
 
1127
 
 
1128
 
 
1129
(defun loop-disallow-conditional (&optional kwd)
 
1130
  #+(or Genera CLOE) (declare (dbg:error-reporter))
 
1131
  (when *loop-inside-conditional*
 
1132
    (loop-error "~:[This LOOP~;The LOOP ~:*~S~] clause is not permitted inside a conditional." kwd)))
 
1133
 
 
1134
(defun loop-disallow-anonymous-collectors ()
 
1135
  (when (find-if-not 'loop-collector-name *loop-collection-cruft*)
 
1136
    (loop-error "This LOOP clause is not permitted with anonymous collectors.")))
 
1137
 
 
1138
(defun loop-disallow-aggregate-booleans ()
 
1139
  (when (loop-tmember *loop-final-value-culprit* '(always never thereis))
 
1140
    (loop-error "This anonymous collection LOOP clause is not permitted with aggregate booleans.")))
 
1141
 
 
1142
 
 
1143
 
 
1144
;;;; Loop Types
 
1145
 
 
1146
 
 
1147
(defun loop-typed-init (data-type)
 
1148
  (when (and data-type (subtypep data-type 'number))
 
1149
    (if (or (subtypep data-type 'float) (subtypep data-type '(complex float)))
 
1150
        (coerce 0 data-type)
 
1151
        0)))
 
1152
 
 
1153
 
 
1154
(defun loop-optional-type (&optional variable)
 
1155
  ;;No variable specified implies that no destructuring is permissible.
 
1156
  (and *loop-source-code*                       ;Don't get confused by NILs...
 
1157
       (let ((z (car *loop-source-code*)))
 
1158
         (cond ((loop-tequal z 'of-type)
 
1159
                ;;This is the syntactically unambigous form in that the form of the
 
1160
                ;; type specifier does not matter.  Also, it is assumed that the
 
1161
                ;; type specifier is unambiguously, and without need of translation,
 
1162
                ;; a common lisp type specifier or pattern (matching the variable) thereof.
 
1163
                (loop-pop-source)
 
1164
                (loop-pop-source))
 
1165
                      
 
1166
               ((symbolp z)
 
1167
                ;;This is the (sort of) "old" syntax, even though we didn't used to support all of
 
1168
                ;; these type symbols.
 
1169
                (let ((type-spec (or (gethash z (loop-universe-type-symbols *loop-universe*))
 
1170
                                     (gethash (symbol-name z) (loop-universe-type-keywords *loop-universe*)))))
 
1171
                  (when type-spec
 
1172
                    (loop-pop-source)
 
1173
                    type-spec)))
 
1174
               (t 
 
1175
                ;;This is our sort-of old syntax.  But this is only valid for when we are destructuring,
 
1176
                ;; so we will be compulsive (should we really be?) and require that we in fact be
 
1177
                ;; doing variable destructuring here.  We must translate the old keyword pattern typespec
 
1178
                ;; into a fully-specified pattern of real type specifiers here.
 
1179
                (if (consp variable)
 
1180
                    (unless (consp z)
 
1181
                     (loop-error
 
1182
                        "~S found where a LOOP keyword, LOOP type keyword, or LOOP type pattern expected."
 
1183
                        z))
 
1184
                    (loop-error "~S found where a LOOP keyword or LOOP type keyword expected." z))
 
1185
                (loop-pop-source)
 
1186
                (labels ((translate (k v)
 
1187
                           (cond ((null k) nil)
 
1188
                                 ((atom k)
 
1189
                                  (replicate
 
1190
                                    (or (gethash k (loop-universe-type-symbols *loop-universe*))
 
1191
                                        (gethash (symbol-name k) (loop-universe-type-keywords *loop-universe*))
 
1192
                                        (loop-error
 
1193
                                          "Destructuring type pattern ~S contains unrecognized type keyword ~S."
 
1194
                                          z k))
 
1195
                                    v))
 
1196
                                 ((atom v)
 
1197
                                  (loop-error
 
1198
                                    "Destructuring type pattern ~S doesn't match variable pattern ~S."
 
1199
                                    z variable))
 
1200
                                 (t (cons (translate (car k) (car v)) (translate (cdr k) (cdr v))))))
 
1201
                         (replicate (typ v)
 
1202
                           (if (atom v) typ (cons (replicate typ (car v)) (replicate typ (cdr v))))))
 
1203
                  (translate z variable)))))))
 
1204
 
 
1205
 
 
1206
 
 
1207
;;;; Loop Variables
 
1208
 
 
1209
 
 
1210
(defun loop-bind-block ()
 
1211
  (when (or *loop-variables* *loop-declarations* *loop-wrappers*)
 
1212
    (push (list (nreverse *loop-variables*) *loop-declarations* *loop-desetq-crocks* *loop-wrappers*)
 
1213
          *loop-bind-stack*)
 
1214
    (setq *loop-variables* nil
 
1215
          *loop-declarations* nil
 
1216
          *loop-desetq-crocks* nil
 
1217
          *loop-wrappers* nil)))
 
1218
 
 
1219
(defun loop-variable-p (name)
 
1220
  (do ((entry *loop-bind-stack* (cdr entry))) (nil)
 
1221
    (cond ((null entry)
 
1222
           (return nil))
 
1223
          ((assoc name (caar entry) :test #'eq)
 
1224
           (return t)))))
 
1225
 
 
1226
(defun loop-make-variable (name initialization dtype &optional iteration-variable-p)
 
1227
  (cond ((null name)
 
1228
         (cond ((not (null initialization))
 
1229
                (push (list (setq name (loop-gentemp 'loop-ignore-))
 
1230
                            initialization)
 
1231
                      *loop-variables*)
 
1232
                (push `(ignore ,name) *loop-declarations*))))
 
1233
        ((atom name)
 
1234
         (cond (iteration-variable-p
 
1235
                (if (member name *loop-iteration-variables*)
 
1236
                    (loop-error "Duplicated LOOP iteration variable ~S." name)
 
1237
                    (push name *loop-iteration-variables*)))
 
1238
               ((assoc name *loop-variables*)
 
1239
                (loop-error "Duplicated variable ~S in LOOP parallel binding." name)))
 
1240
         (unless (symbolp name)
 
1241
           (loop-error "Bad variable ~S somewhere in LOOP." name))
 
1242
         (loop-declare-variable name dtype)
 
1243
         ;; We use ASSOC on this list to check for duplications (above),
 
1244
         ;; so don't optimize out this list:
 
1245
         (push (list name (or initialization (loop-typed-init dtype)))
 
1246
               *loop-variables*))
 
1247
        (initialization
 
1248
         (cond (*loop-destructuring-hooks*
 
1249
                (loop-declare-variable name dtype)
 
1250
                (push (list name initialization) *loop-variables*))
 
1251
               (t (let ((newvar (loop-gentemp 'loop-destructure-)))
 
1252
                    (loop-declare-variable name dtype)
 
1253
                    (push (list newvar initialization) *loop-variables*)
 
1254
                    ;; *LOOP-DESETQ-CROCKS* gathered in reverse order.
 
1255
                    (setq *loop-desetq-crocks*
 
1256
                      (list* name newvar *loop-desetq-crocks*))
 
1257
                    #+ignore
 
1258
                    (loop-make-variable name nil dtype iteration-variable-p)))))
 
1259
        (t (let ((tcar nil) (tcdr nil))
 
1260
             (if (atom dtype) (setq tcar (setq tcdr dtype))
 
1261
                 (setq tcar (car dtype) tcdr (cdr dtype)))
 
1262
             (loop-make-variable (car name) nil tcar iteration-variable-p)
 
1263
             (loop-make-variable (cdr name) nil tcdr iteration-variable-p))))
 
1264
  name)
 
1265
 
 
1266
 
 
1267
(defun loop-make-iteration-variable (name initialization dtype)
 
1268
  (loop-make-variable name initialization dtype t))
 
1269
 
 
1270
 
 
1271
(defun loop-declare-variable (name dtype)
 
1272
  (cond ((or (null name) (null dtype) (eq dtype t)) nil)
 
1273
        ((symbolp name)
 
1274
         (unless (or (eq dtype t) (member (the symbol name) *loop-nodeclare*))
 
1275
           (let ((dtype #-cmu dtype
 
1276
                        #+cmu
 
1277
                        (let ((init (loop-typed-init dtype)))
 
1278
                          (if (typep init dtype)
 
1279
                              dtype
 
1280
                              `(or (member ,init) ,dtype)))))
 
1281
             (push `(type ,dtype ,name) *loop-declarations*))))
 
1282
        ((consp name)
 
1283
         (cond ((consp dtype)
 
1284
                (loop-declare-variable (car name) (car dtype))
 
1285
                (loop-declare-variable (cdr name) (cdr dtype)))
 
1286
               (t (loop-declare-variable (car name) dtype)
 
1287
                  (loop-declare-variable (cdr name) dtype))))
 
1288
        (t (error "Invalid LOOP variable passed in: ~S." name))))
 
1289
 
 
1290
 
 
1291
(defun loop-maybe-bind-form (form data-type)
 
1292
  (if (loop-constantp form)
 
1293
      form
 
1294
      (loop-make-variable (loop-gentemp 'loop-bind-) form data-type)))
 
1295
 
 
1296
 
 
1297
 
 
1298
(defun loop-do-if (for negatep)
 
1299
  (let ((form (loop-get-form))
 
1300
        (*loop-inside-conditional* t)
 
1301
        (it-p nil)
 
1302
        (first-clause-p t))
 
1303
    (flet ((get-clause (for)
 
1304
             (do ((body nil)) (nil)
 
1305
               (let ((key (car *loop-source-code*)) (*loop-body* nil) data)
 
1306
                 (cond ((not (symbolp key))
 
1307
                        (loop-error
 
1308
                          "~S found where keyword expected getting LOOP clause after ~S."
 
1309
                          key for))
 
1310
                       (t (setq *loop-source-context* *loop-source-code*)
 
1311
                          (loop-pop-source)
 
1312
                          (when (and (loop-tequal (car *loop-source-code*) 'it)
 
1313
                                     first-clause-p)
 
1314
                            (setq *loop-source-code*
 
1315
                                  (cons (or it-p (setq it-p (loop-when-it-variable)))
 
1316
                                        (cdr *loop-source-code*))))
 
1317
                          (cond ((or (not (setq data (loop-lookup-keyword
 
1318
                                                       key (loop-universe-keywords *loop-universe*))))
 
1319
                                     (progn (apply (symbol-function (car data)) (cdr data))
 
1320
                                            (null *loop-body*)))
 
1321
                                 (loop-error
 
1322
                                   "~S does not introduce a LOOP clause that can follow ~S."
 
1323
                                   key for))
 
1324
                                (t (setq body (nreconc *loop-body* body)))))))
 
1325
               (setq first-clause-p nil)
 
1326
               (if (loop-tequal (car *loop-source-code*) :and)
 
1327
                   (loop-pop-source)
 
1328
                   (return (if (cdr body) `(progn ,@(nreverse body)) (car body)))))))
 
1329
      (let ((then (get-clause for))
 
1330
            (else (when (loop-tequal (car *loop-source-code*) :else)
 
1331
                    (loop-pop-source)
 
1332
                    (list (get-clause :else)))))
 
1333
        (when (loop-tequal (car *loop-source-code*) :end)
 
1334
          (loop-pop-source))
 
1335
        (when it-p (setq form `(setq ,it-p ,form)))
 
1336
        (loop-pseudo-body
 
1337
          `(if ,(if negatep `(not ,form) form)
 
1338
               ,then
 
1339
               ,@else))))))
 
1340
 
 
1341
 
 
1342
(defun loop-do-initially ()
 
1343
  (loop-disallow-conditional :initially)
 
1344
  (push (loop-get-progn) *loop-prologue*))
 
1345
 
 
1346
(defun loop-do-finally ()
 
1347
  (loop-disallow-conditional :finally)
 
1348
  (push (loop-get-progn) *loop-epilogue*))
 
1349
 
 
1350
(defun loop-do-do ()
 
1351
  (loop-emit-body (loop-get-progn)))
 
1352
 
 
1353
(defun loop-do-named ()
 
1354
  (let ((name (loop-pop-source)))
 
1355
    (unless (symbolp name)
 
1356
      (loop-error "~S is an invalid name for your LOOP." name))
 
1357
    (when (or *loop-before-loop* *loop-body* *loop-after-epilogue* *loop-inside-conditional*)
 
1358
      (loop-error "The NAMED ~S clause occurs too late." name))
 
1359
    (when *loop-names*
 
1360
      (loop-error "You may only use one NAMED clause in your loop: NAMED ~S ... NAMED ~S."
 
1361
                  (car *loop-names*) name))
 
1362
    (setq *loop-names* (list name nil))))
 
1363
 
 
1364
(defun loop-do-return ()
 
1365
  (loop-pseudo-body (loop-construct-return (loop-get-form))))
 
1366
 
 
1367
 
 
1368
;;;; Value Accumulation: List
 
1369
 
 
1370
 
 
1371
(defstruct (loop-collector
 
1372
             (:copier nil)
 
1373
             (:predicate nil))
 
1374
  name
 
1375
  class
 
1376
  (history nil)
 
1377
  (tempvars nil)
 
1378
  dtype
 
1379
  (data nil))                                           ;collector-specific data
 
1380
 
 
1381
 
 
1382
(defun loop-get-collection-info (collector class default-type)
 
1383
  (let ((form (loop-get-form))
 
1384
        (dtype (and (not (loop-universe-ansi *loop-universe*)) (loop-optional-type)))
 
1385
        (name (when (loop-tequal (car *loop-source-code*) 'into)
 
1386
                (loop-pop-source)
 
1387
                (loop-pop-source))))
 
1388
    (when (not (symbolp name))
 
1389
      (loop-error "Value accumulation recipient name, ~S, is not a symbol." name))
 
1390
    (unless name
 
1391
      (loop-disallow-aggregate-booleans))
 
1392
    (unless dtype
 
1393
      (setq dtype (or (loop-optional-type) default-type)))
 
1394
    (let ((cruft (find (the symbol name) *loop-collection-cruft*
 
1395
                       :key #'loop-collector-name)))
 
1396
      (cond ((not cruft)
 
1397
             (when (and name (loop-variable-p name))
 
1398
               (loop-error "Variable ~S cannot be used in INTO clause" name))
 
1399
             (push (setq cruft (make-loop-collector
 
1400
                                 :name name :class class
 
1401
                                 :history (list collector) :dtype dtype))
 
1402
                   *loop-collection-cruft*))
 
1403
            (t (unless (eq (loop-collector-class cruft) class)
 
1404
                 (loop-error
 
1405
                   "Incompatible kinds of LOOP value accumulation specified for collecting~@
 
1406
                    ~:[as the value of the LOOP~;~:*INTO ~S~]: ~S and ~S."
 
1407
                   name (car (loop-collector-history cruft)) collector))
 
1408
               (unless (equal dtype (loop-collector-dtype cruft))
 
1409
                 (loop-warn
 
1410
                   "Unequal datatypes specified in different LOOP value accumulations~@
 
1411
                   into ~S: ~S and ~S."
 
1412
                   name dtype (loop-collector-dtype cruft))
 
1413
                 (when (eq (loop-collector-dtype cruft) t)
 
1414
                   (setf (loop-collector-dtype cruft) dtype)))
 
1415
               (push collector (loop-collector-history cruft))))
 
1416
      (values cruft form))))
 
1417
 
 
1418
 
 
1419
(defun loop-list-collection (specifically)      ;NCONC, LIST, or APPEND
 
1420
  (multiple-value-bind (lc form) (loop-get-collection-info specifically 'list 'list)
 
1421
    (let ((tempvars (loop-collector-tempvars lc)))
 
1422
      (unless tempvars
 
1423
        (setf (loop-collector-tempvars lc)
 
1424
              (setq tempvars (list* (loop-gentemp 'loop-list-head-)
 
1425
                                    (loop-gentemp 'loop-list-tail-)
 
1426
                                    (and (loop-collector-name lc)
 
1427
                                         (list (loop-collector-name lc))))))
 
1428
        (push `(with-loop-list-collection-head ,tempvars) *loop-wrappers*)
 
1429
        (unless (loop-collector-name lc)
 
1430
          (loop-emit-final-value `(loop-collect-answer ,(car tempvars) ,@(cddr tempvars)))))
 
1431
      (ecase specifically
 
1432
        (list (setq form `(list ,form)))
 
1433
        (nconc nil)
 
1434
        (append (unless (and (consp form) (eq (car form) 'list))
 
1435
                  (setq form `(loop-copylist* ,form)))))
 
1436
      (loop-emit-body `(loop-collect-rplacd ,tempvars ,form)))))
 
1437
 
 
1438
 
 
1439
;;;; Value Accumulation: max, min, sum, count.
 
1440
 
 
1441
 
 
1442
 
 
1443
(defun loop-sum-collection (specifically required-type default-type)    ;SUM, COUNT
 
1444
  (multiple-value-bind (lc form)
 
1445
      (loop-get-collection-info specifically 'sum default-type)
 
1446
    (loop-check-data-type (loop-collector-dtype lc) required-type)
 
1447
    (let ((tempvars (loop-collector-tempvars lc)))
 
1448
      (unless tempvars
 
1449
        (setf (loop-collector-tempvars lc)
 
1450
              (setq tempvars (list (loop-make-variable
 
1451
                                     (or (loop-collector-name lc)
 
1452
                                         (loop-gentemp 'loop-sum-))
 
1453
                                     nil (loop-collector-dtype lc)))))
 
1454
        (unless (loop-collector-name lc)
 
1455
          (loop-emit-final-value (car (loop-collector-tempvars lc)))))
 
1456
      (loop-emit-body
 
1457
        (if (eq specifically 'count)
 
1458
            `(when ,form
 
1459
               (setq ,(car tempvars)
 
1460
                     ,(hide-variable-reference t (car tempvars) `(1+ ,(car tempvars)))))
 
1461
            `(setq ,(car tempvars)
 
1462
                   (+ ,(hide-variable-reference t (car tempvars) (car tempvars))
 
1463
                      ,form)))))))
 
1464
 
 
1465
 
 
1466
 
 
1467
(defun loop-maxmin-collection (specifically)
 
1468
  (multiple-value-bind (lc form)
 
1469
      (loop-get-collection-info specifically 'maxmin *loop-real-data-type*)
 
1470
    (loop-check-data-type (loop-collector-dtype lc) *loop-real-data-type*)
 
1471
    (let ((data (loop-collector-data lc)))
 
1472
      (unless data
 
1473
        (setf (loop-collector-data lc)
 
1474
              (setq data (make-loop-minimax
 
1475
                           (or (loop-collector-name lc) (loop-gentemp 'loop-maxmin-))
 
1476
                           (loop-collector-dtype lc))))
 
1477
        (unless (loop-collector-name lc)
 
1478
          (loop-emit-final-value (loop-minimax-answer-variable data))))
 
1479
      (loop-note-minimax-operation specifically data)
 
1480
      (push `(with-minimax-value ,data) *loop-wrappers*)
 
1481
      (loop-emit-body `(loop-accumulate-minimax-value ,data ,specifically ,form))
 
1482
      )))
 
1483
 
 
1484
 
 
1485
;;;; Value Accumulation:  Aggregate Booleans
 
1486
 
 
1487
;;;ALWAYS and NEVER.
 
1488
;;; Under ANSI these are not permitted to appear under conditionalization.
 
1489
(defun loop-do-always (restrictive negate)
 
1490
  (let ((form (loop-get-form)))
 
1491
    (when restrictive (loop-disallow-conditional))
 
1492
    (loop-disallow-anonymous-collectors)
 
1493
    (loop-emit-body `(,(if negate 'when 'unless) ,form
 
1494
                      ,(loop-construct-return nil)))
 
1495
    (loop-emit-final-value t)))
 
1496
 
 
1497
 
 
1498
 
 
1499
;;;THERIS.
 
1500
;;; Under ANSI this is not permitted to appear under conditionalization.
 
1501
(defun loop-do-thereis (restrictive)
 
1502
  (when restrictive (loop-disallow-conditional))
 
1503
  (loop-disallow-anonymous-collectors)
 
1504
  (loop-emit-final-value)
 
1505
  (loop-emit-body `(when (setq ,(loop-when-it-variable) ,(loop-get-form))
 
1506
                     ,(loop-construct-return *loop-when-it-variable*))))
 
1507
 
 
1508
 
 
1509
(defun loop-do-while (negate kwd &aux (form (loop-get-form)))
 
1510
  (loop-disallow-conditional kwd)
 
1511
  (loop-pseudo-body `(,(if negate 'when 'unless) ,form (go end-loop))))
 
1512
 
 
1513
 
 
1514
(defun loop-do-with ()
 
1515
  (loop-disallow-conditional :with)
 
1516
  (do ((var) (val) (dtype)) (nil)
 
1517
    (setq var (loop-pop-source)
 
1518
          dtype (loop-optional-type var)
 
1519
          val (cond ((loop-tequal (car *loop-source-code*) :=)
 
1520
                     (loop-pop-source)
 
1521
                     (loop-get-form))
 
1522
                    (t nil)))
 
1523
    (when (and var (loop-variable-p var))
 
1524
      (loop-error "Variable ~S has already been used" var))
 
1525
    (loop-make-variable var val dtype)
 
1526
    (if (loop-tequal (car *loop-source-code*) :and)
 
1527
        (loop-pop-source)
 
1528
        (return (loop-bind-block)))))
 
1529
 
 
1530
 
 
1531
;;;; The iteration driver
 
1532
 
 
1533
(defun loop-hack-iteration (entry)
 
1534
  (flet ((make-endtest (list-of-forms)
 
1535
           (cond ((null list-of-forms) nil)
 
1536
                 ((member t list-of-forms) '(go end-loop))
 
1537
                 (t `(when ,(if (null (cdr (setq list-of-forms (nreverse list-of-forms))))
 
1538
                                (car list-of-forms)
 
1539
                                (cons 'or list-of-forms))
 
1540
                       (go end-loop))))))
 
1541
    (do ((pre-step-tests nil)
 
1542
         (steps nil)
 
1543
         (post-step-tests nil)
 
1544
         (pseudo-steps nil)
 
1545
         (pre-loop-pre-step-tests nil)
 
1546
         (pre-loop-steps nil)
 
1547
         (pre-loop-post-step-tests nil)
 
1548
         (pre-loop-pseudo-steps nil)
 
1549
         (tem) (data))
 
1550
        (nil)
 
1551
      ;; Note we collect endtests in reverse order, but steps in correct
 
1552
      ;; order.  MAKE-ENDTEST does the nreverse for us.
 
1553
      (setq tem (setq data (apply (symbol-function (first entry)) (rest entry))))
 
1554
      (and (car tem) (push (car tem) pre-step-tests))
 
1555
      (setq steps (nconc steps (loop-copylist* (car (setq tem (cdr tem))))))
 
1556
      (and (car (setq tem (cdr tem))) (push (car tem) post-step-tests))
 
1557
      (setq pseudo-steps (nconc pseudo-steps (loop-copylist* (car (setq tem (cdr tem))))))
 
1558
      (setq tem (cdr tem))
 
1559
      (when *loop-emitted-body*
 
1560
        (loop-error "Iteration in LOOP follows body code."))
 
1561
      (unless tem (setq tem data))
 
1562
      (when (car tem) (push (car tem) pre-loop-pre-step-tests))
 
1563
      (setq pre-loop-steps (nconc pre-loop-steps (loop-copylist* (car (setq tem (cdr tem))))))
 
1564
      (when (car (setq tem (cdr tem))) (push (car tem) pre-loop-post-step-tests))
 
1565
      (setq pre-loop-pseudo-steps (nconc pre-loop-pseudo-steps (loop-copylist* (cadr tem))))
 
1566
      (unless (loop-tequal (car *loop-source-code*) :and)
 
1567
        (setq *loop-before-loop* (list* (loop-make-desetq pre-loop-pseudo-steps)
 
1568
                                        (make-endtest pre-loop-post-step-tests)
 
1569
                                        (loop-make-psetq pre-loop-steps)
 
1570
                                        (make-endtest pre-loop-pre-step-tests)
 
1571
                                        *loop-before-loop*)
 
1572
              *loop-after-body* (list* (loop-make-desetq pseudo-steps)
 
1573
                                       (make-endtest post-step-tests)
 
1574
                                       (loop-make-psetq steps)
 
1575
                                       (make-endtest pre-step-tests)
 
1576
                                       *loop-after-body*))
 
1577
        (loop-bind-block)
 
1578
        (return nil))
 
1579
      (loop-pop-source)                         ; flush the "AND"
 
1580
      (when (and (not (loop-universe-implicit-for-required *loop-universe*))
 
1581
                 (setq tem (loop-lookup-keyword
 
1582
                             (car *loop-source-code*)
 
1583
                             (loop-universe-iteration-keywords *loop-universe*))))
 
1584
        ;;Latest ANSI clarification is that the FOR/AS after the AND must NOT be supplied.
 
1585
        (loop-pop-source)
 
1586
        (setq entry tem)))))
 
1587
 
 
1588
 
 
1589
;;;; Main Iteration Drivers
 
1590
 
 
1591
 
 
1592
;FOR variable keyword ..args..
 
1593
(defun loop-do-for ()
 
1594
  (let* ((var (loop-pop-source))
 
1595
         (data-type (loop-optional-type var))
 
1596
         (keyword (loop-pop-source))
 
1597
         (first-arg nil)
 
1598
         (tem nil))
 
1599
    (setq first-arg (loop-get-form))
 
1600
    (unless (and (symbolp keyword)
 
1601
                 (setq tem (loop-lookup-keyword
 
1602
                             keyword
 
1603
                             (loop-universe-for-keywords *loop-universe*))))
 
1604
      (loop-error "~S is an unknown keyword in FOR or AS clause in LOOP." keyword))
 
1605
    (apply (car tem) var first-arg data-type (cdr tem))))
 
1606
 
 
1607
(defun loop-do-repeat ()
 
1608
  (loop-disallow-conditional :repeat)
 
1609
  (let ((form (loop-get-form))
 
1610
        (type 'real))
 
1611
    (let ((var (loop-make-variable (loop-gentemp) form type)))
 
1612
      (push `(when (minusp (decf ,var)) (go end-loop)) *loop-before-loop*)
 
1613
      (push `(when (minusp (decf ,var)) (go end-loop)) *loop-after-body*)
 
1614
      ;; FIXME: What should
 
1615
      ;;   (loop count t into a
 
1616
      ;;         repeat 3
 
1617
      ;;         count t into b
 
1618
      ;;         finally (return (list a b)))
 
1619
      ;; return: (3 3) or (4 3)? PUSHes above are for the former
 
1620
      ;; variant, L-P-B below for the latter.
 
1621
      #+nil (loop-pseudo-body `(when (minusp (decf ,var)) (go end-loop))))))
 
1622
 
 
1623
(defun loop-when-it-variable ()
 
1624
  (or *loop-when-it-variable*
 
1625
      (setq *loop-when-it-variable*
 
1626
            (loop-make-variable (loop-gentemp 'loop-it-) nil nil))))
 
1627
 
 
1628
 
 
1629
;;;; Various FOR/AS Subdispatches
 
1630
 
 
1631
 
 
1632
;;;ANSI "FOR x = y [THEN z]" is sort of like the old Genera one when the THEN
 
1633
;;; is omitted (other than being more stringent in its placement), and like
 
1634
;;; the old "FOR x FIRST y THEN z" when the THEN is present.  I.e., the first
 
1635
;;; initialization occurs in the loop body (first-step), not in the variable binding
 
1636
;;; phase.
 
1637
(defun loop-ansi-for-equals (var val data-type)
 
1638
  (loop-make-iteration-variable var nil data-type)
 
1639
  (cond ((loop-tequal (car *loop-source-code*) :then)
 
1640
         ;;Then we are the same as "FOR x FIRST y THEN z".
 
1641
         (loop-pop-source)
 
1642
         `(() (,var ,(loop-get-form)) () ()
 
1643
           () (,var ,val) () ()))
 
1644
        (t ;;We are the same as "FOR x = y".
 
1645
         `(() (,var ,val) () ()))))
 
1646
 
 
1647
 
 
1648
(defun loop-for-across (var val data-type)
 
1649
  (loop-make-iteration-variable var nil data-type)
 
1650
  (let ((vector-var (loop-gentemp 'loop-across-vector-))
 
1651
        (index-var (loop-gentemp 'loop-across-index-)))
 
1652
    (multiple-value-bind (vector-form constantp vector-value)
 
1653
        (loop-constant-fold-if-possible val 'vector)
 
1654
      (loop-make-variable
 
1655
        vector-var vector-form
 
1656
        (if (and (consp vector-form) (eq (car vector-form) 'the))
 
1657
            (cadr vector-form)
 
1658
            'vector))
 
1659
      #+Genera (push `(system:array-register ,vector-var) *loop-declarations*)
 
1660
      (loop-make-variable index-var 0 'fixnum)
 
1661
      (let* ((length 0)
 
1662
             (length-form (cond ((not constantp)
 
1663
                                 (let ((v (loop-gentemp 'loop-across-limit-)))
 
1664
                                   (push `(setq ,v (length ,vector-var)) *loop-prologue*)
 
1665
                                   (loop-make-variable v 0 'fixnum)))
 
1666
                                (t (setq length (length vector-value)))))
 
1667
             (first-test `(>= ,index-var ,length-form))
 
1668
             (other-test first-test)
 
1669
             (step `(,var (aref ,vector-var ,index-var)))
 
1670
             (pstep `(,index-var (1+ ,index-var))))
 
1671
        (declare (fixnum length))
 
1672
        (when constantp
 
1673
          (setq first-test (= length 0))
 
1674
          (when (<= length 1)
 
1675
            (setq other-test t)))
 
1676
        `(,other-test ,step () ,pstep
 
1677
          ,@(and (not (eq first-test other-test)) `(,first-test ,step () ,pstep)))))))
 
1678
 
 
1679
 
 
1680
 
 
1681
;;;; List Iteration
 
1682
 
 
1683
 
 
1684
(defun loop-list-step (listvar)
 
1685
  ;;We are not equipped to analyze whether 'FOO is the same as #'FOO here in any
 
1686
  ;; sensible fashion, so let's give an obnoxious warning whenever 'FOO is used
 
1687
  ;; as the stepping function.
 
1688
  ;;While a Discerning Compiler may deal intelligently with (funcall 'foo ...), not
 
1689
  ;; recognizing FOO may defeat some LOOP optimizations.
 
1690
  (let ((stepper (cond ((loop-tequal (car *loop-source-code*) :by)
 
1691
                        (loop-pop-source)
 
1692
                        (loop-get-form))
 
1693
                       (t '(function cdr)))))
 
1694
    (cond ((and (consp stepper) (eq (car stepper) 'quote))
 
1695
           (loop-warn "Use of QUOTE around stepping function in LOOP will be left verbatim.")
 
1696
           (values `(funcall ,stepper ,listvar) nil))
 
1697
          ((and (consp stepper) (eq (car stepper) 'function))
 
1698
           (values (list (cadr stepper) listvar) (cadr stepper)))
 
1699
          (t (values `(funcall ,(loop-make-variable (loop-gentemp 'loop-fn-) stepper 'function)
 
1700
                               ,listvar)
 
1701
                     nil)))))
 
1702
 
 
1703
 
 
1704
(defun loop-for-on (var val data-type)
 
1705
  (multiple-value-bind (list constantp list-value) (loop-constant-fold-if-possible val)
 
1706
    (let ((listvar var))
 
1707
      (cond ((and var (symbolp var)) (loop-make-iteration-variable var list data-type))
 
1708
            (t (loop-make-variable (setq listvar (loop-gentemp)) list 'list)
 
1709
               (loop-make-iteration-variable var nil data-type)))
 
1710
      (multiple-value-bind (list-step step-function) (loop-list-step listvar)
 
1711
        (declare #+(and (not LOOP-Prefer-POP) (not CLOE)) (ignore step-function))
 
1712
        ;;@@@@ The CLOE problem above has to do with bug in macroexpansion of multiple-value-bind.
 
1713
        (let* ((first-endtest
 
1714
                (hide-variable-reference
 
1715
                 (eq var listvar)
 
1716
                 listvar
 
1717
                 ;; the following should use `atom' instead of `endp', per
 
1718
                 ;; [bug2428]
 
1719
                 `(atom ,listvar)))
 
1720
               (other-endtest first-endtest))
 
1721
          (when (and constantp (listp list-value))
 
1722
            (setq first-endtest (null list-value)))
 
1723
          (cond ((eq var listvar)
 
1724
                 ;;Contour of the loop is different because we use the user's variable...
 
1725
                 `(() (,listvar ,(hide-variable-reference t listvar list-step)) ,other-endtest
 
1726
                   () () () ,first-endtest ()))
 
1727
                #+LOOP-Prefer-POP
 
1728
                ((and step-function
 
1729
                      (let ((n (cdr (assoc step-function '((cdr . 1) (cddr . 2)
 
1730
                                                           (cdddr . 3) (cddddr . 4))))))
 
1731
                        (and n (do ((l var (cdr l)) (i 0 (1+ i)))
 
1732
                                   ((atom l) (and (null l) (= i n)))
 
1733
                                 (declare (fixnum i))))))
 
1734
                 (let ((step (mapcan #'(lambda (x) (list x `(pop ,listvar))) var)))
 
1735
                   `(,other-endtest () () ,step ,first-endtest () () ,step)))
 
1736
                (t (let ((step `(,var ,listvar)) (pseudo `(,listvar ,list-step)))
 
1737
                     `(,other-endtest ,step () ,pseudo
 
1738
                       ,@(and (not (eq first-endtest other-endtest))
 
1739
                              `(,first-endtest ,step () ,pseudo)))))))))))
 
1740
 
 
1741
 
 
1742
(defun loop-for-in (var val data-type)
 
1743
  (multiple-value-bind (list constantp list-value) (loop-constant-fold-if-possible val)
 
1744
    (let ((listvar (loop-gentemp 'loop-list-)))
 
1745
      (loop-make-iteration-variable var nil data-type)
 
1746
      (loop-make-variable listvar list 'list)
 
1747
      (multiple-value-bind (list-step step-function) (loop-list-step listvar)
 
1748
        #-LOOP-Prefer-POP (declare (ignore step-function))
 
1749
        (let* ((first-endtest `(endp ,listvar))
 
1750
               (other-endtest first-endtest)
 
1751
               (step `(,var (car ,listvar)))
 
1752
               (pseudo-step `(,listvar ,list-step)))
 
1753
          (when (and constantp (listp list-value))
 
1754
            (setq first-endtest (null list-value)))
 
1755
          #+LOOP-Prefer-POP (when (eq step-function 'cdr)
 
1756
                              (setq step `(,var (pop ,listvar)) pseudo-step nil))
 
1757
          `(,other-endtest ,step () ,pseudo-step
 
1758
            ,@(and (not (eq first-endtest other-endtest))
 
1759
                   `(,first-endtest ,step () ,pseudo-step))))))))
 
1760
 
 
1761
 
 
1762
;;;; Iteration Paths
 
1763
 
 
1764
 
 
1765
(defstruct (loop-path
 
1766
             (:copier nil)
 
1767
             (:predicate nil))
 
1768
  names
 
1769
  preposition-groups
 
1770
  inclusive-permitted
 
1771
  function
 
1772
  user-data)
 
1773
 
 
1774
 
 
1775
(defun add-loop-path (names function universe &key preposition-groups inclusive-permitted user-data)
 
1776
  (unless (listp names) (setq names (list names)))
 
1777
  ;; Can't do this due to CLOS bootstrapping problems.
 
1778
  #-(or Genera (and CLOE Source-Bootstrap)) (check-type universe loop-universe)
 
1779
  (let ((ht (loop-universe-path-keywords universe))
 
1780
        (lp (make-loop-path
 
1781
              :names (mapcar #'symbol-name names)
 
1782
              :function function
 
1783
              :user-data user-data
 
1784
              :preposition-groups (mapcar #'(lambda (x) (if (listp x) x (list x))) preposition-groups)
 
1785
              :inclusive-permitted inclusive-permitted)))
 
1786
    (dolist (name names) (setf (gethash (symbol-name name) ht) lp))
 
1787
    lp))
 
1788
 
 
1789
 
 
1790
;;; Note:  path functions are allowed to use loop-make-variable, hack
 
1791
;;; the prologue, etc.
 
1792
(defun loop-for-being (var val data-type)
 
1793
  ;; FOR var BEING each/the pathname prep-phrases using-stuff...
 
1794
  ;; each/the = EACH or THE.  Not clear if it is optional, so I guess we'll warn.
 
1795
  (let ((path nil)
 
1796
        (data nil)
 
1797
        (inclusive nil)
 
1798
        (stuff nil)
 
1799
        (initial-prepositions nil))
 
1800
    (cond ((loop-tmember val '(:each :the)) (setq path (loop-pop-source)))
 
1801
          ((loop-tequal (car *loop-source-code*) :and)
 
1802
           (loop-pop-source)
 
1803
           (setq inclusive t)
 
1804
           (unless (loop-tmember (car *loop-source-code*) '(:its :each :his :her))
 
1805
             (loop-error "~S found where ITS or EACH expected in LOOP iteration path syntax."
 
1806
                         (car *loop-source-code*)))
 
1807
           (loop-pop-source)
 
1808
           (setq path (loop-pop-source))
 
1809
           (setq initial-prepositions `((:in ,val))))
 
1810
          (t (loop-error "Unrecognizable LOOP iteration path syntax.  Missing EACH or THE?")))
 
1811
    (cond ((not (symbolp path))
 
1812
           (loop-error "~S found where a LOOP iteration path name was expected." path))
 
1813
          ((not (setq data (loop-lookup-keyword path (loop-universe-path-keywords *loop-universe*))))
 
1814
           (loop-error "~S is not the name of a LOOP iteration path." path))
 
1815
          ((and inclusive (not (loop-path-inclusive-permitted data)))
 
1816
           (loop-error "\"Inclusive\" iteration is not possible with the ~S LOOP iteration path." path)))
 
1817
    (let ((fun (loop-path-function data))
 
1818
          (preps (nconc initial-prepositions
 
1819
                        (loop-collect-prepositional-phrases (loop-path-preposition-groups data) t)))
 
1820
          (user-data (loop-path-user-data data)))
 
1821
      (when (symbolp fun) (setq fun (symbol-function fun)))
 
1822
      (setq stuff (if inclusive
 
1823
                      (apply fun var data-type preps :inclusive t user-data)
 
1824
                      (apply fun var data-type preps user-data))))
 
1825
    (when *loop-named-variables*
 
1826
      (loop-error "Unused USING variables: ~S." *loop-named-variables*))
 
1827
    ;; STUFF is now (bindings prologue-forms . stuff-to-pass-back).  Protect the system from the user
 
1828
    ;; and the user from himself.
 
1829
    (unless (member (length stuff) '(6 10))
 
1830
      (loop-error "Value passed back by LOOP iteration path function for path ~S has invalid length."
 
1831
                  path))
 
1832
    (do ((l (car stuff) (cdr l)) (x)) ((null l))
 
1833
      (if (atom (setq x (car l)))
 
1834
          (loop-make-iteration-variable x nil nil)
 
1835
          (loop-make-iteration-variable (car x) (cadr x) (caddr x))))
 
1836
    (setq *loop-prologue* (nconc (reverse (cadr stuff)) *loop-prologue*))
 
1837
    (cddr stuff)))
 
1838
 
 
1839
 
 
1840
 
 
1841
;;;INTERFACE:  Lucid, exported.
 
1842
;;; i.e., this is part of our extended ansi-loop interface.
 
1843
(defun named-variable (name)
 
1844
  (let ((tem (loop-tassoc name *loop-named-variables*)))
 
1845
    (declare (list tem))
 
1846
    (cond ((null tem) (values (loop-gentemp) nil))
 
1847
          (t (setq *loop-named-variables* (delete tem *loop-named-variables*))
 
1848
             (values (cdr tem) t)))))
 
1849
 
 
1850
 
 
1851
(defun loop-collect-prepositional-phrases (preposition-groups &optional USING-allowed initial-phrases)
 
1852
  (flet ((in-group-p (x group) (car (loop-tmember x group))))
 
1853
    (do ((token nil)
 
1854
         (prepositional-phrases initial-phrases)
 
1855
         (this-group nil nil)
 
1856
         (this-prep nil nil)
 
1857
         (disallowed-prepositions
 
1858
           (mapcan #'(lambda (x)
 
1859
                       (loop-copylist*
 
1860
                         (find (car x) preposition-groups :test #'in-group-p)))
 
1861
                   initial-phrases))
 
1862
         (used-prepositions (mapcar #'car initial-phrases)))
 
1863
        ((null *loop-source-code*) (nreverse prepositional-phrases))
 
1864
      (declare (symbol this-prep))
 
1865
      (setq token (car *loop-source-code*))
 
1866
      (dolist (group preposition-groups)
 
1867
        (when (setq this-prep (in-group-p token group))
 
1868
          (return (setq this-group group))))
 
1869
      (cond (this-group
 
1870
             (when (member this-prep disallowed-prepositions)
 
1871
               (loop-error
 
1872
                 (if (member this-prep used-prepositions)
 
1873
                     "A ~S prepositional phrase occurs multiply for some LOOP clause."
 
1874
                     "Preposition ~S used when some other preposition has subsumed it.")
 
1875
                 token))
 
1876
             (setq used-prepositions (if (listp this-group)
 
1877
                                         (append this-group used-prepositions)
 
1878
                                         (cons this-group used-prepositions)))
 
1879
             (loop-pop-source)
 
1880
             (push (list this-prep (loop-get-form)) prepositional-phrases))
 
1881
            ((and USING-allowed (loop-tequal token 'using))
 
1882
             (loop-pop-source)
 
1883
             (do ((z (loop-pop-source) (loop-pop-source)) (tem)) (nil)
 
1884
               (when (cadr z)
 
1885
                 (if (setq tem (loop-tassoc (car z) *loop-named-variables*))
 
1886
                     (loop-error
 
1887
                       "The variable substitution for ~S occurs twice in a USING phrase,~@
 
1888
                        with ~S and ~S."
 
1889
                       (car z) (cadr z) (cadr tem))
 
1890
                     (push (cons (car z) (cadr z)) *loop-named-variables*)))
 
1891
               (when (or (null *loop-source-code*) (symbolp (car *loop-source-code*)))
 
1892
                 (return nil))))
 
1893
            (t (return (nreverse prepositional-phrases)))))))
 
1894
 
 
1895
 
 
1896
;;;; Master Sequencer Function
 
1897
 
 
1898
 
 
1899
(defun loop-sequencer (indexv indexv-type indexv-user-specified-p
 
1900
                          variable variable-type
 
1901
                          sequence-variable sequence-type
 
1902
                          step-hack default-top
 
1903
                          prep-phrases)
 
1904
   (let ((endform nil)                          ;Form (constant or variable) with limit value.
 
1905
         (sequencep nil)                        ;T if sequence arg has been provided.
 
1906
         (testfn nil)                           ;endtest function
 
1907
         (test nil)                             ;endtest form.
 
1908
         (stepby (1+ (or (loop-typed-init indexv-type) 0)))     ;Our increment.
 
1909
         (stepby-constantp t)
 
1910
         (step nil)                             ;step form.
 
1911
         (dir nil)                              ;Direction of stepping: NIL, :UP, :DOWN.
 
1912
         (inclusive-iteration nil)              ;T if include last index.
 
1913
         (start-given nil)                      ;T when prep phrase has specified start
 
1914
         (start-value nil)
 
1915
         (start-constantp nil)
 
1916
         (limit-given nil)                      ;T when prep phrase has specified end
 
1917
         (limit-constantp nil)
 
1918
         (limit-value nil)
 
1919
         )
 
1920
     (when variable (loop-make-iteration-variable variable nil variable-type))
 
1921
     (do ((l prep-phrases (cdr l)) (prep) (form) (odir)) ((null l))
 
1922
       (setq prep (caar l) form (cadar l))
 
1923
       (case prep
 
1924
         ((:of :in)
 
1925
          (setq sequencep t)
 
1926
          (loop-make-variable sequence-variable form sequence-type))
 
1927
         ((:from :downfrom :upfrom)
 
1928
          (setq start-given t)
 
1929
          (cond ((eq prep :downfrom) (setq dir ':down))
 
1930
                ((eq prep :upfrom) (setq dir ':up)))
 
1931
          (multiple-value-setq (form start-constantp start-value)
 
1932
            (loop-constant-fold-if-possible form indexv-type))
 
1933
          (loop-make-iteration-variable indexv form indexv-type))
 
1934
         ((:upto :to :downto :above :below)
 
1935
          (cond ((loop-tequal prep :upto) (setq inclusive-iteration (setq dir ':up)))
 
1936
                ((loop-tequal prep :to) (setq inclusive-iteration t))
 
1937
                ((loop-tequal prep :downto) (setq inclusive-iteration (setq dir ':down)))
 
1938
                ((loop-tequal prep :above) (setq dir ':down))
 
1939
                ((loop-tequal prep :below) (setq dir ':up)))
 
1940
          (setq limit-given t)
 
1941
          (multiple-value-setq (form limit-constantp limit-value)
 
1942
            (loop-constant-fold-if-possible form indexv-type))
 
1943
          (setq endform (if limit-constantp
 
1944
                            `',limit-value
 
1945
                            (loop-make-variable
 
1946
                              (loop-gentemp 'loop-limit-) form indexv-type))))
 
1947
         (:by
 
1948
           (multiple-value-setq (form stepby-constantp stepby)
 
1949
             (loop-constant-fold-if-possible form indexv-type))
 
1950
           (unless stepby-constantp
 
1951
             (loop-make-variable (setq stepby (loop-gentemp 'loop-step-by-)) form indexv-type)))
 
1952
         (t (loop-error
 
1953
              "~S invalid preposition in sequencing or sequence path.~@
 
1954
               Invalid prepositions specified in iteration path descriptor or something?"
 
1955
              prep)))
 
1956
       (when (and odir dir (not (eq dir odir)))
 
1957
         (loop-error "Conflicting stepping directions in LOOP sequencing path"))
 
1958
       (setq odir dir))
 
1959
     (when (and sequence-variable (not sequencep))
 
1960
       (loop-error "Missing OF or IN phrase in sequence path"))
 
1961
     ;; Now fill in the defaults.
 
1962
     (unless start-given
 
1963
       (loop-make-iteration-variable
 
1964
         indexv
 
1965
         (setq start-constantp t start-value (or (loop-typed-init indexv-type) 0))
 
1966
         indexv-type))
 
1967
     (cond ((member dir '(nil :up))
 
1968
            (when (or limit-given default-top)
 
1969
              (unless limit-given
 
1970
                (loop-make-variable (setq endform (loop-gentemp 'loop-seq-limit-))
 
1971
                                    nil indexv-type)
 
1972
                (push `(setq ,endform ,default-top) *loop-prologue*))
 
1973
              (setq testfn (if inclusive-iteration '> '>=)))
 
1974
            (setq step (if (eql stepby 1) `(1+ ,indexv) `(+ ,indexv ,stepby))))
 
1975
           (t (unless start-given
 
1976
                (unless default-top
 
1977
                  (loop-error "Don't know where to start stepping."))
 
1978
                (push `(setq ,indexv (1- ,default-top)) *loop-prologue*))
 
1979
              (when (and default-top (not endform))
 
1980
                (setq endform (loop-typed-init indexv-type) inclusive-iteration t))
 
1981
              (when endform (setq testfn (if inclusive-iteration  '< '<=)))
 
1982
              (setq step (if (eql stepby 1) `(1- ,indexv) `(- ,indexv ,stepby)))))
 
1983
     (when testfn (setq test (hide-variable-reference t indexv `(,testfn ,indexv ,endform))))
 
1984
     (when step-hack
 
1985
       (setq step-hack `(,variable ,(hide-variable-reference indexv-user-specified-p indexv step-hack))))
 
1986
     (let ((first-test test) (remaining-tests test))
 
1987
       (when (and stepby-constantp start-constantp limit-constantp)
 
1988
         (when (setq first-test (funcall (symbol-function testfn) start-value limit-value))
 
1989
           (setq remaining-tests t)))
 
1990
       `(() (,indexv ,(hide-variable-reference t indexv step)) ,remaining-tests ,step-hack
 
1991
         () () ,first-test ,step-hack))))
 
1992
 
 
1993
 
 
1994
;;;; Interfaces to the Master Sequencer
 
1995
 
 
1996
 
 
1997
 
 
1998
(defun loop-for-arithmetic (var val data-type kwd)
 
1999
  (loop-sequencer
 
2000
    var (loop-check-data-type data-type *loop-real-data-type*) t
 
2001
    nil nil nil nil nil nil
 
2002
    (loop-collect-prepositional-phrases
 
2003
      '((:from :upfrom :downfrom) (:to :upto :downto :above :below) (:by))
 
2004
      nil (list (list kwd val)))))
 
2005
 
 
2006
 
 
2007
(defun loop-sequence-elements-path (variable data-type prep-phrases
 
2008
                                    &key fetch-function size-function sequence-type element-type)
 
2009
  (multiple-value-bind (indexv indexv-user-specified-p) (named-variable 'index)
 
2010
    (let ((sequencev (named-variable 'sequence)))
 
2011
      #+Genera (when (and sequencev
 
2012
                          (symbolp sequencev)
 
2013
                          sequence-type
 
2014
                          (subtypep sequence-type 'vector)
 
2015
                          (not (member (the symbol sequencev) *loop-nodeclare*)))
 
2016
                 (push `(sys:array-register ,sequencev) *loop-declarations*))
 
2017
      (list* nil nil                            ; dummy bindings and prologue
 
2018
             (loop-sequencer
 
2019
               indexv 'fixnum indexv-user-specified-p
 
2020
               variable (or data-type element-type)
 
2021
               sequencev sequence-type
 
2022
               `(,fetch-function ,sequencev ,indexv) `(,size-function ,sequencev)
 
2023
               prep-phrases)))))
 
2024
 
 
2025
 
 
2026
;;;; Builtin LOOP Iteration Paths
 
2027
 
 
2028
 
 
2029
#||
 
2030
(loop for v being the hash-values of ht do (print v))
 
2031
(loop for k being the hash-keys of ht do (print k))
 
2032
(loop for v being the hash-values of ht using (hash-key k) do (print (list k v)))
 
2033
(loop for k being the hash-keys of ht using (hash-value v) do (print (list k v)))
 
2034
||#
 
2035
 
 
2036
(defun loop-hash-table-iteration-path (variable data-type prep-phrases &key which)
 
2037
  (check-type which (member hash-key hash-value))
 
2038
  (cond ((or (cdr prep-phrases) (not (member (caar prep-phrases) '(:in :of))))
 
2039
         (loop-error "Too many prepositions!"))
 
2040
        ((null prep-phrases) (loop-error "Missing OF or IN in ~S iteration path.")))
 
2041
  (let ((ht-var (loop-gentemp 'loop-hashtab-))
 
2042
        (next-fn (loop-gentemp 'loop-hashtab-next-))
 
2043
        (dummy-predicate-var nil)
 
2044
        (post-steps nil))
 
2045
    (multiple-value-bind (other-var other-p)
 
2046
        (named-variable (if (eq which 'hash-key) 'hash-value 'hash-key))
 
2047
      ;;@@@@ named-variable returns a second value of T if the name was actually
 
2048
      ;; specified, so clever code can throw away the gensym'ed up variable if
 
2049
      ;; it isn't really needed.
 
2050
      ;;The following is for those implementations in which we cannot put dummy NILs
 
2051
      ;; into multiple-value-setq variable lists.
 
2052
      #-Genera (setq other-p t
 
2053
                     dummy-predicate-var (loop-when-it-variable))
 
2054
      (let* ((key-var nil)
 
2055
             (val-var nil)
 
2056
             (temp-val-var (loop-gentemp 'loop-hash-val-temp-))
 
2057
             (temp-key-var (loop-gentemp 'loop-hash-key-temp-))
 
2058
             (temp-predicate-var (loop-gentemp 'loop-hash-predicate-var-))
 
2059
             (variable (or variable (loop-gentemp)))
 
2060
             (bindings `((,variable nil ,data-type)
 
2061
                         (,ht-var ,(cadar prep-phrases))
 
2062
                         ,@(and other-p other-var `((,other-var nil))))))
 
2063
        (if (eq which 'hash-key)
 
2064
            (setq key-var variable val-var (and other-p other-var))
 
2065
            (setq key-var (and other-p other-var) val-var variable))
 
2066
        (push `(with-hash-table-iterator (,next-fn ,ht-var)) *loop-wrappers*)
 
2067
        (when (consp key-var)
 
2068
          (setq post-steps `(,key-var ,(setq key-var (loop-gentemp 'loop-hash-key-temp-))
 
2069
                             ,@post-steps))
 
2070
          (push `(,key-var nil) bindings))
 
2071
        (when (consp val-var)
 
2072
          (setq post-steps `(,val-var ,(setq val-var (loop-gentemp 'loop-hash-val-temp-))
 
2073
                             ,@post-steps))
 
2074
          (push `(,val-var nil) bindings))
 
2075
        `(,bindings                             ;bindings
 
2076
          ()                                    ;prologue
 
2077
          ()                                    ;pre-test
 
2078
          ()                                    ;parallel steps
 
2079
          (not
 
2080
           (multiple-value-bind (,temp-predicate-var ,temp-key-var ,temp-val-var)
 
2081
               (,next-fn)
 
2082
             ;; We use M-V-BIND instead of M-V-SETQ because we only
 
2083
             ;; want to assign values to the key and val vars when we
 
2084
             ;; are in the hash table.  When we reach the end,
 
2085
             ;; TEMP-PREDICATE-VAR is NIL, and so are temp-key-var and
 
2086
             ;; temp-val-var.  This might break any type declarations
 
2087
             ;; on the key and val vars.
 
2088
             (when ,temp-predicate-var
 
2089
               (setq ,val-var ,temp-val-var)
 
2090
               (setq ,key-var ,temp-key-var))
 
2091
             (setq ,dummy-predicate-var ,temp-predicate-var)
 
2092
             )) ;post-test
 
2093
          ,post-steps)))))
 
2094
 
 
2095
 
 
2096
(defun loop-package-symbols-iteration-path (variable data-type prep-phrases &key symbol-types)
 
2097
  (cond ((and prep-phrases (cdr prep-phrases))
 
2098
         (loop-error "Too many prepositions!"))
 
2099
        ((and prep-phrases (not (member (caar prep-phrases) '(:in :of))))
 
2100
         (loop-error "Unknow preposition ~S" (caar prep-phrases))))
 
2101
  (unless (symbolp variable)
 
2102
    (loop-error "Destructuring is not valid for package symbol iteration."))
 
2103
  (let ((pkg-var (loop-gentemp 'loop-pkgsym-))
 
2104
        (next-fn (loop-gentemp 'loop-pkgsym-next-))
 
2105
        (variable (or variable (loop-gentemp)))
 
2106
        (pkg (or (cadar prep-phrases) '*package*)))
 
2107
    (push `(with-package-iterator (,next-fn ,pkg-var ,@symbol-types)) *loop-wrappers*)
 
2108
    `(((,variable nil ,data-type) (,pkg-var ,pkg))
 
2109
      ()
 
2110
      ()
 
2111
      ()
 
2112
      (not (multiple-value-setq (,(progn
 
2113
                                    ;;@@@@ If an implementation can get away without actually
 
2114
                                    ;; using a variable here, so much the better.
 
2115
                                    #+Genera NIL
 
2116
                                    #-Genera (loop-when-it-variable))
 
2117
                                 ,variable)
 
2118
             (,next-fn)))
 
2119
      ())))
 
2120
 
 
2121
;;;; ANSI Loop
 
2122
 
 
2123
(defun make-ansi-loop-universe (extended-p)
 
2124
  (let ((w (make-standard-loop-universe
 
2125
             :keywords `((named (loop-do-named))
 
2126
                         (initially (loop-do-initially))
 
2127
                         (finally (loop-do-finally))
 
2128
                         (do (loop-do-do))
 
2129
                         (doing (loop-do-do))
 
2130
                         (return (loop-do-return))
 
2131
                         (collect (loop-list-collection list))
 
2132
                         (collecting (loop-list-collection list))
 
2133
                         (append (loop-list-collection append))
 
2134
                         (appending (loop-list-collection append))
 
2135
                         (nconc (loop-list-collection nconc))
 
2136
                         (nconcing (loop-list-collection nconc))
 
2137
                         (count (loop-sum-collection count ,*loop-real-data-type* fixnum))
 
2138
                         (counting (loop-sum-collection count ,*loop-real-data-type* fixnum))
 
2139
                         (sum (loop-sum-collection sum number number))
 
2140
                         (summing (loop-sum-collection sum number number))
 
2141
                         (maximize (loop-maxmin-collection max))
 
2142
                         (minimize (loop-maxmin-collection min))
 
2143
                         (maximizing (loop-maxmin-collection max))
 
2144
                         (minimizing (loop-maxmin-collection min))
 
2145
                         (always (loop-do-always t nil))        ; Normal, do always
 
2146
                         (never (loop-do-always t t))   ; Negate the test on always.
 
2147
                         (thereis (loop-do-thereis t))
 
2148
                         (while (loop-do-while nil :while))     ; Normal, do while
 
2149
                         (until (loop-do-while t :until))       ; Negate the test on while
 
2150
                         (when (loop-do-if when nil))   ; Normal, do when
 
2151
                         (if (loop-do-if if nil))       ; synonymous
 
2152
                         (unless (loop-do-if unless t)) ; Negate the test on when
 
2153
                         (with (loop-do-with))
 
2154
                         (repeat (loop-do-repeat)))
 
2155
             :for-keywords '((= (loop-ansi-for-equals))
 
2156
                             (across (loop-for-across))
 
2157
                             (in (loop-for-in))
 
2158
                             (on (loop-for-on))
 
2159
                             (from (loop-for-arithmetic :from))
 
2160
                             (downfrom (loop-for-arithmetic :downfrom))
 
2161
                             (upfrom (loop-for-arithmetic :upfrom))
 
2162
                             (below (loop-for-arithmetic :below))
 
2163
                             (above (loop-for-arithmetic :above))
 
2164
                             (to (loop-for-arithmetic :to))
 
2165
                             (upto (loop-for-arithmetic :upto))
 
2166
                             (downto (loop-for-arithmetic :downto))
 
2167
                             (by (loop-for-arithmetic :by))
 
2168
                             (being (loop-for-being)))
 
2169
             :iteration-keywords '((for (loop-do-for))
 
2170
                                   (as (loop-do-for)))
 
2171
             :type-symbols '(array atom bignum bit bit-vector character compiled-function
 
2172
                                   complex cons double-float fixnum float
 
2173
                                   function hash-table integer keyword list long-float
 
2174
                                   nil null number package pathname random-state
 
2175
                                   ratio rational readtable sequence short-float
 
2176
                                   simple-array simple-bit-vector simple-string
 
2177
                                   simple-vector single-float standard-char
 
2178
                                   stream string base-char
 
2179
                                   symbol t vector)
 
2180
             :type-keywords nil
 
2181
             :ansi (if extended-p :extended t))))
 
2182
    (add-loop-path '(hash-key hash-keys) 'loop-hash-table-iteration-path w
 
2183
                   :preposition-groups '((:of :in))
 
2184
                   :inclusive-permitted nil
 
2185
                   :user-data '(:which hash-key))
 
2186
    (add-loop-path '(hash-value hash-values) 'loop-hash-table-iteration-path w
 
2187
                   :preposition-groups '((:of :in))
 
2188
                   :inclusive-permitted nil
 
2189
                   :user-data '(:which hash-value))
 
2190
    (add-loop-path '(symbol symbols) 'loop-package-symbols-iteration-path w
 
2191
                   :preposition-groups '((:of :in))
 
2192
                   :inclusive-permitted nil
 
2193
                   :user-data '(:symbol-types (:internal :external :inherited)))
 
2194
    (add-loop-path '(external-symbol external-symbols) 'loop-package-symbols-iteration-path w
 
2195
                   :preposition-groups '((:of :in))
 
2196
                   :inclusive-permitted nil
 
2197
                   :user-data '(:symbol-types (:external)))
 
2198
    (add-loop-path '(present-symbol present-symbols) 'loop-package-symbols-iteration-path w
 
2199
                   :preposition-groups '((:of :in))
 
2200
                   :inclusive-permitted nil
 
2201
                   :user-data '(:symbol-types (:internal :external)))
 
2202
    w))
 
2203
 
 
2204
 
 
2205
(defparameter *loop-ansi-universe*
 
2206
              (make-ansi-loop-universe nil))
 
2207
 
 
2208
 
 
2209
(defun loop-standard-expansion (keywords-and-forms environment universe)
 
2210
  (if (and keywords-and-forms (symbolp (car keywords-and-forms)))
 
2211
      (loop-translate keywords-and-forms environment universe)
 
2212
      (let ((tag (gensym)))
 
2213
        `(block nil (tagbody ,tag (progn ,@keywords-and-forms) (go ,tag))))))
 
2214
 
 
2215
 
 
2216
;;;INTERFACE: ANSI
 
2217
(defmacro loop (&environment env &rest keywords-and-forms)
 
2218
  #+Genera (declare (compiler:do-not-record-macroexpansions)
 
2219
                    (zwei:indentation . zwei:indent-loop))
 
2220
  (loop-standard-expansion keywords-and-forms env *loop-ansi-universe*))
 
2221
 
 
2222
#+allegro
 
2223
(defun excl::complex-loop-expander (body env)
 
2224
  (loop-standard-expansion body env *loop-ansi-universe*))