<div>I've made the following changes to PS LOOP and pushed them on a branch</div><div>called "loop" pending the fixing of the pretty-printer as we discussed</div><div>a couple weeks ago.</div><div><br></div><div>

These changes capture some idioms that were common in our code. They</div><div>deviate from CL's LOOP (I could not bring myself to implement "BEING</div><div>THE HASH-KEYS OF") in ways that are appropriate for JS semantics. Since</div>

<div>PS LOOP was not fully compatible with CL's LOOP anyway, this is not much</div><div>of a loss.</div><div><br></div><div>(1) Added a FOR..OF clause that iterates through the keys of a JS object.</div><div>This translates to JS's "for k in obj" loops and corresponds roughly</div>

<div>to "loop for k being the hash-keys of" in CL.</div><div><br></div><div>  (ps (loop :for k :of obj :do (foo k)))</div><div><br></div><div>  "for (var k in obj) {</div><div>      foo(k);</div><div>  };"</div>

<div><br></div><div>To bind both key and value, you specify a pair. (This is an icky bit</div><div>of syntax but it feels like the least icky option of the ones I'm</div><div>aware of.)</div><div><br></div><div>  (ps (loop :for (k v) :of obj :do (foo k v)))</div>

<div><br></div><div>  "for (var k in obj) {</div><div>      var v = obj[k];</div><div>      foo(k, v);</div><div>  };"</div><div><br></div><div>Destructuring works on the value position just like they do everywhere</div>

<div>else, so you can unpack an array. (Note that in this example the key</div><div>variable isn't needed so we can put NIL in there.)</div><div><br></div><div>  (ps (loop :for (nil (v1 v2)) :of obj :do (foo v1 v2)))</div>

<div><br></div><div>  "for (var _js23095 in obj) {</div><div>      var _js23096 = obj[_js23095];</div><div>      var v1 = _js23096[0];</div><div>      var v2 = _js23096[1];</div><div>      foo(v1, v2);</div><div>  };"</div>

<div><br></div><div>... or named properties (by using keywords):</div><div><br></div><div>  (ps (loop :for (nil (:hello :world)) :of obj :do (foo hello world)))</div><div><br></div><div>  "for (var _js23097 in obj) {</div>

<div>      var var23099 = obj[_js23097];</div><div>      var hello23101 = var23099.hello;</div><div>      var world23102 = var23099.world;</div><div>      foo(hello23101, world23102);</div><div>  };"</div><div><br></div>

<div>Side note: To get the scoping right for parallel loop clauses is</div><div>tricky because LOOP orders things "step test step test" where JS's FOR</div><div>does "step step test test", meaning that the second step will be</div>

<div>evaluated even if the first test fails. It got trickier with the</div><div>introduction of FOR..OF, so I adopted a simpler implementation that</div><div>has some advantages (much tighter generated loop code) but also some</div>

<div>disadvantages: (a) it was a pain to support :INITIALLY clauses so I</div><div>dropped them (I'd be surprised if anyone ever used it), and (b)</div><div>complex loops sometimes require an extra temporary variable to track</div>

<div>whether the loop is on its first iteration or not.</div><div><br></div><div>(2) There is now a MAP..TO clause that works like COLLECT only instead</div><div>of building an array, builds an object mapping keys to values:</div>

<div><br></div><div>  (ps (loop :for str :in strs :map str :to (length str)))</div><div><br></div><div>  "(function () {</div><div>      var _js23109 = strs.length;</div><div>      var map23110 = {  };</div><div>      for (var _js23108 = 0; _js23108 < _js23109; _js23108 += 1) {</div>

<div>          var str = strs[_js23108];</div><div>          map23110[str] = str.length;</div><div>      };</div><div>      return map23110;</div><div>  })();"</div><div><br></div><div>(3) In FOR..ON, a BY term can now be an integer. For example, you can</div>

<div>say "by 2" instead of "by #'cddr" which makes little sense for JS arrays:</div><div><br></div><div>  (ps (loop :for (key val) :on pairs :by 2 :do (foo key val)))</div><div><br></div><div>  "for (var _js23094 = pairs; _js23094.length > 0; _js23094 = _js23094.slice(2)) {</div>

<div>      var key = _js23094[0];</div><div>      var val = _js23094[1];</div><div>      foo(key, val);</div><div>  };"</div><div><br></div><div>If BY doesn't get a number, it assumes it got a function:</div><div>

<br></div><div>  (ps (loop :for (key val) :on pairs :by blah :do (foo key val)))</div><div><br></div><div>  "for (var _js23112 = pairs; _js23112.length > 0; _js23112 = blah(_js23112)) {</div><div>      var key = _js23112[0];</div>

<div>      var val = _js23112[1];</div><div>      foo(key, val);</div><div>  };"</div><div><br></div><div>Daniel</div>