|
|
1.1 root 1: (setq rcs-loop-
2: "$Header: /usr/lib/lisp/loop.l,v 1.1 83/01/29 18:38:49 jkf Exp $")
3:
4: ;;; LOOP -*- Mode:LISP; Package:System-Internals; Base:8; Lowercase:T -*-
5: ;;; **********************************************************************
6: ;;; ****** Universal ******** LOOP Iteration Macro ***********************
7: ;;; **********************************************************************
8: ;;; **** (C) COPYRIGHT 1980, 1981 MASSACHUSETTS INSTITUTE OF TECHNOLOGY **
9: ;;; ******** THIS IS A READ-ONLY FILE! (ALL WRITES RESERVED) *************
10: ;;; **********************************************************************
11:
12: ;;;; LOOP Iteration Macro
13:
14: ;The master copy of this file is on ML:LSB1;LOOP >
15: ;The current Lisp machine copy is on AI:LISPM2;LOOP >
16: ;The FASL and QFASL should also be accessible from LIBLSP; on all machines.
17: ;(Is this necessary anymore? LOOP is now in the Lisp Machine system and
18: ; is accessible on LISP; and distributed with PDP10 Maclisp.)
19: ;Duplicate source is usually also maintained on MC:LSB1;LOOP >
20: ;Printed documentation is available as MIT-LCS Technical Memo 169,
21: ; "LOOP Iteration Macro", from:
22: ; Publications
23: ; MIT Laboratory for Computer Science
24: ; 545 Technology Square
25: ; Cambridge, MA 02139
26: ; the text of which appears in only slightly modified form in the Lisp
27: ; Machine manual.
28:
29: ; Bugs/complaints/suggestions/solicitations-for-documentation to BUG-LOOP
30: ; at any ITS site (MIT-ML preferred).
31:
32:
33: ; **********************************************************************
34: ; *************************** NOTE WELL ********************************
35: ; **********************************************************************
36: ;Incremental compiling of things in this file will generate wrong code
37: ; unless you first evaluate the 'feature' stuff on the next page
38: ; ("readtime environment setup"). (This mainly of Lispm interest.)
39: ;This source sincerely believes that it can run compatibly, WITHOUT ANY
40: ; TEXTUAL MODIFICATIONS AT ALL, in PDP-10 Maclisp, Multics Maclisp, Lisp
41: ; Machine Lisp (Zetalisp), VAX NIL, and Franz Lisp. PLEASE do not make
42: ; changes to this file (the master copy) if you are in any way unsure
43: ; of the implications in a dialect you are not very familiar with; let
44: ; a LOOP maintainer take the responsibility for breaking the master copy
45: ; and maintaining some semblance of sanity among the disparities. Note
46: ; in particular that LOOP also runs in the PDP10 Maclisp -> Vax NIL
47: ; cross-compiler; that environment requires LOOP to produce code which
48: ; can at the same time be interpreted in Maclisp, and compiled for NIL.
49:
50:
51: ; Bootstrap up our basic primitive environment.
52: ; This includes backquote, sharpsign, defmacro, let.
53:
54: (eval-when (eval compile)
55: (cond ((status feature Multics)
56: (defun include-for-multics macro (x)
57: (cons '%include (cdr x))))
58: ('t #-Franz (macro include-for-multics (x) ())
59: #+Franz (defmacro include-for-multics (x) nil))))
60:
61: (include-for-multics lisp_prelude)
62: (include-for-multics lisp_dcls)
63:
64: #+Franz (environment-maclisp)
65:
66:
67: ;;;; Readtime Environment Setup
68:
69: ;Now set up the readtime conditionalization environment. This won't work
70: ; in any compiler that reads the whole file before compiling anything.
71: ; It is a good idea to pretend that case matters in ALL contexts.
72: ; This is in fact true in Franz at the present. Case matters to Multics
73: ; in symbols, except for <frob> in (status feature <frob>).
74: (eval-when (eval compile)
75: #+NIL (progn
76: (defmacro loop-featurep (f)
77: `(featurep ',f target-features))
78: (defmacro loop-nofeaturep (f)
79: `(nofeaturep ',f target-features))
80: (defmacro loop-set-feature (f)
81: `(set-feature ',f target-features))
82: (defmacro loop-set-nofeature (f)
83: `(set-nofeature ',f target-features))
84: )
85: #-NIL (progn
86: (defmacro loop-featurep (f)
87: `(status feature ,f))
88: (defmacro loop-nofeaturep (f)
89: ; Multics doesn't have (status nofeature)...
90: `(not (status feature ,f)))
91: (defmacro loop-set-feature (f)
92: `(sstatus feature ,f))
93: (defmacro loop-set-nofeature (f)
94: ; Does this work on Multics??? I think not but we don't use.
95: `(sstatus nofeature ,f))
96: )
97: ;Note: NEVER in this file is "PDP-10" a valid feature or substring of
98: ; a feature. It is NEVER hyphenated. Keep it that way. (This because
99: ; of continuous lossage with not setting up one or the other of the
100: ; hyphenated/non-hyphenated one.)
101: (cond ((and (loop-featurep PDP10)
102: (loop-featurep NILAID))
103: ;Compiling a PDP10 -> NIL cross-compiling LOOP.
104: ; We check the PDP10 feature first sort of gratuitously so that
105: ; other implementations don't think we are asking about an undefined
106: ; feature name. (Vax-NIL specifically.)
107: (loop-set-feature For-NIL)
108: (loop-set-nofeature For-Maclisp)
109: (loop-set-nofeature For-PDP10)
110: (loop-set-feature Run-in-Maclisp)
111: (loop-set-feature Run-on-PDP10)
112: (loop-set-nofeature Franz))
113: ((and (loop-featurep Maclisp) (loop-nofeaturep For-NIL))
114: ; Standard in-Maclisp for-Maclisp.
115: (loop-set-feature For-Maclisp)
116: (loop-set-feature Run-In-Maclisp)
117: (cond ((loop-nofeaturep Multics)
118: (loop-set-feature For-PDP10)
119: (loop-set-feature PDP10)
120: (loop-set-feature Run-on-PDP10))))
121: ((loop-featurep NIL)
122: ; Real NIL
123: (loop-set-nofeature PDP10)
124: (loop-set-nofeature Multics)
125: (loop-set-nofeature Run-on-PDP10)
126: (loop-set-nofeature For-PDP10)
127: (loop-set-nofeature Run-In-Maclisp)
128: (loop-set-nofeature For-Maclisp))
129: ((loop-featurep Lispm))
130: ((loop-featurep franz)
131: ;The "natural" case of features in franz is all lower.
132: ; Since that is unlike the others used in here, we synonymize
133: ; the obvious other choice.
134: (loop-set-feature Franz))
135: ('t (break loop-implementation-unknown)))
136: (cond ((or (loop-featurep Lispm) (loop-featurep For-PDP10))
137: (loop-set-feature Hairy-Collection))
138: ('t (loop-set-nofeature Hairy-Collection)))
139: (cond ((or (loop-featurep For-NIL) (loop-featurep For-PDP10))
140: (loop-set-feature System-Destructuring))
141: ('t (loop-set-nofeature System-Destructuring)))
142: (cond ((or (loop-featurep For-NIL) (loop-featurep Lispm))
143: (loop-set-feature Named-PROGs))
144: ('t (loop-set-nofeature Named-PROGs)))
145: ;In the following two features, "Local" means the Lisp LOOP will be
146: ; running in, not the one it is being compiled in. "Targeted" means
147: ; the Lisp it will be producing code for. (All from the point of view
148: ; of the running LOOP, you see.)
149: (cond ((or (loop-featurep For-NIL) (loop-featurep Lispm))
150: (loop-set-feature Targeted-Lisp-has-Packages))
151: ('t (loop-set-nofeature Targeted-Lisp-has-Packages)))
152: (cond ((or (loop-featurep Franz) (loop-featurep Run-in-Maclisp))
153: (loop-set-nofeature Local-Lisp-has-Packages))
154: ('t (loop-set-feature Local-Lisp-has-Packages)))
155: (cond ((loop-featurep For-NIL) (loop-set-feature Vector-Destructuring))
156: ('t (loop-set-nofeature Vector-Destructuring)))
157: ;Meaningful-Type-Declarations means that the declarations are (1)
158: ; implemented by the compiler and (2) used for something.
159: ; Assume minimally maclisp-like FIXNUM and FLONUM dcls, for local
160: ; variables or function results.
161: (cond ((loop-featurep Run-in-Maclisp)
162: (loop-set-feature Meaningful-Type-Declarations))
163: ('t (loop-set-nofeature Meaningful-Type-Declarations)))
164: ;Hair for 3600 cross-compilation?
165: (cond ((and (loop-featurep Lispm) (not (loop-featurep 3600.)))
166: (loop-set-feature Loop-Small-Floatp))
167: ('t (loop-set-nofeature Loop-Small-Floatp)))
168: ; -> insert more conditionals here <-
169: ())
170:
171: #+Franz
172: (eval-when (eval compile)
173: (setsyntax #// 143.) ; Make slash be slash
174: (setsyntax #/\ 2.) ; make backslash alphabetic
175: )
176:
177:
178: #+Run-on-PDP10
179: (eval-when (compile)
180: ;Note this hack used when compiled only.
181: ;Its purpose in life is to save a bit of space in the load-time environment,
182: ; since loop doesn't actually need the PDP10 Maclisp doublequoted crocks
183: ; to remember their origin as "strings".
184: (setsyntax #/" 'macro
185: '(lambda ()
186: (do ((ch (tyi) (tyi)) (l () (cons ch l)))
187: ((= ch #/")
188: (list squid (list 'quote (implode (nreverse l)))))
189: (and (= ch #//) (setq ch (tyi)))))))
190:
191:
192: ;;;; Other basic header stuff
193:
194:
195: ; Following isn't needed on Lispm, as loop is installed there (ie, these
196: ; symbols are already in GLOBAL).
197: #+(and Targeted-Lisp-has-Packages (not Lispm))
198: (mapc 'globalize
199: '("LOOP" ; Major macro
200: "LOOP-FINISH" ; Handy macro
201: "DEFINE-LOOP-MACRO"
202: "DEFINE-LOOP-PATH" ; for users to define paths
203: "DEFINE-LOOP-SEQUENCE-PATH" ; this too
204: ))
205:
206: #+(or For-NIL For-PDP10)
207: (herald LOOP)
208:
209:
210: ;;;; Macro Environment Setup
211:
212: ;Wrapper for putting around DEFMACRO etc. forms to determine whether
213: ; they are defined in the compiled output file or not. (It is assumed
214: ; that DEFMACRO forms will be.) Making loop-macro-progn output for loading
215: ; is convenient if loop will have incremental-recompilation done on it.
216: ; (Note, of course, that the readtime environment is NOT set up.)
217:
218: #+Lispm
219: (defmacro loop-macro-progn (&rest forms)
220: `(progn 'compile ,@forms))
221: #-Lispm
222: (eval-when (eval compile)
223: (defmacro loop-macro-progn (&rest forms)
224: `(eval-when (eval compile) ,@forms)))
225:
226:
227: ; Hack up the stuff for data-types. DATA-TYPE? will always be a macro
228: ; so that it will not require the data-type package at run time if
229: ; all uses of the other routines are conditionalized upon that value.
230: (eval-when (eval compile)
231: ; Crock for DATA-TYPE? derives from DTDCL. We just copy it rather
232: ; than load it in, which requires knowing where it comes from (sigh).
233: ;
234: #-Local-Lisp-has-Packages
235: (defmacro data-type? (x) `(get ,x ':data-type))
236: #+Local-Lisp-has-Packages
237: (defmacro data-type? (frob)
238: (let ((foo (gensym)))
239: `((lambda (,foo)
240: ; NIL croaks if () given to GET...
241: (and #+NIL (symbolp ,foo) #-NIL 't
242: (or (get ,foo ':data-type)
243: (and (setq ,foo (intern-soft (get-pname ,foo) ""))
244: (get ,foo ':data-type)))))
245: ,frob))))
246:
247: (declare (*lexpr variable-declarations)
248: ; Multics defaults to free-functional-variable since it is declared
249: ; special & used as function before it is defined:
250: (*expr loop-when-it-variable)
251: (*expr initial-value primitive-type)
252: #+(or Maclisp Franz) (macros t) ; Defmacro dependency
253: #+Run-in-Maclisp
254: (muzzled t) ; I know what i'm doing
255: )
256:
257: #+Run-on-PDP10
258: (declare (mapex ())
259: (genprefix loop/|-)
260: (special squid)
261: #+(and Run-in-Maclisp For-NIL) ; patch it up
262: (*expr stringp vectorp vref vector-length)
263: )
264:
265: #-Run-on-PDP10
266: (declare
267: #+Lispm (setq open-code-map-switch t)
268: #+Run-in-Maclisp (mapex t)
269: #+Run-in-Maclisp (genprefix loop-iteration/|-))
270:
271: #+Run-on-PDP10
272: (mapc '(lambda (x)
273: (or (getl x '(subr lsubr fsubr macro fexpr expr autoload))
274: ; This dtdcl will sort of work for NIL code generation,
275: ; if declarations will ignored.
276: (putprop x '((lisp) dtdcl fasl) 'autoload)))
277: '(data-type? variable-declarations initial-value primitive-type))
278:
279: (loop-macro-progn
280: (defmacro loop-copylist* (l)
281: #+Lispm `(copylist* ,l)
282: #-Lispm `(append ,l ())))
283:
284:
285: ;;;; Random Macros
286:
287: ; Error macro. Note that in the PDP10 version we call LOOP-DIE rather
288: ; than ERROR -- there are so many occurences of it in this source that
289: ; it is worth breaking off that function, since calling the lsubr ERROR
290: ; takes more inline code.
291: (loop-macro-progn
292: (defmacro loop-simple-error (unquoted-message &optional (datum () datump))
293: #+(and Run-In-Maclisp (not Multics))
294: (progn (cond ((symbolp unquoted-message))
295: ((and (not (atom unquoted-message))
296: compiler-state
297: (eq (car unquoted-message) squid)
298: (not (atom (setq unquoted-message
299: (cadr unquoted-message))))
300: (eq (car unquoted-message) 'quote)
301: (symbolp (cadr unquoted-message)))
302: (setq unquoted-message (cadr unquoted-message)))
303: ('t (error '|Uloze -- LOOP-SIMPLE-ERROR|
304: (list 'loop-simple-error
305: unquoted-message datum))))
306: (cond (datump `(loop-die ',unquoted-message ,datum))
307: ('t `(error ',unquoted-message))))
308: #+(or Franz Multics)
309: (progn (or (memq (typep unquoted-message) '(string symbol))
310: (error '|Uloze -- | (list 'loop-simple-error
311: unquoted-message datum)))
312: `(error ,(let ((l (list "lisp: " unquoted-message
313: (if datump " -- " ""))))
314: #+Franz (get_pname (apply 'uconcat l))
315: #-Franz (apply 'catenate l))
316: . ,(and datump (list datum))))
317: #-(or Run-In-Maclisp Franz)
318: `(ferror () ,(if datump (string-append "~S " unquoted-message)
319: unquoted-message)
320: . ,(and datump (list datum)))))
321:
322:
323: #+(and Run-in-Maclisp (not Multics))
324: (defun loop-die (arg1 arg2)
325: (error arg1 arg2))
326:
327:
328: ; This is a KLUDGE. But it apparently saves an average of two inline
329: ; instructions per call in the PDP10 version... The ACS prop is
330: ; fairly gratuitous.
331:
332: #+Run-on-PDP10
333: (progn 'compile
334: (lap-a-list
335: '((lap loop-pop-source subr)
336: (args loop-pop-source (() . 0))
337: (hlrz a @ (special loop-source-code))
338: (hrrz b @ (special loop-source-code))
339: (movem b (special loop-source-code))
340: (popj p)
341: nil))
342: (eval-when (compile)
343: (defprop loop-pop-source 2 acs)
344: ))
345:
346: #-Run-on-PDP10
347: (loop-macro-progn
348: (defmacro loop-pop-source () '(pop loop-source-code)))
349:
350: (loop-macro-progn
351: (defmacro object-that-cares-p (x)
352: #+Lispm `(listp ,x)
353: #+(or NIL PDP10) `(pairp ,x)
354: #-(or Lispm NIL PDP10) `(eq (typep ,x) 'list)))
355:
356:
357: ;;;; Variable defining macros
358:
359: ;There is some confusion among lisps as to whether or not a file containing
360: ; a DEFVAR will declare the variable when the compiled file is loaded
361: ; into a compiler. LOOP assumes that DEFVAR does so (this is needed for
362: ; various user-accessible variables). DEFIVAR is for "private" variables.
363: ; Note that this is moot for Lispm due to incremental-recompilation support
364: ; anyway.
365: ;Multics lcp has some bug whereby DECLARE and (EVAL-WHEN (COMPILE) ...)
366: ; don't get hacked properly inside of more than one level of
367: ; (PROGN 'COMPILE ...). Thus we hack around DEFVAR and DEFIVAR to bypass
368: ; this lossage.
369: ;Franz DEFVAR does not make the declaration on loading, so we redefine it.
370:
371: #+(or Multics Franz)
372: (loop-macro-progn
373: (defmacro defvar (name &optional (init nil initp) documentation
374: &aux (dclform `(and #+Franz (getd 'special)
375: #-Franz (status feature compiler)
376: (special ,name))))
377: ; For some obscure reason, (DECLARE ...) doesn't take effect within 2
378: ; (PROGN 'COMPILE ...)s, but (EVAL-WHEN (COMPILE) ...) does, on Multics.
379: (eval dclform) ; sigh
380: (cond ((not initp) dclform)
381: (t `(progn 'compile
382: ,dclform
383: (or (boundp ',name) (setq ,name ,init)))))))
384:
385: (loop-macro-progn
386: ; A DEFVAR alternative - "DEFine Internal VARiable".
387: (defmacro defivar (name &optional (init () initp))
388: ; The Lispm choice here is based on likelihood of incremental compilation.
389: #+Lispm `(defvar ,name ,@(and initp `(,init)))
390: #+Multics (progn (apply 'special (list name))
391: (if initp `(or (boundp ',name) (setq ,name ,init))
392: `(progn 'compile)))
393: #-(or Lispm Multics)
394: `(progn 'compile
395: (declare (special ,name))
396: . ,(and initp `((or (boundp ',name) (setq ,name ,init)))))))
397:
398: #+Franz
399: ;Defconst is like defvar but always initializes.
400: ; It happens in this case that we really don't care about the global
401: ; declaration on loading, so actually treat it more like DEFIVAR.
402: ; (This is now in Multics and PDP10 Maclisp, thanks to Maclisp Extensions
403: ; Manual.)
404: (loop-macro-progn
405: (defmacro defconst (name init &optional documentation)
406: `(progn 'compile (declare (special ,name)) (setq ,name ,init))))
407:
408:
409:
410: ;;;; Setq Hackery
411:
412: ; Note: LOOP-MAKE-PSETQ is NOT flushable depending on the existence
413: ; of PSETQ, unless PSETQ handles destructuring. Even then it is
414: ; preferable for the code LOOP produces to not contain intermediate
415: ; macros, especially in the PDP10 version.
416:
417: (defun loop-make-psetq (frobs)
418: (and frobs
419: (loop-make-setq
420: (list (car frobs)
421: (if (null (cddr frobs)) (cadr frobs)
422: `(prog1 ,(cadr frobs)
423: ,(loop-make-psetq (cddr frobs))))))))
424:
425: #-System-Destructuring
426: (progn 'compile
427:
428: (defvar si:loop-use-system-destructuring?
429: ())
430:
431: (defivar loop-desetq-temporary)
432:
433: ; Do we want this??? It is, admittedly, useful...
434: ;(defmacro loop-desetq (&rest x)
435: ; (let ((loop-desetq-temporary ()))
436: ; (let ((setq-form (loop-make-desetq x)))
437: ; (if loop-desetq-temporary
438: ; `((lambda (,loop-desetq-temporary) ,setq-form) ())
439: ; setq-form))))
440:
441:
442: (defun loop-make-desetq (x)
443: (if si:loop-use-system-destructuring?
444: (cons (do ((l x (cddr l))) ((null l) 'setq)
445: (or (and (not (null (car l))) (symbolp (car l)))
446: (return 'desetq)))
447: x)
448: (do ((x x (cddr x)) (r ()) (var) (val))
449: ((null x) (and r (cons 'setq r)))
450: (setq var (car x) val (cadr x))
451: (cond ((and (not (atom var))
452: (not (atom val))
453: (not (and (memq (car val)
454: '(car cdr cadr cddr caar cdar))
455: (atom (cadr val)))))
456: (setq x (list* (or loop-desetq-temporary
457: (setq loop-desetq-temporary (gensym)))
458: val var loop-desetq-temporary (cddr x)))))
459: (setq r (nconc r (loop-desetq-internal (car x) (cadr x)))))))
460:
461: (defun loop-desetq-internal (var val)
462: (cond ((null var) ())
463: ((atom var) (list var val))
464: ('t (nconc (loop-desetq-internal (car var) `(car ,val))
465: (loop-desetq-internal (cdr var) `(cdr ,val))))))
466: ); End desetq hackery for #-System-Destructuring
467:
468:
469: (defun loop-make-setq (pairs)
470: (and pairs
471: #-System-Destructuring
472: (loop-make-desetq pairs)
473: #+System-Destructuring
474: (cons (do ((l pairs (cddr l))) ((null l) 'setq)
475: (or (and (car l) (symbolp (car l))) (return 'desetq)))
476: pairs)))
477:
478:
479: (defconst loop-keyword-alist ;clause introducers
480: '(
481: #+Named-PROGs
482: (named loop-do-named)
483: (initially loop-do-initially)
484: (finally loop-do-finally)
485: (nodeclare loop-nodeclare)
486: (do loop-do-do)
487: (doing loop-do-do)
488: (return loop-do-return)
489: (collect loop-do-collect list)
490: (collecting loop-do-collect list)
491: (append loop-do-collect append)
492: (appending loop-do-collect append)
493: (nconc loop-do-collect nconc)
494: (nconcing loop-do-collect nconc)
495: (count loop-do-collect count)
496: (counting loop-do-collect count)
497: (sum loop-do-collect sum)
498: (summing loop-do-collect sum)
499: (maximize loop-do-collect max)
500: (minimize loop-do-collect min)
501: (always loop-do-always or)
502: (never loop-do-always and)
503: (thereis loop-do-thereis)
504: (while loop-do-while or while)
505: (until loop-do-while and until)
506: (when loop-do-when ())
507: (if loop-do-when ())
508: (unless loop-do-when t)
509: (with loop-do-with)))
510:
511:
512: (defconst loop-iteration-keyword-alist
513: `((for loop-do-for)
514: (as loop-do-for)
515: (repeat loop-do-repeat)))
516:
517:
518: (defconst loop-for-keyword-alist ;Types of FOR
519: '( (= loop-for-equals)
520: (first loop-for-first)
521: (in loop-list-stepper car)
522: (on loop-list-stepper ())
523: (from loop-for-arithmetic from)
524: (downfrom loop-for-arithmetic downfrom)
525: (upfrom loop-for-arithmetic upfrom)
526: (below loop-for-arithmetic below)
527: (to loop-for-arithmetic to)
528: (being loop-for-being)))
529:
530: #+Named-PROGs
531: (defivar loop-prog-names)
532:
533: (defvar loop-path-keyword-alist ()) ; PATH functions
534: (defivar loop-named-variables) ; see SI:LOOP-NAMED-VARIABLE
535: (defivar loop-collection-crocks) ; see LOOP-DO-COLLECT etc
536: (defivar loop-variables) ;Variables local to the loop
537: (defivar loop-declarations) ; Local dcls for above
538: (defivar loop-nodeclare) ; but don't declare these
539: (defivar loop-variable-stack)
540: (defivar loop-declaration-stack)
541: #-System-Destructuring
542: (defivar loop-desetq-crocks) ; see loop-make-variable
543: #-System-Destructuring
544: (defivar loop-desetq-stack) ; and loop-translate-1
545: (defivar loop-prologue) ;List of forms in reverse order
546: (defivar loop-before-loop)
547: (defivar loop-body) ;..
548: (defivar loop-after-body) ;.. for FOR steppers
549: (defivar loop-epilogue) ;..
550: (defivar loop-after-epilogue) ;So COLLECT's RETURN comes after FINALLY
551: (defivar loop-conditionals) ;If non-NIL, condition for next form in body
552: ;The above is actually a list of entries of the form
553: ;(cond (condition forms...))
554: ;When it is output, each successive condition will get
555: ;nested inside the previous one, but it is not built up
556: ;that way because you wouldn't be able to tell a WHEN-generated
557: ;COND from a user-generated COND.
558: ;When ELSE is used, each cond can get a second clause
559:
560: (defivar loop-when-it-variable) ;See LOOP-DO-WHEN
561: (defivar loop-never-stepped-variable) ; see LOOP-FOR-FIRST
562: (defivar loop-emitted-body?) ; see LOOP-EMIT-BODY,
563: ; and LOOP-DO-FOR
564: (defivar loop-iteration-variables) ; LOOP-MAKE-ITERATION-VARIABLE
565: (defivar loop-iteration-variablep) ; ditto
566: (defivar loop-collect-cruft) ; for multiple COLLECTs (etc)
567: (defivar loop-source-code)
568: (defvar loop-duplicate-code ()) ; see LOOP-OPTIMIZE-DUPLICATED-CODE-ETC
569:
570:
571: ;;;; Token Hackery
572:
573: ;Compare two "tokens". The first is the frob out of LOOP-SOURCE-CODE,
574: ;the second a symbol to check against.
575:
576: ; Consider having case-independent comparison on Multics.
577: #+(or Multics Franz)
578: (progn 'compile
579: (defmacro si:loop-tequal (x1 x2)
580: `(eq ,x1 ,x2))
581: (defmacro si:loop-tmember (x l)
582: `(memq ,x ,l))
583: (defmacro si:loop-tassoc (x l)
584: `(assq ,x ,l)))
585:
586:
587: #+Lispm
588: (progn 'compile
589: (defun si:loop-tequal (x1 x2)
590: (and (symbolp x1) (string-equal x1 x2)))
591: (defun si:loop-tassoc (kwd alist)
592: (and (symbolp kwd) (ass #'string-equal kwd alist)))
593: (defun si:loop-tmember (kwd list)
594: (and (symbolp kwd) (mem #'string-equal kwd list))))
595:
596:
597: #+Run-on-PDP10
598: (progn 'compile
599: #+For-NIL
600: (defun si:loop-tequal (x1 x2)
601: (eq x1 x2))
602: #-For-NIL
603: (progn 'compile
604: (eval-when (load compile)
605: (cond ((status feature complr)
606: ; Gross me out!
607: (setq macrolist
608: (cons '(si:loop-tequal
609: . (lambda (x) (cons 'eq (cdr x))))
610: (delq (assq 'si:loop-tequal macrolist)
611: macrolist)))
612: (*expr si:loop-tmember si:loop-tassoc))))
613: (defun si:loop-tequal (x1 x2)
614: (eq x1 x2)))
615: (defun si:loop-tmember (kwd list)
616: (memq kwd list))
617: (defun si:loop-tassoc (kwd alist)
618: (assq kwd alist))
619: )
620:
621: #+(and For-NIL (not Run-in-Maclisp))
622: (progn 'compile
623: ; STRING-EQUAL only accepts strings. GET-PNAME can be open-coded
624: ; however.
625: (defun si:loop-tequal (kwd1 kwd2)
626: (and (symbolp kwd1) (string-equal (get-pname kwd1) (get-pname kwd2))))
627: (defun si:loop-tassoc (kwd alist)
628: (cond ((symbolp kwd)
629: (setq kwd (get-pname kwd))
630: (do ((l alist (cdr l))) ((null l) ())
631: (and (string-equal kwd (get-pname (caar l)))
632: (return (car l)))))))
633: (defun si:loop-tmember (token list)
634: (cond ((symbolp token)
635: (setq token (get-pname token))
636: (do ((l list (cdr l))) ((null l))
637: (and (string-equal token (get-pname (car l)))
638: (return l)))))))
639:
640:
641: #+(or For-PDP10 For-NIL)
642: (eval-when (eval compile) (setq defmacro-displace-call ()))
643:
644: (defmacro define-loop-macro (keyword)
645: (or (eq keyword 'loop)
646: (si:loop-tassoc keyword loop-keyword-alist)
647: (si:loop-tassoc keyword loop-iteration-keyword-alist)
648: (loop-simple-error "not a loop keyword - define-loop-macro" keyword))
649: (subst keyword 'keyword
650: '(eval-when (compile load eval)
651: #+(or For-NIL Run-on-PDP10)
652: (progn (flush-macromemos 'keyword ())
653: (flush-macromemos 'loop ()))
654: #-Run-in-Maclisp
655: (progn
656: #+Franz
657: (putd 'keyword
658: '(macro (macroarg) (loop-translate macroarg)))
659: #-Franz
660: (fset-carefully 'keyword '(macro . loop-translate)))
661: #+Run-in-Maclisp
662: (progn (defprop keyword loop-translate macro))
663: )))
664:
665: #+(or For-PDP10 For-NIL)
666: (eval-when (eval compile) (setq defmacro-displace-call 't))
667:
668: (define-loop-macro loop)
669:
670: #+Run-in-Maclisp
671: (defun (loop-finish macro) (form)
672: ;This definition solves two problems:
673: ; (1) wasted address space
674: ; (2) displacing of a form which might tend to be pure.
675: ; There is little point in macro-memoizing a constant anyway.
676: (and (cdr form) (loop-simple-error "Wrong number of args" form))
677: '(go end-loop))
678:
679: #-Run-in-Maclisp
680: (defmacro loop-finish ()
681: '(go end-loop))
682:
683:
684: (defun loop-translate (x)
685: #-(or For-NIL Run-on-PDP10) (displace x (loop-translate-1 x))
686: #+(or For-NIL Run-on-PDP10)
687: (or (macrofetch x) (macromemo x (loop-translate-1 x) 'loop)))
688:
689:
690: (defun loop-end-testify (list-of-forms)
691: (if (null list-of-forms) ()
692: `(and ,(if (null (cdr (setq list-of-forms (nreverse list-of-forms))))
693: (car list-of-forms)
694: (cons 'or list-of-forms))
695: (go end-loop))))
696:
697: (defun loop-optimize-duplicated-code-etc (&aux before after groupa groupb a b
698: lastdiff)
699: (do ((l1 (nreverse loop-before-loop) (cdr l1))
700: (l2 (nreverse loop-after-body) (cdr l2)))
701: ((equal l1 l2)
702: (setq loop-body (nconc (delq '() l1) (nreverse loop-body))))
703: (push (car l1) before) (push (car l2) after))
704: (cond ((not (null loop-duplicate-code))
705: (setq loop-before-loop (nreverse (delq () before))
706: loop-after-body (nreverse (delq () after))))
707: ('t (setq loop-before-loop () loop-after-body ()
708: before (nreverse before) after (nreverse after))
709: (do ((bb before (cdr bb)) (aa after (cdr aa)))
710: ((null aa))
711: (cond ((not (equal (car aa) (car bb))) (setq lastdiff aa))
712: ((not (si:loop-simplep (car aa))) ;Mustn't duplicate
713: (return ()))))
714: (cond (lastdiff ;Down through lastdiff should be duplicated
715: (do () (())
716: (and (car before) (push (car before) loop-before-loop))
717: (and (car after) (push (car after) loop-after-body))
718: (setq before (cdr before) after (cdr after))
719: (and (eq after (cdr lastdiff)) (return ())))
720: (setq loop-before-loop (nreverse loop-before-loop)
721: loop-after-body (nreverse loop-after-body))))
722: (do ((bb (nreverse before) (cdr bb))
723: (aa (nreverse after) (cdr aa)))
724: ((null aa))
725: (setq a (car aa) b (car bb))
726: (cond ((and (null a) (null b)))
727: ((equal a b)
728: (loop-output-group groupb groupa)
729: (push a loop-body)
730: (setq groupb () groupa ()))
731: ('t (and a (push a groupa)) (and b (push b groupb)))))
732: (loop-output-group groupb groupa)))
733: (and loop-never-stepped-variable
734: (push `(setq ,loop-never-stepped-variable ()) loop-after-body))
735: ())
736:
737:
738: (defun loop-output-group (before after)
739: (and (or after before)
740: (let ((v (or loop-never-stepped-variable
741: (setq loop-never-stepped-variable
742: (loop-make-variable (gensym) ''t ())))))
743: (push (cond ((not before) `(or ,v (progn . ,after)))
744: ((not after) `(and ,v (progn . ,before)))
745: ('t `(cond (,v . ,before) ('t . ,after))))
746: loop-body))))
747:
748:
749: (defun loop-translate-1 (loop-source-code)
750: (and (eq (car loop-source-code) 'loop)
751: (setq loop-source-code (cdr loop-source-code)))
752: (do ((loop-iteration-variables ())
753: (loop-iteration-variablep ())
754: (loop-variables ())
755: (loop-nodeclare ())
756: (loop-named-variables ())
757: (loop-declarations ())
758: #-System-Destructuring
759: (loop-desetq-crocks ())
760: (loop-variable-stack ())
761: (loop-declaration-stack ())
762: #-System-destructuring
763: (loop-desetq-stack ())
764: (loop-prologue ())
765: (loop-before-loop ())
766: (loop-body ())
767: (loop-emitted-body? ())
768: (loop-after-body ())
769: (loop-epilogue ())
770: (loop-after-epilogue ())
771: (loop-conditionals ())
772: (loop-when-it-variable ())
773: (loop-never-stepped-variable ())
774: #-System-Destructuring
775: (loop-desetq-temporary ())
776: #+Named-PROGs
777: (loop-prog-names ())
778: (loop-collect-cruft ())
779: (loop-collection-crocks ())
780: (keyword)
781: (tem)
782: (progvars))
783: ((null loop-source-code)
784: (and loop-conditionals
785: (loop-simple-error "Hanging conditional in loop macro"
786: (caadar loop-conditionals)))
787: (loop-optimize-duplicated-code-etc)
788: (loop-bind-block)
789: (setq progvars loop-collection-crocks)
790: #-System-Destructuring
791: (and loop-desetq-temporary (push loop-desetq-temporary progvars))
792: (setq tem `(prog #+Named-PROGs ,.loop-prog-names
793: ,progvars
794: #+Hairy-Collection
795: ,.(do ((l loop-collection-crocks (cddr l))
796: (v () (cons `(loop-collect-init
797: ,(cadr l) ,(car l))
798: v)))
799: ((null l) v))
800: ,.(nreverse loop-prologue)
801: ,.loop-before-loop
802: next-loop
803: ,.loop-body
804: ,.loop-after-body
805: (go next-loop)
806: ; Multics complr notices when end-loop is not gone
807: ; to. So we put in a dummy go. This does not generate
808: ; extra code, at least in the simple example i tried,
809: ; but it does keep it from complaining about unused
810: ; go tag.
811: #+Multics (go end-loop)
812: end-loop
813: ,.(nreverse loop-epilogue)
814: ,.(nreverse loop-after-epilogue)))
815: (do ((vars) (dcls) #-System-Destructuring (crocks))
816: ((null loop-variable-stack))
817: (setq vars (car loop-variable-stack)
818: loop-variable-stack (cdr loop-variable-stack)
819: dcls (car loop-declaration-stack)
820: loop-declaration-stack (cdr loop-declaration-stack)
821: tem (ncons tem))
822: #-System-Destructuring
823: (and (setq crocks (pop loop-desetq-stack))
824: (push (loop-make-desetq crocks) tem))
825: (and dcls (push (cons 'declare dcls) tem))
826: (cond ((do ((l vars (cdr l))) ((null l) ())
827: (and (not (atom (car l)))
828: (or (null (caar l)) (not (symbolp (caar l))))
829: (return 't)))
830: (setq tem `(let ,(nreverse vars) ,.tem)))
831: ('t (let ((lambda-vars ()) (lambda-vals ()))
832: (do ((l vars (cdr l)) (v)) ((null l))
833: (cond ((atom (setq v (car l)))
834: (push v lambda-vars)
835: (push () lambda-vals))
836: ('t (push (car v) lambda-vars)
837: (push (cadr v) lambda-vals))))
838: (setq tem `((lambda ,lambda-vars ,.tem)
839: ,.lambda-vals))))))
840: tem)
841: (if (symbolp (setq keyword (loop-pop-source)))
842: (if (setq tem (si:loop-tassoc keyword loop-keyword-alist))
843: (apply (cadr tem) (cddr tem))
844: (if (setq tem (si:loop-tassoc
845: keyword loop-iteration-keyword-alist))
846: (loop-hack-iteration tem)
847: (if (si:loop-tmember keyword '(and else))
848: ; Alternative is to ignore it, ie let it go around to the
849: ; next keyword...
850: (loop-simple-error
851: "secondary clause misplaced at top level in LOOP macro"
852: (list keyword (car loop-source-code)
853: (cadr loop-source-code)))
854: (loop-simple-error
855: "unknown keyword in LOOP macro" keyword))))
856: (loop-simple-error
857: "found where keyword expected in LOOP macro" keyword))))
858:
859:
860: (defun loop-bind-block ()
861: (cond ((not (null loop-variables))
862: (push loop-variables loop-variable-stack)
863: (push loop-declarations loop-declaration-stack)
864: (setq loop-variables () loop-declarations ())
865: #-System-Destructuring
866: (progn (push loop-desetq-crocks loop-desetq-stack)
867: (setq loop-desetq-crocks ())))))
868:
869:
870: ;Get FORM argument to a keyword. Read up to atom. PROGNify if necessary.
871: (defun loop-get-form ()
872: (do ((forms (ncons (loop-pop-source)) (cons (loop-pop-source) forms))
873: (nextform (car loop-source-code) (car loop-source-code)))
874: ((atom nextform)
875: (if (null (cdr forms)) (car forms)
876: (cons 'progn (nreverse forms))))))
877:
878:
879: ;Note that this function is not absolutely general. For instance, in Maclisp,
880: ; the functions < and > can only take 2 args, whereas greaterp and lessp
881: ; may take any number. Also, certain of the generic functions behave
882: ; differently from the type-specific ones in "degenerate" cases, like
883: ; QUOTIENT or DIFFERENCE of one arg.
884: ;And of course one always must be careful doing textual substitution.
885: (defun loop-typed-arith (substitutable-expression data-type)
886: #-(or Lispm Franz)
887: (if (setq data-type (car (si:loop-tmember (if (data-type? data-type)
888: (primitive-type data-type)
889: data-type)
890: '(fixnum flonum))))
891: (sublis (cond ((eq data-type 'fixnum)
892: #+For-NIL
893: '((plus . +&) (add1 . 1+&)
894: (difference . -&) (sub1 . 1-&)
895: (quotient . //&) (remainder . \&) (times . *&)
896: (zerop . 0p) (plusp . +p) (minusp . -p)
897: (greaterp . >&) (lessp . <&)
898: (min . min&) (max . max&))
899: #-For-NIL
900: '((plus . +) (add1 . 1+)
901: (difference . -) (sub1 . 1-)
902: (quotient . //) (remainder . \) (times . *)
903: (greaterp . >) (lessp . <)))
904: ('t #+For-NIL
905: '((plus . +$) (difference . -$)
906: (add1 . 1+$) (sub1 . 1-$)
907: (quotient . //$) (times . *$)
908: (greaterp . >$) (lessp . <$)
909: (max . max$) (min . min$))
910: #-For-NIL
911: '((plus . +$) (difference . -$)
912: (add1 . 1+$) (sub1 . 1-$)
913: (quotient . //$) (times . *$)
914: (greaterp . >) (lessp . <))))
915: substitutable-expression)
916: substitutable-expression)
917: #+Lispm
918: (progn data-type substitutable-expression)
919: #+Franz
920: (if (si:loop-tequal data-type 'fixnum)
921: (sublis '((add1 . 1+) (sub1 . 1-) (plus . +) (difference . -)
922: (times . *) (quotient . //) (remainder . \))
923: substitutable-expression)
924: substitutable-expression)
925: )
926:
927:
928: (defun loop-typed-init (data-type)
929: (cond ((data-type? data-type) (initial-value data-type))
930: ((setq data-type (car (si:loop-tmember
931: data-type '(fixnum flonum integer number
932: #+Loop-Small-Floatp
933: small-flonum))))
934: (cond ((eq data-type 'flonum) 0.0)
935: #+Loop-Small-Floatp
936: ((eq data-type 'small-flonum)
937: #.(and (loop-featurep Loop-Small-Floatp)
938: (small-float 0)))
939: ('t 0)))))
940:
941:
942: (defun loop-make-variable (name initialization dtype)
943: (cond ((null name)
944: (cond ((not (null initialization))
945: (push (list #+Lispm 'ignore
946: #+Multics (setq name (gensym))
947: #-(or Lispm Multics) ()
948: initialization)
949: loop-variables)
950: #+Multics (push `(progn ,name) loop-prologue))))
951: (#-Vector-Destructuring (atom name)
952: #+Vector-Destructuring (symbolp name)
953: (cond (loop-iteration-variablep
954: (if (memq name loop-iteration-variables)
955: (loop-simple-error
956: "Duplicated iteration variable somewhere in LOOP"
957: name)
958: (push name loop-iteration-variables)))
959: ((assq name loop-variables)
960: (loop-simple-error
961: "Duplicated var in LOOP bind block" name)))
962: #-Vector-Destructuring
963: (or (symbolp name)
964: (loop-simple-error "Bad variable somewhere in LOOP" name))
965: (loop-declare-variable name dtype)
966: ; We use ASSQ on this list to check for duplications (above),
967: ; so don't optimize out this list:
968: (push (list name (or initialization (loop-typed-init dtype)))
969: loop-variables))
970: (initialization
971: #+System-Destructuring
972: (progn (loop-declare-variable name dtype)
973: (push (list name initialization) loop-variables))
974: #-System-Destructuring
975: (cond (si:loop-use-system-destructuring?
976: (loop-declare-variable name dtype)
977: (push (list name initialization) loop-variables))
978: ('t (let ((newvar (gensym)))
979: (push (list newvar initialization) loop-variables)
980: ; LOOP-DESETQ-CROCKS gathered in reverse order.
981: (setq loop-desetq-crocks
982: (list* name newvar loop-desetq-crocks))
983: (loop-make-variable name () dtype)))))
984: ('t
985: #-Vector-Destructuring
986: (let ((tcar) (tcdr))
987: (if (atom dtype) (setq tcar (setq tcdr dtype))
988: (setq tcar (car dtype) tcdr (cdr dtype)))
989: (loop-make-variable (car name) () tcar)
990: (loop-make-variable (cdr name) () tcdr))
991: #+Vector-Destructuring
992: (cond ((object-that-cares-p name)
993: (let ((tcar) (tcdr))
994: (if (object-that-cares-p dtype)
995: (setq tcar (car dtype) tcdr (cdr dtype))
996: (setq tcar (setq tcdr dtype)))
997: (loop-make-variable (car name) () tcar)
998: (loop-make-variable (cdr name) () tcdr)))
999: ((vectorp name)
1000: (do ((i 0 (1+ i))
1001: (n (vector-length name))
1002: (dti 0 (1+ dti))
1003: (dtn (and (vectorp dtype) (vector-length dtype))))
1004: ((= i n))
1005: #+Run-in-Maclisp (declare (fixnum i n dti))
1006: (loop-make-variable
1007: (vref name i) ()
1008: (if (null dtn) dtype
1009: (and (< dti dtn) (vref dtype dti))))))
1010: ('t (loop-simple-error
1011: "bad variable somewhere in LOOP" name)))
1012: ))
1013: name)
1014:
1015:
1016: (defun loop-make-iteration-variable (name initialization dtype)
1017: (let ((loop-iteration-variablep 't))
1018: (loop-make-variable name initialization dtype)))
1019:
1020:
1021: (defun loop-declare-variable (name dtype)
1022: (cond ((or (null name) (null dtype)) ())
1023: ((symbolp name)
1024: (cond ((memq name loop-nodeclare))
1025: #+Multics
1026: ; local type dcls of specials lose. This doesn't work
1027: ; for locally-declared specials.
1028: ((get name 'special))
1029: ((data-type? dtype)
1030: (setq loop-declarations
1031: (append (variable-declarations dtype name)
1032: loop-declarations)))
1033: #+Meaningful-Type-Declarations
1034: ((si:loop-tmember dtype '(fixnum flonum))
1035: (push `(,dtype ,name) loop-declarations))))
1036: ((object-that-cares-p name)
1037: (cond ((object-that-cares-p dtype)
1038: (loop-declare-variable (car name) (car dtype))
1039: (loop-declare-variable (cdr name) (cdr dtype)))
1040: ('t (loop-declare-variable (car name) dtype)
1041: (loop-declare-variable (cdr name) dtype))))
1042: #+Vector-Destructuring
1043: ((vectorp name)
1044: (do ((i 0 (1+ i))
1045: (n (vector-length name))
1046: (dtn (and (vectorp dtype) (vector-length dtype)))
1047: (dti 0 (1+ dti)))
1048: ((= i n))
1049: #+Meaningful-Type-Declarations (declare (fixnum i n dti))
1050: (loop-declare-variable
1051: (vref name i)
1052: (if (null dtn) dtype (and (< dti dtn) (vref dtype dti))))))
1053: ('t (loop-simple-error "can't hack this"
1054: (list 'loop-declare-variable name dtype)))))
1055:
1056:
1057: #+For-PDP10
1058: (declare (special squid))
1059:
1060: (defun loop-constantp (form)
1061: (or (numberp form)
1062: #+For-NIL (or (null form) (vectorp form))
1063: #-For-NIL (memq form '(t ()))
1064: #-For-PDP10 (stringp form)
1065: (and (not (atom form))
1066: #-Run-on-PDP10 (eq (car form) 'quote)
1067: #+Run-on-PDP10 (or (eq (car form) 'quote)
1068: ; SQUID implies quoting.
1069: (and compiler-state (eq (car form) squid))))
1070: ))
1071:
1072: (defun loop-maybe-bind-form (form data-type?)
1073: ; Consider implementations which will not keep EQ quoted constants
1074: ; EQ after compilation & loading.
1075: ; Note FUNCTION is not hacked, multiple occurences might cause the
1076: ; compiler to break the function off multiple times!
1077: ; Hacking it probably isn't too important here anyway. The ones that
1078: ; matter are the ones that use it as a stepper (or whatever), which
1079: ; handle it specially.
1080: (if (loop-constantp form) form
1081: (loop-make-variable (gensym) form data-type?)))
1082:
1083:
1084: (defun loop-optional-type ()
1085: (let ((token (car loop-source-code)))
1086: (and (not (null token))
1087: (or (not (atom token))
1088: (data-type? token)
1089: (si:loop-tmember token '(fixnum flonum integer number notype
1090: #+Loop-Small-Floatp small-flonum)))
1091: (loop-pop-source))))
1092:
1093:
1094: ;Incorporates conditional if necessary
1095: (defun loop-make-conditionalization (form)
1096: (cond ((not (null loop-conditionals))
1097: (rplacd (last (car (last (car (last loop-conditionals)))))
1098: (ncons form))
1099: (cond ((si:loop-tequal (car loop-source-code) 'and)
1100: (loop-pop-source)
1101: ())
1102: ((si:loop-tequal (car loop-source-code) 'else)
1103: (loop-pop-source)
1104: ;; If we are already inside an else clause, close it off
1105: ;; and nest it inside the containing when clause
1106: (let ((innermost (car (last loop-conditionals))))
1107: (cond ((null (cddr innermost))) ;Now in a WHEN clause, OK
1108: ((null (cdr loop-conditionals))
1109: (loop-simple-error "More ELSEs than WHENs"
1110: (list 'else (car loop-source-code)
1111: (cadr loop-source-code))))
1112: ('t (setq loop-conditionals (cdr (nreverse loop-conditionals)))
1113: (rplacd (last (car (last (car loop-conditionals))))
1114: (ncons innermost))
1115: (setq loop-conditionals (nreverse loop-conditionals)))))
1116: ;; Start a new else clause
1117: (rplacd (last (car (last loop-conditionals)))
1118: (ncons (ncons ''t)))
1119: ())
1120: ('t ;Nest up the conditionals and output them
1121: (do ((prev (car loop-conditionals) (car l))
1122: (l (cdr loop-conditionals) (cdr l)))
1123: ((null l))
1124: (rplacd (last (car (last prev))) (ncons (car l))))
1125: (prog1 (car loop-conditionals)
1126: (setq loop-conditionals ())))))
1127: ('t form)))
1128:
1129: (defun loop-pseudo-body (form &aux (z (loop-make-conditionalization form)))
1130: (cond ((not (null z))
1131: (cond (loop-emitted-body? (push z loop-body))
1132: ('t (push z loop-before-loop) (push z loop-after-body))))))
1133:
1134: (defun loop-emit-body (form)
1135: (setq loop-emitted-body? 't)
1136: (loop-pseudo-body form))
1137:
1138:
1139: #+Named-PROGs
1140: (defun loop-do-named ()
1141: (let ((name (loop-pop-source)))
1142: (or (and name (symbolp name))
1143: (loop-simple-error "Bad name for your loop construct" name))
1144: (and (cdr (setq loop-prog-names (cons name loop-prog-names)))
1145: (loop-simple-error "Too many names for your loop construct"
1146: loop-prog-names))))
1147:
1148: (defun loop-do-initially ()
1149: (push (loop-get-form) loop-prologue))
1150:
1151: (defun loop-nodeclare (&aux (varlist (loop-pop-source)))
1152: (or (and varlist (eq (typep varlist) 'list))
1153: (loop-simple-error "Bad varlist to nodeclare loop clause" varlist))
1154: (setq loop-nodeclare (append varlist loop-nodeclare)))
1155:
1156: (defun loop-do-finally ()
1157: (push (loop-get-form) loop-epilogue))
1158:
1159: (defun loop-do-do ()
1160: (loop-emit-body (loop-get-form)))
1161:
1162: (defun loop-do-return ()
1163: (loop-pseudo-body `(return ,(loop-get-form))))
1164:
1165:
1166: ;;;; List Collection
1167:
1168: ; The way we collect (list-collect) things is to bind two variables.
1169: ; One is the final result, and is accessible for value during the
1170: ; loop compuation. The second is the "tail". In implementations where
1171: ; we can do so, the tail var is initialized to a locative of the first,
1172: ; such that it can be updated with RPLACD. In other implementations,
1173: ; the update must be conditionalized (on whether or not the tail is NIL).
1174:
1175: ; For PDP10 Maclisp:
1176: ; The "value cell" of a special variable is a (pseudo) list cell, the CDR
1177: ; of which is the value. Hence the abovementioned tail variable gets
1178: ; initialized to this. (It happens to be the CDAR of the symbol.)
1179: ; For local variables in compiled code, the Maclisp compiler implements
1180: ; a (undocumented private) form of the
1181: ; "(setq tail (variable-location var))" construct; specifically, it
1182: ; is of the form (#.gofoo var tail). This construct must appear in
1183: ; the binding environment those variables are bound in, currently.
1184: ; Note that this hack only currently works for local variables, so loop
1185: ; has to check to see if the variable is special. It is anticipated,
1186: ; however, that the compiler will be able to do this all by itself
1187: ; at some point.
1188:
1189: #+For-PDP10
1190: (progn 'compile
1191: (cond ((status feature complr)
1192: (setq loop-specvar-hack ((lambda (obarray)
1193: (implode '(s p e c v a r s)))
1194: sobarray))
1195: (defun loop-collect-init-compiler (form)
1196: (cond ((memq compiler-state '(toplevel maklap))
1197: ; We are being "toplevel" macro expanded.
1198: ; We MUST expand into something which can be
1199: ; evaluated without loop, in the interpreter.
1200: `(setq ,(caddr form) (munkam (value-cell-location
1201: ',(cadr form)))))
1202: ((or specials
1203: (get (cadr form) 'special)
1204: (assq (cadr form) (symeval loop-specvar-hack)))
1205: `(setq ,(caddr form) (cdar ',(cadr form))))
1206: (t (cons gofoo (cdr form)))))
1207: (push '(loop-collect-init . loop-collect-init-compiler)
1208: macrolist)))
1209: (defun loop-collect-init fexpr (x)
1210: (set (cadr x) (cdar (car x)))))
1211:
1212: #+(and Hairy-Collection (not For-PDP10))
1213: (defmacro loop-collect-init (var1 var2)
1214: #+Lispm ;***** Remove kludgey fboundp when everyone up-to-date *****
1215: `(setq ,var2 ,(if (fboundp 'variable-location)
1216: `(variable-location ,var1)
1217: `(value-cell-location ',var1)))
1218: #-Lispm `(setq ,var2 (munkam (value-cell-location ',var1))))
1219:
1220:
1221: (defun loop-do-collect (type)
1222: (let ((var) (form) (tem) (tail) (dtype) (cruft) (rvar)
1223: (ctype (cond ((memq type '(max min)) 'maxmin)
1224: ((memq type '(nconc list append)) 'list)
1225: ((memq type '(count sum)) 'sum)
1226: ('t (loop-simple-error
1227: "unrecognized LOOP collecting keyword" type)))))
1228: (setq form (loop-get-form) dtype (loop-optional-type))
1229: (cond ((si:loop-tequal (car loop-source-code) 'into)
1230: (loop-pop-source)
1231: (setq rvar (setq var (loop-pop-source)))))
1232: ; CRUFT will be (varname ctype dtype var tail (optional tem))
1233: (cond ((setq cruft (assq var loop-collect-cruft))
1234: (cond ((not (eq ctype (car (setq cruft (cdr cruft)))))
1235: (loop-simple-error
1236: "incompatible LOOP collection types"
1237: (list ctype (car cruft))))
1238: ((and dtype (not (eq dtype (cadr cruft))))
1239: ;Conditional should be on data-type reality
1240: #+Run-in-Maclisp
1241: (loop-simple-error
1242: "Unequal data types in multiple collections"
1243: (list dtype (cadr cruft) (car cruft)))
1244: #-Run-in-Maclisp
1245: (ferror () "~A and ~A Unequal data types into ~A"
1246: dtype (cadr cruft) (car cruft))))
1247: (setq dtype (car (setq cruft (cdr cruft)))
1248: var (car (setq cruft (cdr cruft)))
1249: tail (car (setq cruft (cdr cruft)))
1250: tem (cadr cruft))
1251: (and (eq ctype 'maxmin)
1252: (not (atom form)) (null tem)
1253: (rplaca (cdr cruft) (setq tem (loop-make-variable
1254: (gensym) () dtype)))))
1255: ('t (and (null dtype)
1256: (setq dtype (cond ((eq type 'count) 'fixnum)
1257: ((memq type '(min max sum)) 'number))))
1258: (or var (push `(return ,(setq var (gensym)))
1259: loop-after-epilogue))
1260: (or (eq ctype 'list) (loop-make-iteration-variable var () dtype))
1261: (setq tail
1262: (cond ((eq ctype 'list)
1263: #-Hairy-Collection
1264: (setq tem (loop-make-variable (gensym) () ()))
1265: (car (setq loop-collection-crocks
1266: (list* (gensym) var
1267: loop-collection-crocks))))
1268: ((eq ctype 'maxmin)
1269: (or (atom form)
1270: (setq tem (loop-make-variable
1271: (gensym) () dtype)))
1272: (loop-make-variable (gensym) ''t ()))))
1273: (push (list rvar ctype dtype var tail tem)
1274: loop-collect-cruft)))
1275: (loop-emit-body
1276: (caseq type
1277: (count (setq tem `(setq ,var (,(loop-typed-arith 'add1 dtype)
1278: ,var)))
1279: (if (member form '(t 't)) tem `(and ,form ,tem)))
1280: (sum `(setq ,var (,(loop-typed-arith 'plus dtype) ,form ,var)))
1281: ((max min)
1282: (let ((forms ()) (arglist ()))
1283: ; TEM is temporary, properly typed.
1284: (and tem (setq forms `((setq ,tem ,form)) form tem))
1285: (setq arglist (list var form))
1286: (push (if (si:loop-tmember dtype '(fixnum flonum
1287: #+Loop-Small-Floatp
1288: small-flonum))
1289: ; no contagious arithmetic
1290: `(and (or ,tail
1291: (,(loop-typed-arith
1292: (if (eq type 'max) 'lessp 'greaterp)
1293: dtype)
1294: . ,arglist))
1295: (setq ,tail () . ,arglist))
1296: ; potentially contagious arithmetic -- must use
1297: ; MAX or MIN so that var will be contaminated
1298: `(setq ,var (cond (,tail (setq ,tail ()) ,form)
1299: ((,type . ,arglist)))))
1300: forms)
1301: (if (cdr forms) (cons 'progn (nreverse forms)) (car forms))))
1302: (t (caseq type
1303: (list (setq form (list 'list form)))
1304: (append (or (and (not (atom form)) (eq (car form) 'list))
1305: (setq form #+Lispm `(copylist* ,form)
1306: #-Lispm `(append ,form ())))))
1307: #+Hairy-Collection
1308: (let ((q `(rplacd ,tail ,form)))
1309: (cond ((and (not (atom form)) (eq (car form) 'list)
1310: (not (null (cdr form))))
1311: ; RPLACD of cdr-coded list:
1312: #+Lispm
1313: (rplaca (cddr q)
1314: (if (cddr form) `(list* ,@(cdr form) ())
1315: `(ncons ,(cadr form))))
1316: `(setq ,tail ,(loop-cdrify (cdr form) q)))
1317: ('t `(and (cdr ,q)
1318: (setq ,tail (last (cdr ,tail)))))))
1319: #-Hairy-Collection
1320: (let ((q `(cond (,tail (cdr (rplacd ,tail ,tem)))
1321: ((setq ,var ,tem)))))
1322: (if (and (not (atom form)) (eq (car form) 'list) (cdr form))
1323: `(setq ,tem ,form ,tail ,(loop-cdrify (cddr form) q))
1324: `(and (setq ,tem ,form) (setq ,tail (last ,q))))))))))
1325:
1326:
1327: (defun loop-cdrify (arglist form)
1328: (do ((size (length arglist) (- size 4)))
1329: ((< size 4)
1330: (if (zerop size) form
1331: (list (cond ((= size 1) 'cdr) ((= size 2) 'cddr) ('t 'cdddr))
1332: form)))
1333: #+Meaningful-Type-Declarations (declare (fixnum size))
1334: (setq form (list 'cddddr form))))
1335:
1336:
1337: (defun loop-do-while (cond kwd &aux (form (loop-get-form)))
1338: (and loop-conditionals (loop-simple-error
1339: "not allowed inside LOOP conditional"
1340: (list kwd form)))
1341: (loop-pseudo-body `(,cond ,form (go end-loop))))
1342:
1343:
1344: (defun loop-do-when (negate?)
1345: (let ((form (loop-get-form)) (cond))
1346: (cond ((si:loop-tequal (cadr loop-source-code) 'it)
1347: ;WHEN foo RETURN IT and the like
1348: (setq cond `(setq ,(loop-when-it-variable) ,form))
1349: (setq loop-source-code ;Plug in variable for IT
1350: (list* (car loop-source-code)
1351: loop-when-it-variable
1352: (cddr loop-source-code))))
1353: ('t (setq cond form)))
1354: (and negate? (setq cond `(not ,cond)))
1355: (setq loop-conditionals (nconc loop-conditionals `((cond (,cond)))))))
1356:
1357: (defun loop-do-with ()
1358: (do ((var) (equals) (val) (dtype)) (())
1359: (setq var (loop-pop-source) equals (car loop-source-code))
1360: (cond ((si:loop-tequal equals '=)
1361: (loop-pop-source)
1362: (setq val (loop-get-form) dtype ()))
1363: ((or (si:loop-tequal equals 'and)
1364: (si:loop-tassoc equals loop-keyword-alist)
1365: (si:loop-tassoc equals loop-iteration-keyword-alist))
1366: (setq val () dtype ()))
1367: ('t (setq dtype (loop-pop-source) equals (car loop-source-code))
1368: (cond ((si:loop-tequal equals '=)
1369: (loop-pop-source)
1370: (setq val (loop-get-form)))
1371: ((and (not (null loop-source-code))
1372: (not (si:loop-tassoc equals loop-keyword-alist))
1373: (not (si:loop-tassoc
1374: equals loop-iteration-keyword-alist))
1375: (not (si:loop-tequal equals 'and)))
1376: (loop-simple-error "Garbage where = expected" equals))
1377: ('t (setq val ())))))
1378: (loop-make-variable var val dtype)
1379: (if (not (si:loop-tequal (car loop-source-code) 'and)) (return ())
1380: (loop-pop-source)))
1381: (loop-bind-block))
1382:
1383: (defun loop-do-always (pred)
1384: (let ((form (loop-get-form)))
1385: (loop-emit-body `(,pred ,form (return ())))
1386: (push '(return 't) loop-after-epilogue)))
1387:
1388: ;THEREIS expression
1389: ;If expression evaluates non-nil, return that value.
1390: (defun loop-do-thereis ()
1391: (loop-emit-body `(and (setq ,(loop-when-it-variable) ,(loop-get-form))
1392: (return ,loop-when-it-variable))))
1393:
1394:
1395: ;;;; Hacks
1396:
1397: #+Meaningful-Type-Declarations
1398: (declare (fixnum (loop-simplep-1 notype)))
1399:
1400: (defun si:loop-simplep (expr)
1401: (if (null expr) 0
1402: (*catch 'si:loop-simplep
1403: (let ((ans (si:loop-simplep-1 expr)))
1404: #+Meaningful-Type-Declarations (declare (fixnum ans))
1405: (and (< ans 20.) ans)))))
1406:
1407: (defvar si:loop-simplep
1408: (append '(> < greaterp lessp plusp minusp typep zerop
1409: plus difference + - add1 sub1 1+ 1-
1410: +$ -$ 1+$ 1-$ boole rot ash ldb equal atom
1411: setq prog1 prog2 and or =)
1412: #+(or Lispm NIL) '(aref ar-1 ar-2 ar-3)
1413: #+Lispm '#.(and (loop-featurep Lispm)
1414: (mapcar 'ascii '(#/ #/ #/)))
1415: #+For-NIL '(vref vector-length 1+& 1-& +& -& +p -p 0p *& //& \&
1416: si:xref char string-length)
1417: ))
1418:
1419: (defun si:loop-simplep-1 (x)
1420: (let ((z 0))
1421: #+Meaningful-Type-Declarations (declare (fixnum z))
1422: (cond ((loop-constantp x) 0)
1423: ((atom x) 1)
1424: ((eq (car x) 'cond)
1425: (do ((cl (cdr x) (cdr cl))) ((null cl))
1426: (do ((f (car cl) (cdr f))) ((null f))
1427: (setq z (+ (si:loop-simplep-1 (car f)) z 1))))
1428: z)
1429: ((symbolp (car x))
1430: (let ((fn (car x)) (tem ()))
1431: (cond ((setq tem (get fn 'si:loop-simplep))
1432: (if (fixp tem) (setq z tem)
1433: (setq z (funcall tem x) x ())))
1434: ((memq fn '(null not eq go return progn)))
1435: (#+Run-on-PDP10
1436: (or (not (minusp (+internal-carcdrp fn)))
1437: (eq fn 'cxr))
1438: #-Run-on-PDP10 (memq fn '(car cdr))
1439: (setq z 1))
1440: #-Run-on-PDP10
1441: ((memq fn '(caar cadr cdar cddr)) (setq z 2))
1442: #-Run-on-PDP10
1443: ((memq fn '(caaar caadr cadar caddr
1444: cdaar cdadr cddar cdddr))
1445: (setq z 3))
1446: #-Run-on-PDP10
1447: ((memq fn '(caaaar caaadr caadar caaddr
1448: cadaar cadadr caddar cadddr
1449: cdaaar cdaadr cdadar cdaddr
1450: cddaar cddadr cdddar cddddr))
1451: (setq z 4))
1452: ((memq fn si:loop-simplep)
1453: (setq z 2))
1454: (#+(or Lispm For-PDP10 For-NIL)
1455: (not (eq (setq tem (macroexpand-1 x)) x))
1456: #+Franz (not (eq (setq tem (macroexpand x)) x))
1457: #+Multics
1458: (setq tem (get (car x) 'macro))
1459: #+Multics (setq tem (funcall tem x))
1460: (setq z (si:loop-simplep-1 tem) x ()))
1461: ('t (*throw 'si:loop-simplep ())))
1462: (do ((l (cdr x) (cdr l))) ((null l))
1463: (setq z (+ (si:loop-simplep-1 (car l)) 1 z)))
1464: z))
1465: ('t (*throw 'si:loop-simplep ())))))
1466:
1467:
1468: ;;;; The iteration driver
1469: (defun loop-hack-iteration (entry)
1470: (do ((last-entry entry)
1471: (source loop-source-code loop-source-code)
1472: (pre-step-tests ())
1473: (steps ())
1474: (post-step-tests ())
1475: (pseudo-steps ())
1476: (pre-loop-pre-step-tests ())
1477: (pre-loop-steps ())
1478: (pre-loop-post-step-tests ())
1479: (pre-loop-pseudo-steps ())
1480: (tem) (data) (foo) (bar))
1481: (())
1482: ; Note we collect endtests in reverse order, but steps in correct
1483: ; order. LOOP-END-TESTIFY does the nreverse for us.
1484: (setq tem (setq data (apply (cadr entry) (cddr entry))))
1485: (and (car tem) (push (car tem) pre-step-tests))
1486: (setq steps (nconc steps (loop-copylist* (car (setq tem (cdr tem))))))
1487: (and (car (setq tem (cdr tem))) (push (car tem) post-step-tests))
1488: (setq pseudo-steps
1489: (nconc pseudo-steps (loop-copylist* (car (setq tem (cdr tem))))))
1490: (setq tem (cdr tem))
1491: (and (or loop-conditionals loop-emitted-body?)
1492: (or tem pre-step-tests post-step-tests pseudo-steps)
1493: (let ((cruft (list (car entry) (car source)
1494: (cadr source) (caddr source))))
1495: (if loop-emitted-body?
1496: (loop-simple-error
1497: "Iteration is not allowed to follow body code" cruft)
1498: (loop-simple-error
1499: "Iteration starting inside of conditional in LOOP"
1500: cruft))))
1501: (or tem (setq tem data))
1502: (and (car tem) (push (car tem) pre-loop-pre-step-tests))
1503: (setq pre-loop-steps
1504: (nconc pre-loop-steps (loop-copylist* (car (setq tem (cdr tem))))))
1505: (and (car (setq tem (cdr tem))) (push (car tem) pre-loop-post-step-tests))
1506: (setq pre-loop-pseudo-steps
1507: (nconc pre-loop-pseudo-steps (loop-copylist* (cadr tem))))
1508: (cond ((or (not (si:loop-tequal (car loop-source-code) 'and))
1509: (and loop-conditionals
1510: (not (si:loop-tassoc (cadr loop-source-code)
1511: loop-iteration-keyword-alist))))
1512: (setq foo (list (loop-end-testify pre-loop-pre-step-tests)
1513: (loop-make-psetq pre-loop-steps)
1514: (loop-end-testify pre-loop-post-step-tests)
1515: (loop-make-setq pre-loop-pseudo-steps))
1516: bar (list (loop-end-testify pre-step-tests)
1517: (loop-make-psetq steps)
1518: (loop-end-testify post-step-tests)
1519: (loop-make-setq pseudo-steps)))
1520: (cond ((not loop-conditionals)
1521: (setq loop-before-loop (nreconc foo loop-before-loop)
1522: loop-after-body (nreconc bar loop-after-body)))
1523: ('t ((lambda (loop-conditionals)
1524: (push (loop-make-conditionalization
1525: (cons 'progn (delq () foo)))
1526: loop-before-loop))
1527: (mapcar '(lambda (x) ;Copy parts that will get rplacd'ed
1528: (cons (car x)
1529: (mapcar '(lambda (x) (loop-copylist* x)) (cdr x))))
1530: loop-conditionals))
1531: (push (loop-make-conditionalization
1532: (cons 'progn (delq () bar)))
1533: loop-after-body)))
1534: (loop-bind-block)
1535: (return ())))
1536: (loop-pop-source) ; flush the "AND"
1537: (setq entry (cond ((setq tem (si:loop-tassoc
1538: (car loop-source-code)
1539: loop-iteration-keyword-alist))
1540: (loop-pop-source)
1541: (setq last-entry tem))
1542: ('t last-entry)))))
1543:
1544:
1545: ;FOR variable keyword ..args..
1546: (defun loop-do-for ()
1547: (let ((var (loop-pop-source))
1548: (data-type? (loop-optional-type))
1549: (keyword (loop-pop-source))
1550: (first-arg (loop-get-form))
1551: (tem ()))
1552: (or (setq tem (si:loop-tassoc keyword loop-for-keyword-alist))
1553: (loop-simple-error
1554: "Unknown keyword in FOR or AS clause in LOOP"
1555: (list 'for var keyword)))
1556: (lexpr-funcall (cadr tem) var first-arg data-type? (cddr tem))))
1557:
1558:
1559: (defun loop-do-repeat ()
1560: (let ((var (loop-make-variable (gensym) (loop-get-form) 'fixnum)))
1561: `((not (,(loop-typed-arith 'plusp 'fixnum) ,var))
1562: () ()
1563: (,var (,(loop-typed-arith 'sub1 'fixnum) ,var)))))
1564:
1565:
1566: ; Kludge the First
1567: (defun loop-when-it-variable ()
1568: (or loop-when-it-variable
1569: (setq loop-when-it-variable
1570: (loop-make-variable (gensym) () ()))))
1571:
1572:
1573:
1574: (defun loop-for-equals (var val data-type?)
1575: (cond ((si:loop-tequal (car loop-source-code) 'then)
1576: ;FOR var = first THEN next
1577: (loop-pop-source)
1578: (loop-make-iteration-variable var val data-type?)
1579: `(() (,var ,(loop-get-form)) () ()
1580: () () () ()))
1581: ('t (loop-make-iteration-variable var () data-type?)
1582: (let ((varval (list var val)))
1583: (cond (loop-emitted-body?
1584: (loop-emit-body (loop-make-setq varval))
1585: '(() () () ()))
1586: (`(() ,varval () ())))))))
1587:
1588: (defun loop-for-first (var val data-type?)
1589: (or (si:loop-tequal (car loop-source-code) 'then)
1590: (loop-simple-error "found where THEN expected in FOR ... FIRST"
1591: (car loop-source-code)))
1592: (loop-pop-source)
1593: (loop-make-iteration-variable var () data-type?)
1594: `(() (,var ,(loop-get-form)) () () () (,var ,val) () ()))
1595:
1596:
1597: (defun loop-list-stepper (var val data-type? fn)
1598: (let ((stepper (cond ((si:loop-tequal (car loop-source-code) 'by)
1599: (loop-pop-source) (loop-get-form))
1600: ('t '(function cdr))))
1601: (var1 ()) (stepvar ()) (step ()) (et ()) (pseudo ()))
1602: (setq step (if (or (atom stepper)
1603: (not (memq (car stepper) '(quote function))))
1604: `(funcall ,(setq stepvar (gensym)))
1605: (list (cadr stepper))))
1606: (cond ((and (atom var)
1607: ;; (eq (car step) 'cdr)
1608: (not fn))
1609: (setq var1 (loop-make-iteration-variable var val data-type?)))
1610: ('t (loop-make-iteration-variable var () data-type?)
1611: (setq var1 (loop-make-variable (gensym) val ()))
1612: (setq pseudo (list var (if fn (list fn var1) var1)))))
1613: (rplacd (last step) (list var1))
1614: (and stepvar (loop-make-variable stepvar stepper ()))
1615: (setq stepper (list var1 step) et `(null ,var1))
1616: (if (not pseudo) `(() ,stepper ,et () () () ,et ())
1617: (if (eq (car step) 'cdr) `(,et ,pseudo () ,stepper)
1618: `((null (setq . ,stepper)) () () ,pseudo ,et () () ,pseudo)))))
1619:
1620:
1621: (defun loop-for-arithmetic (var val data-type? kwd)
1622: ; Args to loop-sequencer:
1623: ; indexv indexv-type variable? vtype? sequencev? sequence-type
1624: ; stephack? default-top? crap prep-phrases
1625: (si:loop-sequencer
1626: var (or data-type? 'fixnum) () () () () () () `(for ,var ,kwd ,val)
1627: (cons (list kwd val)
1628: (loop-gather-preps
1629: '(from upfrom downfrom to upto downto above below by)
1630: ()))))
1631:
1632:
1633: (defun si:loop-named-variable (name)
1634: (let ((tem (si:loop-tassoc name loop-named-variables)))
1635: (cond ((null tem) (gensym))
1636: ('t (setq loop-named-variables (delq tem loop-named-variables))
1637: (cdr tem)))))
1638:
1639: #+Run-in-Maclisp ;Gross me out
1640: (and (status feature #+Multics Compiler #-Multics complr)
1641: (*expr si:loop-named-variable))
1642:
1643:
1644: ; Note: path functions are allowed to use loop-make-variable, hack
1645: ; the prologue, etc.
1646: (defun loop-for-being (var val data-type?)
1647: ; FOR var BEING something ... - var = VAR, something = VAL.
1648: ; If what passes syntactically for a pathname isn't, then
1649: ; we trap to the DEFAULT-LOOP-PATH path; the expression which looked like
1650: ; a path is given as an argument to the IN preposition. Thus,
1651: ; by default, FOR var BEING EACH expr OF expr-2
1652: ; ==> FOR var BEING DEFAULT-LOOP-PATH IN expr OF expr-2.
1653: (let ((tem) (inclusive?) (ipps) (each?) (attachment))
1654: (if (or (si:loop-tequal val 'each) (si:loop-tequal val 'the))
1655: (setq each? 't val (car loop-source-code))
1656: (push val loop-source-code))
1657: (cond ((and (setq tem (si:loop-tassoc val loop-path-keyword-alist))
1658: (or each? (not (si:loop-tequal (cadr loop-source-code)
1659: 'and))))
1660: ;; FOR var BEING {each} path {prep expr}..., but NOT
1661: ;; FOR var BEING var-which-looks-like-path AND {ITS} ...
1662: (loop-pop-source))
1663: ('t (setq val (loop-get-form))
1664: (cond ((si:loop-tequal (car loop-source-code) 'and)
1665: ;; FOR var BEING value AND ITS path-or-ar
1666: (or (null each?)
1667: (loop-simple-error
1668: "Malformed BEING EACH clause in LOOP" var))
1669: (setq ipps `((of ,val)) inclusive? 't)
1670: (loop-pop-source)
1671: (or (si:loop-tmember (setq tem (loop-pop-source))
1672: '(its his her their each))
1673: (loop-simple-error
1674: "found where ITS or EACH expected in LOOP path"
1675: tem))
1676: (if (setq tem (si:loop-tassoc
1677: (car loop-source-code)
1678: loop-path-keyword-alist))
1679: (loop-pop-source)
1680: (push (setq attachment `(in ,(loop-get-form)))
1681: ipps)))
1682: ((not (setq tem (si:loop-tassoc
1683: (car loop-source-code)
1684: loop-path-keyword-alist)))
1685: ; FOR var BEING {each} a-r ...
1686: (setq ipps (list (setq attachment (list 'in val)))))
1687: ('t ; FOR var BEING {each} pathname ...
1688: ; Here, VAL should be just PATHNAME.
1689: (loop-pop-source)))))
1690: (cond ((not (null tem)))
1691: ((not (setq tem (si:loop-tassoc 'default-loop-path
1692: loop-path-keyword-alist)))
1693: (loop-simple-error "Undefined LOOP iteration path"
1694: (cadr attachment))))
1695: (setq tem (funcall (cadr tem) (car tem) var data-type?
1696: (nreconc ipps (loop-gather-preps (caddr tem) 't))
1697: inclusive? (caddr tem) (cdddr tem)))
1698: (and loop-named-variables
1699: (loop-simple-error "unused USING variables" loop-named-variables))
1700: ; For error continuability (if there is any):
1701: (setq loop-named-variables ())
1702: ;; TEM is now (bindings prologue-forms . stuff-to-pass-back)
1703: (do ((l (car tem) (cdr l)) (x)) ((null l))
1704: (if (atom (setq x (car l)))
1705: (loop-make-iteration-variable x () ())
1706: (loop-make-iteration-variable (car x) (cadr x) (caddr x))))
1707: (setq loop-prologue (nconc (reverse (cadr tem)) loop-prologue))
1708: (cddr tem)))
1709:
1710:
1711: (defun loop-gather-preps (preps-allowed crockp)
1712: (do ((token (car loop-source-code) (car loop-source-code)) (preps ()))
1713: (())
1714: (cond ((si:loop-tmember token preps-allowed)
1715: (push (list (loop-pop-source) (loop-get-form)) preps))
1716: ((si:loop-tequal token 'using)
1717: (loop-pop-source)
1718: (or crockp (loop-simple-error
1719: "USING used in illegal context"
1720: (list 'using (car loop-source-code))))
1721: (do ((z (car loop-source-code) (car loop-source-code)) (tem))
1722: ((atom z))
1723: (and (or (atom (cdr z))
1724: (not (null (cddr z)))
1725: (not (symbolp (car z)))
1726: (and (cadr z) (not (symbolp (cadr z)))))
1727: (loop-simple-error
1728: "bad variable pair in path USING phrase" z))
1729: (cond ((not (null (cadr z)))
1730: (and (setq tem (si:loop-tassoc
1731: (car z) loop-named-variables))
1732: (loop-simple-error
1733: "Duplicated var substitition in USING phrase"
1734: (list tem z)))
1735: (push (cons (car z) (cadr z)) loop-named-variables)))
1736: (loop-pop-source)))
1737: ('t (return (nreverse preps))))))
1738:
1739: (defun loop-add-path (name data)
1740: (setq loop-path-keyword-alist
1741: (cons (cons name data)
1742: ; Don't change this to use DELASSQ in PDP10, the lsubr
1743: ; calling sequence makes that lose.
1744: (delq (si:loop-tassoc name loop-path-keyword-alist)
1745: loop-path-keyword-alist)))
1746: ())
1747:
1748: #+Run-on-PDP10
1749: (declare ; Suck my obarray...
1750: (own-symbol define-loop-path define-loop-sequence-path))
1751:
1752: (defmacro define-loop-path (names &rest cruft)
1753: (setq names (if (atom names) (list names) names))
1754: #-For-Maclisp
1755: (let ((forms (mapcar #'(lambda (name) `(loop-add-path ',name ',cruft))
1756: names)))
1757: `(eval-when (eval load compile)
1758: #+For-NIL (flush-macromemos 'loop ())
1759: ,@forms))
1760: #+For-Maclisp
1761: (subst (do ((l)) ((null names) l)
1762: (setq l (cons `(setq loop-path-keyword-alist
1763: (cons '(,(car names) . ,cruft)
1764: (delq (assq ',(car names)
1765: loop-path-keyword-alist)
1766: loop-path-keyword-alist)))
1767: l)
1768: names (cdr names)))
1769: 'progn
1770: '(eval-when (eval load compile)
1771: #-For-PDP10 (or (boundp 'loop-path-keyword-alist)
1772: (setq loop-path-keyword-alist ()))
1773: #+For-PDP10 (and (or (boundp 'loop-path-keyword-alist)
1774: (setq loop-path-keyword-alist ()))
1775: (flush-macromemos 'loop ()))
1776: . progn)))
1777:
1778:
1779: (defun si:loop-sequencer (indexv indexv-type
1780: variable? vtype?
1781: sequencev? sequence-type?
1782: stephack? default-top?
1783: crap prep-phrases)
1784: (let ((endform) (sequencep) (test)
1785: (step ; Gross me out!
1786: (add1 (or (loop-typed-init indexv-type) 0)))
1787: (dir) (inclusive-iteration?) (start-given?) (limit-given?))
1788: (and variable? (loop-make-iteration-variable variable? () vtype?))
1789: (do ((l prep-phrases (cdr l)) (prep) (form) (odir)) ((null l))
1790: (setq prep (caar l) form (cadar l))
1791: (cond ((si:loop-tmember prep '(of in))
1792: (and sequencep (loop-simple-error
1793: "Sequence duplicated in LOOP path"
1794: (list variable? (car l))))
1795: (setq sequencep 't)
1796: (loop-make-variable sequencev? form sequence-type?))
1797: ((si:loop-tmember prep '(from downfrom upfrom))
1798: (and start-given?
1799: (loop-simple-error
1800: "Iteration start redundantly specified in LOOP sequencing"
1801: (append crap l)))
1802: (setq start-given? 't)
1803: (cond ((si:loop-tequal prep 'downfrom) (setq dir 'down))
1804: ((si:loop-tequal prep 'upfrom) (setq dir 'up)))
1805: (loop-make-iteration-variable indexv form indexv-type))
1806: ((cond ((si:loop-tequal prep 'upto)
1807: (setq inclusive-iteration? (setq dir 'up)))
1808: ((si:loop-tequal prep 'to)
1809: (setq inclusive-iteration? 't))
1810: ((si:loop-tequal prep 'downto)
1811: (setq inclusive-iteration? (setq dir 'down)))
1812: ((si:loop-tequal prep 'above) (setq dir 'down))
1813: ((si:loop-tequal prep 'below) (setq dir 'up)))
1814: (and limit-given?
1815: (loop-simple-error
1816: "Endtest redundantly specified in LOOP sequencing path"
1817: (append crap l)))
1818: (setq limit-given? 't)
1819: (setq endform (loop-maybe-bind-form form indexv-type)))
1820: ((si:loop-tequal prep 'by)
1821: (setq step (if (loop-constantp form) form
1822: (loop-make-variable (gensym) form 'fixnum))))
1823: ('t ; This is a fatal internal error...
1824: (loop-simple-error "Illegal prep in sequence path"
1825: (append crap l))))
1826: (and odir dir (not (eq dir odir))
1827: (loop-simple-error
1828: "Conflicting stepping directions in LOOP sequencing path"
1829: (append crap l)))
1830: (setq odir dir))
1831: (and sequencev? (not sequencep)
1832: (loop-simple-error "Missing OF phrase in sequence path" crap))
1833: ; Now fill in the defaults.
1834: (setq step (list indexv step))
1835: (cond ((memq dir '(() up))
1836: (or start-given?
1837: (loop-make-iteration-variable indexv 0 indexv-type))
1838: (and (or limit-given?
1839: (cond (default-top?
1840: (loop-make-variable
1841: (setq endform (gensym)) () indexv-type)
1842: (push `(setq ,endform ,default-top?)
1843: loop-prologue))))
1844: (setq test (if inclusive-iteration? '(greaterp . args)
1845: '(not (lessp . args)))))
1846: (push 'plus step))
1847: ('t (cond ((not start-given?)
1848: (or default-top?
1849: (loop-simple-error
1850: "Don't know where to start stepping"
1851: (append crap prep-phrases)))
1852: (loop-make-iteration-variable indexv 0 indexv-type)
1853: (push `(setq ,indexv
1854: (,(loop-typed-arith 'sub1 indexv-type)
1855: ,default-top?))
1856: loop-prologue)))
1857: (cond ((and default-top? (not endform))
1858: (setq endform (loop-typed-init indexv-type)
1859: inclusive-iteration? 't)))
1860: (and (not (null endform))
1861: (setq test (if inclusive-iteration? '(lessp . args)
1862: '(not (greaterp . args)))))
1863: (push 'difference step)))
1864: (and (member (caddr step)
1865: #+Loop-Small-Floatp
1866: '(1 1.0 #.(and (loop-featurep Loop-Small-Floatp)
1867: (small-float 1)))
1868: #-Loop-Small-Floatp '(1 1.0))
1869: (rplacd (cdr (rplaca step (if (eq (car step) 'plus) 'add1 'sub1)))
1870: ()))
1871: (rplaca step (loop-typed-arith (car step) indexv-type))
1872: (setq step (list indexv step))
1873: (setq test (loop-typed-arith test indexv-type))
1874: (setq test (subst (list indexv endform) 'args test))
1875: (and stephack? (setq stephack? `(,variable? ,stephack?)))
1876: `(() ,step ,test ,stephack?
1877: () () ,test ,stephack?)))
1878:
1879:
1880: ; Although this function is no longer documented, the "SI:" is needed
1881: ; because compiled files may reference it that way (via
1882: ; DEFINE-LOOP-SEQUENCE-PATH).
1883: (defun si:loop-sequence-elements-path (path variable data-type
1884: prep-phrases inclusive?
1885: allowed-preps data)
1886: allowed-preps ; unused
1887: (let ((indexv (si:loop-named-variable 'index))
1888: (sequencev (si:loop-named-variable 'sequence))
1889: (fetchfun ()) (sizefun ()) (type ()) (default-var-type ())
1890: (crap `(for ,variable being the ,path)))
1891: (cond ((not (null inclusive?))
1892: (rplacd (cddr crap) `(,(cadar prep-phrases) and its ,path))
1893: (loop-simple-error "Can't step sequence inclusively" crap)))
1894: (setq fetchfun (car data)
1895: sizefun (car (setq data (cdr data)))
1896: type (car (setq data (cdr data)))
1897: default-var-type (cadr data))
1898: (list* () () ; dummy bindings and prologue
1899: (si:loop-sequencer
1900: indexv 'fixnum
1901: variable (or data-type default-var-type)
1902: sequencev type
1903: `(,fetchfun ,sequencev ,indexv) `(,sizefun ,sequencev)
1904: crap prep-phrases))))
1905:
1906:
1907: #+Run-on-PDP10
1908: (defun (define-loop-sequence-path macro) (x)
1909: `(define-loop-path ,(cadr x) si:loop-sequence-elements-path
1910: (of in from downfrom to downto below above by)
1911: . ,(cddr x)))
1912:
1913: #-Run-on-PDP10
1914: (defmacro define-loop-sequence-path (path-name-or-names fetchfun sizefun
1915: &optional sequence-type element-type)
1916: `(define-loop-path ,path-name-or-names
1917: si:loop-sequence-elements-path
1918: (of in from downfrom to downto below above by)
1919: ,fetchfun ,sizefun ,sequence-type ,element-type))
1920:
1921:
1922: ;;;; NIL interned-symbols path
1923:
1924: #+For-NIL
1925: (progn 'compile
1926: (defun loop-interned-symbols-path (path variable data-type prep-phrases
1927: inclusive? allowed-preps data
1928: &aux statev1 statev2 statev3
1929: (localp (car data)))
1930: allowed-preps ; unused
1931: (and inclusive? (loop-simple-error
1932: "INTERNED-SYMBOLS path doesn't work inclusively"
1933: variable))
1934: (and (not (null prep-phrases))
1935: (or (cdr prep-phrases)
1936: (not (si:loop-tmember (caar prep-phrases) '(in of))))
1937: (ferror () "Illegal prep phrase(s) in ~A path of ~A - ~A"
1938: path variable prep-phrases))
1939: (loop-make-variable variable () data-type)
1940: (loop-make-variable
1941: (setq statev1 (gensym))
1942: `(loop-find-package
1943: ,@(and prep-phrases `(,(cadar prep-phrases))))
1944: ())
1945: (loop-make-variable (setq statev2 (gensym)) () ())
1946: (loop-make-variable (setq statev3 (gensym)) () ())
1947: (push `(multiple-value (,statev1 ,statev2 ,statev3)
1948: (loop-initialize-mapatoms-state ,statev1 ',localp))
1949: loop-prologue)
1950: `(() () (multiple-value (() ,statev1 ,statev2 ,statev3)
1951: (,(if localp 'loop-test-and-step-mapatoms-local
1952: 'loop-test-and-step-mapatoms)
1953: ,statev1 ,statev2 ,statev3))
1954: (,variable (loop-get-mapatoms-symbol ,statev1 ,statev2 ,statev3)) () ()))
1955:
1956: (defun loop-find-package (&optional (pkg () pkgp))
1957: #+Run-in-Maclisp
1958: (if pkgp pkg obarray)
1959: #-Run-in-Maclisp
1960: (if pkgp (pkg-find-package pkg) package))
1961:
1962: (defun loop-find-package-translate (form)
1963: ; Note that we can only be compiling for nil-nil, so we only need
1964: ; to consider that. The run-in-maclisp conditionals in the functions
1965: ; are for the benefit of running interpreted code.
1966: (values (if (null (cdr form)) 'package `(pkg-find-package ,(cadr form))) 't))
1967:
1968: (putprop 'loop-find-package
1969: '(loop-find-package-translate)
1970: 'source-trans)
1971:
1972: #-Run-in-Maclisp
1973: (defun loop-initialize-mapatoms-state (pkg localp)
1974: (let* ((symtab (si:package-symbol-table pkg))
1975: (len (vector-length symtab)))
1976: (values pkg len (if localp symtab (cons (ncons pkg) ())))))
1977:
1978: #+Run-in-Maclisp
1979: (defun loop-initialize-mapatoms-state (ob ())
1980: (values ob (ncons nil) 511.))
1981:
1982: #-Run-in-Maclisp
1983: (defun loop-test-and-step-mapatoms (pkg index location &aux val)
1984: (prog (symtab)
1985: (setq symtab (si:package-symbol-table pkg))
1986: lp (cond ((-p (setq index (1-& index)))
1987: ;(do ((l (si:package-super-packages pkg) (cdr l)))
1988: ; ((null l) (cdr location))
1989: ; (or (memq (car l) (car location))
1990: ; (memq (car l) (cdr location))
1991: ; (rplacd location (cons (car l) (cdr location)))))
1992: (let ((p (si:package-super-package pkg)))
1993: (or (memq p (car location))
1994: (memq p (cdr location))
1995: (rplacd location (cons p (cdr location)))))
1996: (or (cdr location) (return (setq val 't)))
1997: (rplacd location
1998: (prog1 (cddr location)
1999: (rplaca location
2000: (rplacd (cdr location)
2001: (car location)))))
2002: (setq pkg (caar location))
2003: (setq symtab (si:package-symbol-table pkg))
2004: (setq index (vector-length symtab))
2005: (go lp))
2006: ((symbolp (vref symtab index)) (return ()))
2007: ('t (go lp))))
2008: (values val pkg index location))
2009:
2010: #+Run-in-Maclisp
2011: (defun loop-test-and-step-mapatoms (ob list index)
2012: (loop-test-and-step-mapatoms-local ob list index))
2013:
2014: #-Run-in-Maclisp
2015: (defun loop-test-and-step-mapatoms-local (pkg index symtab &aux val)
2016: (prog ()
2017: lp (cond ((-p (setq index (1-& index))) (return (setq val 't)))
2018: ((symbolp (vref symtab index)) (return ()))
2019: ('t (go lp))))
2020: (values val pkg index symtab))
2021:
2022: #+Run-in-Maclisp
2023: (defun loop-test-and-step-mapatoms-local (ob list index &aux val)
2024: (declare (fixnum index))
2025: (prog ()
2026: lp (cond ((not (null (cdr list)))
2027: (rplaca list (cadr list))
2028: (rplacd list (cddr list))
2029: (return ()))
2030: ((minusp (setq index (1- index))) (return (setq val 't)))
2031: ('t ; If this is going to run in multics maclisp also the
2032: ; arraycall should be hacked to have type `obarray'.
2033: (rplacd list (arraycall t ob index))
2034: (go lp))))
2035: (values val ob list index))
2036:
2037: #-Run-in-Maclisp
2038: (defun loop-get-mapatoms-symbol (pkg index something-or-other)
2039: ;Note there is a potential bug/timing screw in here. We should be
2040: ; looking in the symbol-table saved initially, not the current one.
2041: ; There just isn't enough state saved (sigh).
2042: (declare (ignore something-or-other))
2043: (vref (si:package-symbol-table pkg) index))
2044:
2045: #+Run-in-Maclisp
2046: (defun loop-get-mapatoms-symbol (ob list index)
2047: (declare (ignore ob index))
2048: (car list))
2049:
2050: (and #+Run-in-Maclisp (status feature complr)
2051: (*expr loop-get-mapatoms-symbol
2052: loop-initialize-mapatoms-state
2053: loop-test-and-step-mapatoms
2054: loop-test-and-step-mapatoms-local))
2055: )
2056:
2057:
2058: ;;;; Maclisp interned-symbols path
2059:
2060: #+For-Maclisp
2061: (defun loop-interned-symbols-path (path variable data-type prep-phrases
2062: inclusive? allowed-preps data
2063: &aux indexv listv ob)
2064: allowed-preps data ; unused vars
2065: (and inclusive? (loop-simple-error
2066: "INTERNED-SYMBOLS path doesn't work inclusively"
2067: variable))
2068: (and (not (null prep-phrases))
2069: (or (cdr prep-phrases)
2070: (not (si:loop-tmember (caar prep-phrases) '(in of))))
2071: (loop-simple-error
2072: "Illegal prep phrase(s) in INTERNED-SYMBOLS LOOP path"
2073: (list* variable 'being path prep-phrases)))
2074: (loop-make-variable variable () data-type)
2075: (loop-make-variable
2076: (setq ob (gensym)) (if prep-phrases (cadar prep-phrases) 'obarray) ())
2077: ; Multics lisp does not store single-char-obs in the obarray buckets.
2078: ; Thus, we need to iterate over the portion of the obarray
2079: ; containing them also. (511. = (ascii 0))
2080: (loop-make-variable
2081: (setq indexv (gensym)) #+Multics 639. #-Multics 511. 'fixnum)
2082: (loop-make-variable (setq listv (gensym)) () ())
2083: `(() ()
2084: (and #-Multics (null ,listv)
2085: #+Multics (or (> ,indexv 510.) (null ,listv))
2086: (prog ()
2087: lp (cond ((minusp (setq ,indexv (1- ,indexv))) (return t))
2088: ((setq ,listv (arraycall ; The following is the kind of
2089: ; gratuity that pisses me off:
2090: #+Multics obarray #-Multics t
2091: ,ob ,indexv))
2092: (return ()))
2093: ((go lp)))))
2094: (,variable
2095: #+Multics (cond ((> ,indexv 510.) ,listv)
2096: (t (prog2 () (car ,listv) (setq ,listv (cdr ,listv)))))
2097: #-Multics (car ,listv))
2098: ()
2099: #+Multics () #-Multics (,listv (cdr ,listv))))
2100:
2101:
2102: ;;;; Lispm interned-symbols path
2103:
2104: #+Lispm
2105: (progn 'compile
2106:
2107: (defun loop-interned-symbols-path (path variable data-type prep-phrases
2108: inclusive? allowed-preps data
2109: &aux statev1 statev2 statev3
2110: (localp (car data)))
2111: path data-type allowed-preps ; unused vars
2112: (and inclusive? (loop-simple-error
2113: "INTERNED-SYMBOLS path doesn't work inclusively"
2114: variable))
2115: (and (not (null prep-phrases))
2116: (or (cdr prep-phrases)
2117: (not (si:loop-tmember (caar prep-phrases) '(in of))))
2118: (ferror () "Illegal prep phrase(s) in ~A path of ~A - ~A"
2119: path variable prep-phrases))
2120: (loop-make-variable variable () data-type)
2121: (loop-make-variable
2122: (setq statev1 (gensym))
2123: (if prep-phrases `(pkg-find-package ,(cadar prep-phrases)) 'package)
2124: ())
2125: (loop-make-variable (setq statev2 (gensym)) () ())
2126: (loop-make-variable (setq statev3 (gensym)) () ())
2127: (push `(multiple-value (,statev1 ,statev2 ,statev3)
2128: (loop-initialize-mapatoms-state ,statev1 ,localp))
2129: loop-prologue)
2130: `(() () (multiple-value (nil ,statev1 ,statev2 ,statev3)
2131: (,(if localp 'loop-test-and-step-mapatoms-local
2132: 'loop-test-and-step-mapatoms)
2133: ,statev1 ,statev2 ,statev3))
2134: (,variable (loop-get-mapatoms-symbol ,statev1 ,statev2 ,statev3))
2135: () ()))
2136:
2137: (defun loop-initialize-mapatoms-state (pkg localp)
2138: ; Return the initial values of the three state variables.
2139: ; This scheme uses them to be:
2140: ; (1) Index into the package (decremented as we go)
2141: ; (2) Temporary (to hold the symbol)
2142: ; (3) the package
2143: localp ; ignored
2144: (prog ()
2145: (return (array-dimension-n 2 pkg) () pkg)))
2146:
2147: (defun loop-test-and-step-mapatoms (index temp pkg)
2148: temp ; ignored
2149: (prog ()
2150: lp (cond ((< (setq index (1- index)) 0)
2151: (cond ((setq pkg (pkg-super-package pkg))
2152: (setq index (array-dimension-n 2 pkg))
2153: (go lp))
2154: (t (return t))))
2155: ((numberp (ar-2 pkg 0 index))
2156: (return nil index (ar-2 pkg 1 index) pkg))
2157: (t (go lp)))))
2158:
2159: (defun loop-test-and-step-mapatoms-local (index temp pkg)
2160: temp ; ignored
2161: (prog ()
2162: lp (cond ((minusp (setq index (1- index))) (return t))
2163: ((numberp (ar-2 pkg 0 index))
2164: (return () index (ar-2 pkg 1 index) pkg))
2165: (t (go lp)))))
2166:
2167: (defun loop-get-mapatoms-symbol (index temp pkg)
2168: index pkg ; ignored
2169: temp)
2170: )
2171:
2172: ; We don't want these defined in the compilation environment because
2173: ; the appropriate environment hasn't been set up. So, we just bootstrap
2174: ; them up.
2175: (mapc '(lambda (x)
2176: (mapc '(lambda (y)
2177: (setq loop-path-keyword-alist
2178: (cons (cons y (cdr x))
2179: (delq (si:loop-tassoc
2180: y loop-path-keyword-alist)
2181: loop-path-keyword-alist))))
2182: (car x)))
2183: '(
2184: #+(or For-NIL For-Maclisp Lispm)
2185: ((interned-symbols interned-symbol)
2186: loop-interned-symbols-path (in))
2187: #+(or For-NIL Lispm)
2188: ((local-interned-symbols local-interned-symbol)
2189: loop-interned-symbols-path (in) t)
2190: ))
2191:
2192: #-Multics ; none defined yet
2193: (mapc '(lambda (x)
2194: (mapc '(lambda (y)
2195: (setq loop-path-keyword-alist
2196: (cons `(,y si:loop-sequence-elements-path
2197: (of in from downfrom to downto below above by)
2198: . ,(cdr x))
2199: (delq (si:loop-tassoc
2200: y loop-path-keyword-alist)
2201: loop-path-keyword-alist))))
2202: (car x)))
2203: '(#+Lispm
2204: ((array-element array-elements) aref array-active-length)
2205: ; These NIL guys are set up by NILAID in the PDP10 version but no one
2206: ; sets them up on the VAX. Anyway redundancy won't hurt unless i
2207: ; break something.
2208: #+(and For-NIL (not Run-in-Maclisp))
2209: ((vector-element vector-elements) vref vector-length vector)
2210: #+(and For-NIL (not Run-in-Maclisp))
2211: ((bit bits) bit bits-length bits fixnum)
2212: #+(and For-NIL (not Run-in-Maclisp))
2213: ((character characters) char string-length string character)
2214: )
2215: )
2216:
2217: ; Sigh. (c.f. loop-featurep, note macro-expansion lossage.)
2218: ; Note that we end up doing both in the PDP10 NIL version.
2219: #+(or (not For-NIL) Run-in-Maclisp)
2220: (or (status feature loop) (sstatus feature loop))
2221: #+For-NIL
2222: (set-feature 'loop 'local)
2223:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.