• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Copyright 2015 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5// Flags: --harmony-do-expressions --allow-natives-syntax
6
7function returnValue(v) { return v; }
8function MyError() {}
9var global = this;
10
11function TestBasic() {
12  // Looping and lexical declarations
13  assertEquals(512, returnValue(do {
14    let n = 2;
15    for (let i = 0; i < 4; i++) n <<= 2;
16  }));
17
18  // Strings do the right thing
19  assertEquals("spooky halloween", returnValue(do {
20    "happy halloween".replace('happy', 'spooky');
21  }));
22
23  // Do expressions with no completion produce an undefined value
24  assertEquals(undefined, returnValue(do {}));
25  assertEquals(undefined, returnValue(do { var x = 99; }));
26  assertEquals(undefined, returnValue(do { function f() {}; }));
27  assertEquals(undefined, returnValue(do { let z = 33; }));
28
29  // Propagation of exception
30  assertThrows(function() {
31    (do {
32      throw new MyError();
33      "potatoes";
34    });
35  }, MyError);
36
37  assertThrows(function() {
38    return do {
39      throw new MyError();
40      "potatoes";
41    };
42  }, MyError);
43
44  // Return value within do-block overrides `return |do-expression|`
45  assertEquals("inner-return", (function() {
46    return "outer-return" + do {
47      return "inner-return";
48      "";
49    };
50  })());
51
52  var count = 0, n = 1;
53  // Breaking out |do-expression|
54  assertEquals(3, (function() {
55    for (var i = 0; i < 10; ++i) (count += 2 * do { if (i === 3) break; ++n });
56    return i;
57  })());
58  // (2 * 2) + (2 * 3) + (2 * 4)
59  assertEquals(18, count);
60
61  // Continue in |do-expression|
62  count = 0, n = 1;
63  assertEquals([1, 3, 5, 7, 9], (function() {
64    var values = [];
65    for (var i = 0; i < 10; ++i) {
66      count += 2 * (do {
67        if ((i & 1) === 0) continue;
68        values.push(i);
69        ++n;
70      }) + 1;
71    }
72    // (2*2) + 1 + (2*3) + 1 + (2*4) + 1 + (2*5) + 1 + (2*6) + 1
73    return values;
74  })());
75  assertEquals(count, 45);
76
77  assertThrows("(do { break; });", SyntaxError);
78  assertThrows("(do { continue; });", SyntaxError);
79
80  // Real-world use case for desugaring
81  var array = [1, 2, 3, 4, 5], iterable = [6, 7, 8,9];
82  assertEquals([1, 2, 3, 4, 5, 6, 7, 8, 9], do {
83    for (var element of iterable) array.push(element);
84    array;
85  });
86
87  // Nested do-expressions
88  assertEquals(125, do { (do { (do { 5 * 5 * 5 }) }) });
89
90  // Directives are not honoured
91  (do {
92    "use strict";
93    foo = 80;
94    assertEquals(foo, 80);
95  });
96
97  // Non-empty operand stack testing
98  var O = {
99    method1() {
100      let x = 256;
101      return x + do {
102        for (var i = 0; i < 4; ++i) x += i;
103      } + 17;
104    },
105    method2() {
106      let x = 256;
107      this.reset();
108      return x + do {
109        for (var i = 0; i < this.length(); ++i) x += this.index() * 2;
110      };
111    },
112    _index: 0,
113    index() {
114      return ++this._index;
115    },
116    _length: 4,
117    length() { return this._length; },
118    reset() { this._index = 0; }
119  };
120  assertEquals(535, O["method" + do { 1 } + ""]());
121  assertEquals(532, O["method" + do { ({ valueOf() { return "2"; } }); }]());
122  assertEquals(532, O[
123      do { let s = ""; for (let c of "method") s += c; } + "2"]());
124}
125TestBasic();
126
127
128function TestDeoptimization1() {
129  function f(v) {
130    return 88 + do {
131      v.a * v.b + v.c;
132    };
133  }
134
135  var o1 = {};
136  o1.a = 10;
137  o1.b = 5;
138  o1.c = 50;
139
140  var o2 = {};
141  o2.c = 100;
142  o2.a = 10;
143  o2.b = 10;
144
145  assertEquals(188, f(o1));
146  assertEquals(188, f(o1));
147  %OptimizeFunctionOnNextCall(f);
148  assertEquals(188, f(o1));
149  assertOptimized(f);
150  assertEquals(288, f(o2));
151  assertUnoptimized(f);
152  assertEquals(288, f(o2));
153}
154TestDeoptimization1();
155
156
157function TestInParameterInitializers() {
158  var first_name = "George";
159  var last_name = "Jetson";
160  function fn1(name = do { first_name + " " + last_name }) {
161    return name;
162  }
163  assertEquals("George Jetson", fn1());
164
165  var _items = [1, 2, 3, NaN, 4, 5];
166  function fn2(items = do {
167    let items = [];
168    for (var el of _items) {
169      if (el !== el) {
170        items;
171        break;
172      }
173      items.push(el), items;
174    }
175  }) {
176    return items;
177  }
178  assertEquals([1, 2, 3], fn2());
179
180  function thrower() { throw new MyError(); }
181  function fn3(exception = do {  try { thrower(); } catch (e) { e } }) {
182    return exception;
183  }
184  assertDoesNotThrow(fn3);
185  assertInstanceof(fn3(), MyError);
186
187  function fn4(exception = do { throw new MyError() }) {}
188  function catcher(fn) {
189    try {
190      fn();
191      assertUnreachable("fn() initializer should throw");
192    } catch (e) {
193      assertInstanceof(e, MyError);
194    }
195  }
196  catcher(fn4);
197}
198TestInParameterInitializers();
199
200
201function TestWithEval() {
202  (function sloppy1() {
203    assertEquals(do { eval("var x = 5"), x }, 5);
204    assertEquals(x, 5);
205  })();
206
207  assertThrows(function strict1() {
208    "use strict";
209    (do { eval("var x = 5"), x }, 5);
210  }, ReferenceError);
211
212  assertThrows(function strict2() {
213    (do { eval("'use strict'; var x = 5"), x }, 5);
214  }, ReferenceError);
215}
216TestWithEval();
217
218
219function TestHoisting() {
220  (do { var a = 1; });
221  assertEquals(a, 1);
222  assertEquals(global.a, undefined);
223
224  (do {
225    for (let it of [1, 2, 3, 4, 5]) {
226      var b = it;
227    }
228  });
229  assertEquals(b, 5);
230  assertEquals(global.b, undefined);
231
232  {
233    let x = 1
234
235    // TODO(caitp): ensure VariableStatements in |do-expressions| in parameter
236    // initializers, are evaluated in the same VariableEnvironment as they would
237    // be for eval().
238    // function f1(a = do { var x = 2 }, b = x) { return b }
239    // assertEquals(1, f1())
240
241    // function f2(a = x, b = do { var x = 2 }) { return a }
242    // assertEquals(1, f2())
243
244    function f3({a = do { var x = 2 }, b = x}) { return b }
245    assertEquals(2, f3({}))
246
247    function f4({a = x, b = do { var x = 2 }}) { return b }
248    assertEquals(undefined, f4({}))
249
250    function f5(a = do { var y = 0 }) {}
251    assertThrows(() => y, ReferenceError)
252  }
253
254  // TODO(caitp): Always block-scope function declarations in |do| expressions
255  //(do {
256  //  assertEquals(true, inner_func());
257  //  function inner_func() { return true; }
258  //});
259  //assertThrows(function() { return innerFunc(); }, ReferenceError);
260}
261TestHoisting();
262
263
264// v8:4661
265
266function tryFinallySimple() { (do { try {} finally {} }); }
267tryFinallySimple();
268tryFinallySimple();
269tryFinallySimple();
270tryFinallySimple();
271
272var finallyRanCount = 0;
273function tryFinallyDoExpr() {
274  return (do {
275    try {
276      throw "BOO";
277    } catch (e) {
278      "Caught: " + e + " (" + finallyRanCount + ")"
279    } finally {
280      ++finallyRanCount;
281    }
282  });
283}
284assertEquals("Caught: BOO (0)", tryFinallyDoExpr());
285assertEquals(1, finallyRanCount);
286assertEquals("Caught: BOO (1)", tryFinallyDoExpr());
287assertEquals(2, finallyRanCount);
288assertEquals("Caught: BOO (2)", tryFinallyDoExpr());
289assertEquals(3, finallyRanCount);
290assertEquals("Caught: BOO (3)", tryFinallyDoExpr());
291assertEquals(4, finallyRanCount);
292
293
294function TestOSR() {
295  var numbers = do {
296    let nums = [];
297    for (let i = 0; i < 1000; ++i) {
298      let value = (Math.random() * 100) | 0;
299      nums.push(value === 0 ? 1 : value), nums;
300    }
301  };
302  assertEquals(numbers.length, 1000);
303}
304
305for (var i = 0; i < 64; ++i) TestOSR();
306