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