For some reason I thought for and while were both implemented using loop. Turns out only for is so that probably led to some confusion. I guess it would make sense to implement while with xloop. I do like the idea of moving the current for to up. What I meant originally was to replace the uses of loop with xloop.
I have to agree with you that the current loop should definitely allow variable declarations as it should be the general case of up/down. The remaining cases should be covered by while (unless we want to put the update and the test in the same place which I see no reason for).
Just a question about some of your code. How is while not infinitely recursive? Are macros substituted at runtime in wart?
Edit: I just realized that we can implement the current loop in terms of xloop.
I've made a subtle change to up and down -- following C, they are no longer inclusive of their second bound. Before:
arc> (up i 0 3 prn.i)
0
1
2
3
After:
arc> (up i 0 3 prn.i)
0
1
2
I think I've caught all their callers and corrected them, but there might be stray bugs in lib/math.arc. (It's amazing how much cleaner math.arc has gotten with the saner, C-inspired bounds.)
(mac drain (expr (o eos nil))
(w/uniq (gacc gres)
`(accum ,gacc
(whiler ,gres ,expr ,eos
(,gacc ,gres)))))
I'm still concerned about changing the semantics of loop and for, especially with the prospect of updates from pg. Fortunately it's easy to roll back these changes :)
A final, more speculative change: for loops are named, so you can break and continue multiple loops at once using the name of the loop variable. Both these fragments have identical output:
(up i 0 3
(up j 0 3
(if (> j i) (break))
(prn i " " j)))
(up i 0 3
(up j 0 3
(if (> j i) (continue-i))
(prn i " " j)))