|
|
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.