;Loop macro blathering.
;
; This doc is totally wrong. Complete documentation (nice looking
; hardcopy) is available from GSB, or from ML:LSBDOC;LPDOC (which
; needs to be run through BOLIO).
;
;This is intended to be a cleaned-up version of PSZ's FOR package
;which is a cleaned-up version of the Interlisp CLisp FOR package.
;Note that unlike those crocks, the order of evaluation is the
;same as the textual order of the code, always.
;
;The form is introduced by the word LOOP followed by a series of clauses,
;each of which is introduced by a keyword which however need not be
;in any particular package. Certain keywords may be made "major"
;which means they are global and macros themselves, so you could put
;them at the front of the form and omit the initial "LOOP".
;
;Each clause can generate:
;
; Variables local to the loop.
;
; Prologue Code.
;
; Main Code.
;
; Epilogue Code.
;
;Within each of the three code sections, code is always executed strictly
;in the order that the clauses were written by the user. For parallel assignments
;and such there are special syntaxes within a clause. The prologue is executed
;once to set up. The main code is executed several times as the loop. The epilogue
;is executed once after the loop terminates.
;
;The term expression means any Lisp form. The term expression(s) means any number
;of Lisp forms, where only the first may be atomic. It stops at the first atom
;after the first form.
;
;The following clauses exist:
;
;Prologue:
; INITIALLY expression(s)
; This explicitly inserts code into the prologue. More commonly
; code comes from variable initializations.
;
;Epilogue:
; FINALLY expression(s)
; This is the only way to explicitly insert code into the epilogue.
;
;Side effects:
; DO expression(s)
; The expressions are evaluated. This is how you make a "body".
; DOING is synonymous with DO.
;
;Return values:
; RETURN expression(s)
; The last expression is returned immediately as the value of the form.
; This is equivalent to DO (RETURN expression) which you will
; need to use if you want to return multiple values.
; COLLECT expression(s)
; The return value of the form will be a list (unless over-ridden
; with a RETURN). The list is formed out of the values of the
; last expression.
; COLLECTING is synonymous with COLLECT.
; APPEND (or APPENDING) and NCONC (or NCONCING) can be used
; in place of COLLECT, forming the list in the appropriate ways.
; COUNT expression(s)
; The return value of the form will be the number of times the
; value of the last expression was non-NIL.
; SUM expression(s)
; The return value of the form will be the arithmetic sum of
; the values of the last expression.
; The following are a bit wierd syntactically, but Interlisp has them
; so they must be good.
; ALWAYS expression(s)
; The return value will be T if the last expression is true on
; every iteration, NIL otherwise.
; NEVER expressions(s)
; The return value will be T if the last expression is false on
; every iteration, NIL otherwise.
; THEREIS expression(s)
; This is wierd, I'm not sure what it really does.
; You probably want WHEN (NUMBERP X) RETURN X
; or maybe WHEN expression RETURN IT
;
;Conditionals: (these all affect only the main code)
;
; WHILE expression
; The loop terminates at this point if expression is false.
; UNTIL expression
; The loop terminates at this point if expression is true.
; WHEN expression clause
; Clause is performed only if expression is true.
; This affects only the main-code portion of a clause
; such as COLLECT. Use with FOR is a little unclear.
; IF is synonymous with WHEN.
; WHEN expression RETURN IT (also COLLECT IT, COUNT IT, SUM IT)
; This is a special case, the value of expression is returned if non-NIL.
; This works by generating a temporary variable to hold
; the value of the expression.
; UNLESS expression clause
; Clause is performed only if expression is false.
;
;Variables and iterations: (this is the hairy part)
;
; WITH variable = expression {AND variable = expression}...
; The variable is set to the expression in the prologue.
; If several variables are chained together with AND
; the setq's happen in parallel. Note that all variables
; are bound before any expressions are evaluated (unlike DO).
;
; FOR variable = expression {AND variable = expression}...
; At this point in the main code the variable is set to the expression.
; Equivalent to DO (PSETQ variable expression variable expression...)
; except that the variables are bound local to the loop.
;
; FOR variable FROM expression TO expression {BY expression}
; Numeric iteration. BY defaults to 1.
; BY and TO may be in either order.
; If you say DOWNTO instead of TO, BY defaults to -1 and
; the end-test is reversed.
; If you say BELOW instead of TO or ABOVE instead of DOWNTO
; the iteration stops before the end-value instead of after.
; The expressions are evaluated in the prologue then the
; variable takes on its next value at this point in the loop;
; hair is required to win the first time around if this FOR is
; not the first thing in the main code.
; FOR variable IN expression
; Iteration down members of a list.
; FOR variable ON expression
; Iteration down tails of a list.
; FOR variable IN/ON expression BY expression
; This is an Interlisp crock which looks useful.
; FOR var ON list BY expression[var]
; is the same as FOR var = list THEN expression[var]
; FOR var IN list BY expression[var]
; is similar except that var gets tails of the list
; and, kludgiferously, the internal tail-variable
; is substituted for var in expression.
; FOR variable = expression THEN expression
; General DO-type iteration.
; Note that all the different types of FOR clauses can be tied together
; with AND to achieve parallel assignment. Is this worthwhile?
; [It's only implemented for = mode.]
; AS is synonymous with FOR.
;
; FOR variable BEING expression(s) AND ITS pathname
; FOR variable BEING expression(s) AND ITS a-r
; FOR variable BEING {EACH} pathname {OF expression(s)}
; FOR variable BEING {EACH} a-r {OF expression(s)}
; Programmable iteration facility. Each pathname has a
; function associated with it, on LOOP-PATH-KEYWORD-ALIST; the
; alist has entries of the form (pathname function prep-list).
; prep-list is a list of allowed prepositions; after either of
; the above formats is parsed, then pairs of (preposition expression)
; are collected, while preposition is in prep-list. The expression
; may be a progn if there are multiple prepositions before the next
; keyword. The function is then called with arguments of:
; pathnname variable prep-phrases inclusive? prep-list
; Prep-phrases is the list of pairs collected, in order. Inclusive?
; is T for the first format, NIL otherwise; it says that the init
; value of the form takes on expression. For the first format, the
; list (OF expression) is pushed onto the fromt of the prep-phrases.
; In the above examples, a-r is a form to be evaluated to get an
; attachment-relationship. In this case, the pathname is taken as
; being ATTACHMENTS, and a-r is passed in by being treated as if it
; had been used with the preposition IN. The function should return
; a list of the form (bindings init-form step-form end-test); bindings
; are stuffed onto loop-variables, init-form is initialization code,
; step-form is step-code, and end-test tells whether or not to exit.
;
;Declarations? Not needed by Lisp machine. For Maclisp these will be done
;by a reserved word in front of the variable name as in PSZ's macro.
;
;The implementation is as a PROG. No initial values are given for the
;PROG-variables. PROG1 is used for parallel assignment.
;
;The iterating forms of FOR present a special problem. The problem is that
;you must do everything in the order that it was written by the user, but the
;FOR-variable gets its value in a different way in the first iteration than
;in the subsequent iterations. Note that the end-tests created by FOR have
;to be done in the appropriate order, since otherwise the next clause might get
;an error.
;
;The most general way is to introduce a flag, !FIRST-TIME, and compile the
;clause "FOR var = first TO last" as "INITIALLY (SETQ var first)
;WHEN (NOT !FIRST-TIME) DO (SETQ var (1+ var)) WHILE (<= var last)".
;However we try to optimize this by recognizing a special case:
;The special case is recognized where all FOR clauses are at the front of
;the main code; in this case if there is only one its stepping and
;endtest are moved to the end, and a jump to the endtest put at the
;front. If there are more than one their stepping and endtests are moved
;to the end, with duplicate endtests at the front except for the last
;which doesn't need a duplicate endtest. If FORs are embedded in the
;main code it can only be implemented by either a first-time flag or
;starting the iteration variable at a special value (initial minus step
;in the numeric iteration case). This could probably just be regarded as
;an error. The important thing is that it never does anything out of
;order.