| OLD | NEW | 
| (Empty) |  | 
 |    1 // Copyright 2013 the V8 project authors. All rights reserved. | 
 |    2 // Redistribution and use in source and binary forms, with or without | 
 |    3 // modification, are permitted provided that the following conditions are | 
 |    4 // met: | 
 |    5 // | 
 |    6 //     * Redistributions of source code must retain the above copyright | 
 |    7 //       notice, this list of conditions and the following disclaimer. | 
 |    8 //     * Redistributions in binary form must reproduce the above | 
 |    9 //       copyright notice, this list of conditions and the following | 
 |   10 //       disclaimer in the documentation and/or other materials provided | 
 |   11 //       with the distribution. | 
 |   12 //     * Neither the name of Google Inc. nor the names of its | 
 |   13 //       contributors may be used to endorse or promote products derived | 
 |   14 //       from this software without specific prior written permission. | 
 |   15 // | 
 |   16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
 |   17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
 |   18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
 |   19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
 |   20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
 |   21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
 |   22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
 |   23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
 |   24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
 |   25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
 |   26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
 |   27  | 
 |   28 // Flags: --harmony | 
 |   29  | 
 |   30 // Test for-of semantics. | 
 |   31  | 
 |   32 "use strict"; | 
 |   33  | 
 |   34  | 
 |   35 // First, some helpers. | 
 |   36  | 
 |   37 function* values() { | 
 |   38   for (var i = 0; i < arguments.length; i++) { | 
 |   39     yield arguments[i]; | 
 |   40   } | 
 |   41 } | 
 |   42  | 
 |   43 function integers_until(max) { | 
 |   44   function next() { | 
 |   45     var ret = { value: this.n, done: this.n == max }; | 
 |   46     this.n++; | 
 |   47     return ret; | 
 |   48   } | 
 |   49   return { next: next, n: 0 } | 
 |   50 } | 
 |   51  | 
 |   52 function results(results) { | 
 |   53   var i = 0; | 
 |   54   function next() { | 
 |   55     return results[i++]; | 
 |   56   } | 
 |   57   return { next: next } | 
 |   58 } | 
 |   59  | 
 |   60 function* integers_from(n) { | 
 |   61   while (1) yield n++; | 
 |   62 } | 
 |   63  | 
 |   64 // A destructive append. | 
 |   65 function append(x, tail) { | 
 |   66   tail[tail.length] = x; | 
 |   67   return tail; | 
 |   68 } | 
 |   69  | 
 |   70 function sum(x, tail) { | 
 |   71   return x + tail; | 
 |   72 } | 
 |   73  | 
 |   74 function fold(cons, seed, iter) { | 
 |   75   for (var x of iter) { | 
 |   76     seed = cons(x, seed); | 
 |   77   } | 
 |   78   return seed; | 
 |   79 } | 
 |   80  | 
 |   81 function* take(iter, n) { | 
 |   82   if (n == 0) return; | 
 |   83   for (let x of iter) { | 
 |   84     yield x; | 
 |   85     if (--n == 0) break; | 
 |   86   } | 
 |   87 } | 
 |   88  | 
 |   89 function nth(iter, n) { | 
 |   90   for (let x of iter) { | 
 |   91     if (n-- == 0) return x; | 
 |   92   } | 
 |   93   throw "unreachable"; | 
 |   94 } | 
 |   95  | 
 |   96 function* skip_every(iter, n) { | 
 |   97   var i = 0; | 
 |   98   for (let x of iter) { | 
 |   99     if (++i % n == 0) continue; | 
 |  100     yield x; | 
 |  101   } | 
 |  102 } | 
 |  103  | 
 |  104 function* iter_map(iter, f) { | 
 |  105   for (var x of iter) { | 
 |  106     yield f(x); | 
 |  107   } | 
 |  108 } | 
 |  109 function nested_fold(cons, seed, iter) { | 
 |  110   var visited = [] | 
 |  111   for (let x of iter) { | 
 |  112     for (let y of x) { | 
 |  113       seed = cons(y, seed); | 
 |  114     } | 
 |  115   } | 
 |  116   return seed; | 
 |  117 } | 
 |  118  | 
 |  119 function* unreachable(iter) { | 
 |  120   for (let x of iter) { | 
 |  121     throw "not reached"; | 
 |  122   } | 
 |  123 } | 
 |  124  | 
 |  125 function one_time_getter(o, prop, val) { | 
 |  126   function set_never() { throw "unreachable"; } | 
 |  127   var gotten = false; | 
 |  128   function get_once() { | 
 |  129     if (gotten) throw "got twice"; | 
 |  130     gotten = true; | 
 |  131     return val; | 
 |  132   } | 
 |  133   Object.defineProperty(o, prop, {get: get_once, set: set_never}) | 
 |  134   return o; | 
 |  135 } | 
 |  136  | 
 |  137 function never_getter(o, prop) { | 
 |  138   function never() { throw "unreachable"; } | 
 |  139   Object.defineProperty(o, prop, {get: never, set: never}) | 
 |  140   return o; | 
 |  141 } | 
 |  142  | 
 |  143 function remove_next_after(iter, n) { | 
 |  144   function next() { | 
 |  145     if (n-- == 0) delete this.next; | 
 |  146     return iter.next(); | 
 |  147   } | 
 |  148   return { next: next } | 
 |  149 } | 
 |  150  | 
 |  151 function poison_next_after(iter, n) { | 
 |  152   function next() { | 
 |  153     return iter.next(); | 
 |  154   } | 
 |  155   function next_getter() { | 
 |  156     if (n-- < 0) | 
 |  157       throw "poisoned"; | 
 |  158     return next; | 
 |  159   } | 
 |  160   var o = {}; | 
 |  161   Object.defineProperty(o, 'next', { get: next_getter }); | 
 |  162   return o; | 
 |  163 } | 
 |  164  | 
 |  165 // Now, the tests. | 
 |  166  | 
 |  167 // Non-generator iterators. | 
 |  168 assertEquals(45, fold(sum, 0, integers_until(10))); | 
 |  169 // Generator iterators. | 
 |  170 assertEquals([1, 2, 3], fold(append, [], values(1, 2, 3))); | 
 |  171 // Break. | 
 |  172 assertEquals(45, fold(sum, 0, take(integers_from(0), 10))); | 
 |  173 // Continue. | 
 |  174 assertEquals(90, fold(sum, 0, take(skip_every(integers_from(0), 2), 10))); | 
 |  175 // Return. | 
 |  176 assertEquals(10, nth(integers_from(0), 10)); | 
 |  177 // Nested for-of. | 
 |  178 assertEquals([0, 0, 1, 0, 1, 2, 0, 1, 2, 3], | 
 |  179              nested_fold(append, | 
 |  180                          [], | 
 |  181                          iter_map(integers_until(5), integers_until))); | 
 |  182 // Result objects with sparse fields. | 
 |  183 assertEquals([undefined, 1, 2, 3], | 
 |  184              fold(append, [], | 
 |  185                   results([{ done: false }, | 
 |  186                            { value: 1, done: false }, | 
 |  187                            // A missing "done" is the same as undefined, which | 
 |  188                            // is false. | 
 |  189                            { value: 2 }, | 
 |  190                            // Not done. | 
 |  191                            { value: 3, done: 0 }, | 
 |  192                            // Done. | 
 |  193                            { value: 4, done: 42 }]))); | 
 |  194 // Results that are not objects. | 
 |  195 assertEquals([undefined, undefined, undefined], | 
 |  196              fold(append, [], | 
 |  197                   results([10, "foo", /qux/, { value: 37, done: true }]))); | 
 |  198 // Getters (shudder). | 
 |  199 assertEquals([1, 2], | 
 |  200              fold(append, [], | 
 |  201                   results([one_time_getter({ value: 1 }, 'done', false), | 
 |  202                            one_time_getter({ done: false }, 'value', 2), | 
 |  203                            { value: 37, done: true }, | 
 |  204                            never_getter(never_getter({}, 'done'), 'value')]))); | 
 |  205  | 
 |  206 // Null and undefined do not cause an error. | 
 |  207 assertEquals(0, fold(sum, 0, unreachable(null))); | 
 |  208 assertEquals(0, fold(sum, 0, unreachable(undefined))); | 
 |  209  | 
 |  210 // Other non-iterators do cause an error. | 
 |  211 assertThrows('fold(sum, 0, unreachable({}))', TypeError); | 
 |  212 assertThrows('fold(sum, 0, unreachable("foo"))', TypeError); | 
 |  213 assertThrows('fold(sum, 0, unreachable(37))', TypeError); | 
 |  214  | 
 |  215 // "next" is looked up each time. | 
 |  216 assertThrows('fold(sum, 0, remove_next_after(integers_until(10), 5))', | 
 |  217              TypeError); | 
 |  218 // It is not called at any other time. | 
 |  219 assertEquals(45, | 
 |  220              fold(sum, 0, remove_next_after(integers_until(10), 10))); | 
 |  221 // It is not looked up too many times. | 
 |  222 assertEquals(45, | 
 |  223              fold(sum, 0, poison_next_after(integers_until(10), 10))); | 
 |  224  | 
 |  225 function labelled_continue(iter) { | 
 |  226   var n = 0; | 
 |  227 outer: | 
 |  228   while (true) { | 
 |  229     n++; | 
 |  230     for (var x of iter) continue outer; | 
 |  231     break; | 
 |  232   } | 
 |  233   return n; | 
 |  234 } | 
 |  235 assertEquals(11, labelled_continue(integers_until(10))); | 
 |  236  | 
 |  237 function labelled_break(iter) { | 
 |  238   var n = 0; | 
 |  239 outer: | 
 |  240   while (true) { | 
 |  241     n++; | 
 |  242     for (var x of iter) break outer; | 
 |  243   } | 
 |  244   return n; | 
 |  245 } | 
 |  246 assertEquals(1, labelled_break(integers_until(10))); | 
 |  247  | 
 |  248 // Test continue/break in catch. | 
 |  249 function catch_control(iter, k) { | 
 |  250   var n = 0; | 
 |  251   for (var x of iter) { | 
 |  252     try { | 
 |  253       return k(x); | 
 |  254     } catch (e) { | 
 |  255       if (e == "continue") continue; | 
 |  256       else if (e == "break") break; | 
 |  257       else throw e; | 
 |  258     } | 
 |  259   } while (false); | 
 |  260   return false; | 
 |  261 } | 
 |  262 assertEquals(false, | 
 |  263              catch_control(integers_until(10), | 
 |  264                            function() { throw "break" })); | 
 |  265 assertEquals(false, | 
 |  266              catch_control(integers_until(10), | 
 |  267                            function() { throw "continue" })); | 
 |  268 assertEquals(5, | 
 |  269              catch_control(integers_until(10), | 
 |  270                            function(x) { | 
 |  271                              if (x == 5) return x; | 
 |  272                              throw "continue"; | 
 |  273                            })); | 
 |  274  | 
 |  275 // Test continue/break in try. | 
 |  276 function try_control(iter, k) { | 
 |  277   var n = 0; | 
 |  278   for (var x of iter) { | 
 |  279     try { | 
 |  280       var e = k(x); | 
 |  281       if (e == "continue") continue; | 
 |  282       else if (e == "break") break; | 
 |  283       return e; | 
 |  284     } catch (e) { | 
 |  285       throw e; | 
 |  286     } | 
 |  287   } while (false); | 
 |  288   return false; | 
 |  289 } | 
 |  290 assertEquals(false, | 
 |  291              try_control(integers_until(10), | 
 |  292                          function() { return "break" })); | 
 |  293 assertEquals(false, | 
 |  294              try_control(integers_until(10), | 
 |  295                          function() { return "continue" })); | 
 |  296 assertEquals(5, | 
 |  297              try_control(integers_until(10), | 
 |  298                          function(x) { return (x == 5) ? x : "continue" })); | 
 |  299  | 
 |  300 // Proxy results, with getters. | 
 |  301 function transparent_proxy(x) { | 
 |  302   return Proxy.create({ | 
 |  303     get: function(receiver, name) { return x[name]; } | 
 |  304   }); | 
 |  305 } | 
 |  306 assertEquals([1, 2], | 
 |  307              fold(append, [], | 
 |  308                   results([one_time_getter({ value: 1 }, 'done', false), | 
 |  309                            one_time_getter({ done: false }, 'value', 2), | 
 |  310                            { value: 37, done: true }, | 
 |  311                            never_getter(never_getter({}, 'done'), 'value')] | 
 |  312                           .map(transparent_proxy)))); | 
 |  313  | 
 |  314 // Proxy iterators. | 
 |  315 function poison_proxy_after(x, n) { | 
 |  316   return Proxy.create({ | 
 |  317     get: function(receiver, name) { | 
 |  318       if (name == 'next' && n-- < 0) throw "unreachable"; | 
 |  319       return x[name]; | 
 |  320     }, | 
 |  321     // Needed for integers_until(10)'s this.n++. | 
 |  322     set: function(receiver, name, val) { | 
 |  323       return x[name] = val; | 
 |  324     } | 
 |  325   }); | 
 |  326 } | 
 |  327 assertEquals(45, fold(sum, 0, poison_proxy_after(integers_until(10), 10))); | 
| OLD | NEW |