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