| Index: test/mjsunit/harmony/do-expressions.js
|
| diff --git a/test/mjsunit/harmony/do-expressions.js b/test/mjsunit/harmony/do-expressions.js
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..a2c014cbc6f523e7bbba07a2bc5323fa548cd8a7
|
| --- /dev/null
|
| +++ b/test/mjsunit/harmony/do-expressions.js
|
| @@ -0,0 +1,273 @@
|
| +// Copyright 2015 the V8 project authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +// Flags: --harmony-do-expressions --harmony-sloppy-let --allow-natives-syntax
|
| +// Flags: --harmony-default-parameters --harmony-destructuring
|
| +
|
| +function returnValue(v) { return v; }
|
| +function MyError() {}
|
| +var global = this;
|
| +
|
| +function TestBasic() {
|
| + // Looping and lexical declarations
|
| + assertEquals(512, returnValue(do {
|
| + let n = 2;
|
| + for (let i = 0; i < 4; i++) n <<= 2;
|
| + }));
|
| +
|
| + // Strings do the right thing
|
| + assertEquals("spooky halloween", returnValue(do {
|
| + "happy halloween".replace('happy', 'spooky');
|
| + }));
|
| +
|
| + // Do expressions with no completion produce an undefined value
|
| + assertEquals(undefined, returnValue(do {}));
|
| + assertEquals(undefined, returnValue(do { var x = 99; }));
|
| + assertEquals(undefined, returnValue(do { function f() {}; }));
|
| + assertEquals(undefined, returnValue(do { let z = 33; }));
|
| +
|
| + // Propagation of exception
|
| + assertThrows(function() {
|
| + (do {
|
| + throw new MyError();
|
| + "potatoes";
|
| + });
|
| + }, MyError);
|
| +
|
| + assertThrows(function() {
|
| + return do {
|
| + throw new MyError();
|
| + "potatoes";
|
| + };
|
| + }, MyError);
|
| +
|
| + // Return value within do-block overrides `return |do-expression|`
|
| + assertEquals("inner-return", (function() {
|
| + return "outer-return" + do {
|
| + return "inner-return";
|
| + "";
|
| + };
|
| + })());
|
| +
|
| + var count = 0, n = 1;
|
| + // Breaking out |do-expression|
|
| + assertEquals(3, (function() {
|
| + for (var i = 0; i < 10; ++i) (count += 2 * do { if (i === 3) break; ++n });
|
| + return i;
|
| + })());
|
| + // (2 * 2) + (2 * 3) + (2 * 4)
|
| + assertEquals(18, count);
|
| +
|
| + // Continue in |do-expression|
|
| + count = 0, n = 1;
|
| + assertEquals([1, 3, 5, 7, 9], (function() {
|
| + var values = [];
|
| + for (var i = 0; i < 10; ++i) {
|
| + count += 2 * (do {
|
| + if ((i & 1) === 0) continue;
|
| + values.push(i);
|
| + ++n;
|
| + }) + 1;
|
| + }
|
| + // (2*2) + 1 + (2*3) + 1 + (2*4) + 1 + (2*5) + 1 + (2*6) + 1
|
| + return values;
|
| + })());
|
| + assertEquals(count, 45);
|
| +
|
| + assertThrows("(do { break; });", SyntaxError);
|
| + assertThrows("(do { continue; });", SyntaxError);
|
| +
|
| + // Real-world use case for desugaring
|
| + var array = [1, 2, 3, 4, 5], iterable = [6, 7, 8,9];
|
| + assertEquals([1, 2, 3, 4, 5, 6, 7, 8, 9], do {
|
| + for (var element of iterable) array.push(element);
|
| + array;
|
| + });
|
| +
|
| + // Nested do-expressions
|
| + assertEquals(125, do { (do { (do { 5 * 5 * 5 }) }) });
|
| +
|
| + // Directives are not honoured
|
| + (do {
|
| + "use strict";
|
| + foo = 80;
|
| + assertEquals(foo, 80);
|
| + });
|
| +
|
| + // Non-empty operand stack testing
|
| + var O = {
|
| + method1() {
|
| + let x = 256;
|
| + return x + do {
|
| + for (var i = 0; i < 4; ++i) x += i;
|
| + } + 17;
|
| + },
|
| + method2() {
|
| + let x = 256;
|
| + this.reset();
|
| + return x + do {
|
| + for (var i = 0; i < this.length(); ++i) x += this.index() * 2;
|
| + };
|
| + },
|
| + _index: 0,
|
| + index() {
|
| + return ++this._index;
|
| + },
|
| + _length: 4,
|
| + length() { return this._length; },
|
| + reset() { this._index = 0; }
|
| + };
|
| + assertEquals(535, O["method" + do { 1 } + ""]());
|
| + assertEquals(532, O["method" + do { ({ valueOf() { return "2"; } }); }]());
|
| + assertEquals(532, O[
|
| + do { let s = ""; for (let c of "method") s += c; } + "2"]());
|
| +}
|
| +TestBasic();
|
| +
|
| +
|
| +function TestDeoptimization1() {
|
| + function f(v) {
|
| + return 88 + do {
|
| + v.a * v.b + v.c;
|
| + };
|
| + }
|
| +
|
| + var o1 = {};
|
| + o1.a = 10;
|
| + o1.b = 5;
|
| + o1.c = 50;
|
| +
|
| + var o2 = {};
|
| + o2.c = 100;
|
| + o2.a = 10;
|
| + o2.b = 10;
|
| +
|
| + assertEquals(188, f(o1));
|
| + assertEquals(188, f(o1));
|
| + %OptimizeFunctionOnNextCall(f);
|
| + assertEquals(188, f(o1));
|
| + assertOptimized(f);
|
| + assertEquals(288, f(o2));
|
| + assertUnoptimized(f);
|
| + assertEquals(288, f(o2));
|
| +}
|
| +TestDeoptimization1();
|
| +
|
| +
|
| +function TestInParameterInitializers() {
|
| + var first_name = "George";
|
| + var last_name = "Jetson";
|
| + function fn1(name = do { first_name + " " + last_name }) {
|
| + return name;
|
| + }
|
| + assertEquals("George Jetson", fn1());
|
| +
|
| + var _items = [1, 2, 3, NaN, 4, 5];
|
| + function fn2(items = do {
|
| + let items = [];
|
| + for (var el of _items) {
|
| + if (el !== el) break;
|
| + items.push(el), items;
|
| + }
|
| + }) {
|
| + return items;
|
| + }
|
| + assertEquals([1, 2, 3], fn2());
|
| +
|
| + function thrower() { throw new MyError(); }
|
| + function fn3(exception = do { try { thrower(); } catch (e) { e } }) {
|
| + return exception;
|
| + }
|
| + assertDoesNotThrow(fn3);
|
| + assertInstanceof(fn3(), MyError);
|
| +
|
| + function fn4(exception = do { throw new MyError() }) {}
|
| + function catcher(fn) {
|
| + try {
|
| + fn();
|
| + assertUnreachable("fn() initializer should throw");
|
| + } catch (e) {
|
| + assertInstanceof(e, MyError);
|
| + }
|
| + }
|
| + catcher(fn4);
|
| +}
|
| +TestInParameterInitializers();
|
| +
|
| +
|
| +function TestWithEval() {
|
| + (function sloppy1() {
|
| + assertEquals(do { eval("var x = 5"), x }, 5);
|
| + assertEquals(x, 5);
|
| + })();
|
| +
|
| + assertThrows(function strict1() {
|
| + "use strict";
|
| + (do { eval("var x = 5"), x }, 5);
|
| + }, ReferenceError);
|
| +
|
| + assertThrows(function strict2() {
|
| + (do { eval("'use strict'; var x = 5"), x }, 5);
|
| + }, ReferenceError);
|
| +}
|
| +TestWithEval();
|
| +
|
| +
|
| +function TestHoisting() {
|
| + (do { var a = 1; });
|
| + assertEquals(a, 1);
|
| + assertEquals(global.a, undefined);
|
| +
|
| + (do {
|
| + for (let it of [1, 2, 3, 4, 5]) {
|
| + var b = it;
|
| + }
|
| + });
|
| + assertEquals(b, 5);
|
| + assertEquals(global.b, undefined);
|
| +
|
| + {
|
| + let x = 1
|
| +
|
| + // TODO(caitp): ensure VariableStatements in |do-expressions| in parameter
|
| + // initializers, are evaluated in the same VariableEnvironment as they would
|
| + // be for eval().
|
| + // function f1(a = do { var x = 2 }, b = x) { return b }
|
| + // assertEquals(1, f1())
|
| +
|
| + // function f2(a = x, b = do { var x = 2 }) { return a }
|
| + // assertEquals(1, f2())
|
| +
|
| + function f3({a = do { var x = 2 }, b = x}) { return b }
|
| + assertEquals(2, f3({}))
|
| +
|
| + function f4({a = x, b = do { var x = 2 }}) { return b }
|
| + assertEquals(undefined, f4({}))
|
| +
|
| + function f5(a = do { var y = 0 }) {}
|
| + assertThrows(() => y, ReferenceError)
|
| + }
|
| +
|
| + // TODO(caitp): Always block-scope function declarations in |do| expressions
|
| + //(do {
|
| + // assertEquals(true, inner_func());
|
| + // function inner_func() { return true; }
|
| + //});
|
| + //assertThrows(function() { return innerFunc(); }, ReferenceError);
|
| +}
|
| +TestHoisting();
|
| +
|
| +
|
| +function TestOSR() {
|
| + var numbers = do {
|
| + let nums = [];
|
| + for (let i = 0; i < 1000; ++i) {
|
| + let value = (Math.random() * 100) | 0;
|
| + nums.push(value === 0 ? 1 : value), nums;
|
| + }
|
| + };
|
| + assertEquals(numbers.length, 1000);
|
| +}
|
| +
|
| +for (var i = 0; i < 64; ++i) TestOSR();
|
|
|