|  | // Copyright 2011 the V8 project authors. All rights reserved. | 
|  | // Redistribution and use in source and binary forms, with or without | 
|  | // modification, are permitted provided that the following conditions are | 
|  | // met: | 
|  | // | 
|  | //     * Redistributions of source code must retain the above copyright | 
|  | //       notice, this list of conditions and the following disclaimer. | 
|  | //     * Redistributions in binary form must reproduce the above | 
|  | //       copyright notice, this list of conditions and the following | 
|  | //       disclaimer in the documentation and/or other materials provided | 
|  | //       with the distribution. | 
|  | //     * Neither the name of Google Inc. nor the names of its | 
|  | //       contributors may be used to endorse or promote products derived | 
|  | //       from this software without specific prior written permission. | 
|  | // | 
|  | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 
|  | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 
|  | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 
|  | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 
|  | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
|  | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
|  | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
|  | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 
|  | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
|  |  | 
|  | // Test let declarations in various settings. | 
|  |  | 
|  | "use strict"; | 
|  |  | 
|  | // Global | 
|  | let x; | 
|  | let y = 2; | 
|  | const z = 4; | 
|  | class c { static foo() { return 1; } } | 
|  |  | 
|  | // Block local | 
|  | { | 
|  | let y; | 
|  | let x = 3; | 
|  | const z = 5; | 
|  | class c { static foo() { return 2; } } | 
|  | } | 
|  |  | 
|  | assertEquals(undefined, x); | 
|  | assertEquals(2,y); | 
|  | assertEquals(4,z); | 
|  | assertEquals(1, c.foo()); | 
|  |  | 
|  | if (true) { | 
|  | let y; | 
|  | assertEquals(undefined, y); | 
|  | } | 
|  |  | 
|  | // Invalid declarations are early errors in harmony mode and thus should trigger | 
|  | // an exception in eval code during parsing, before even compiling or executing | 
|  | // the code. Thus the generated function is not called here. | 
|  | function TestLocalThrows(str, expect) { | 
|  | assertThrows("(function(arg){ 'use strict'; " + str + "})", expect); | 
|  | } | 
|  |  | 
|  | function TestLocalDoesNotThrow(str) { | 
|  | assertDoesNotThrow("(function(arg){ 'use strict'; " + str + "})()"); | 
|  | } | 
|  |  | 
|  | // Test let declarations in statement positions. | 
|  | TestLocalThrows("if (true) let x;", SyntaxError); | 
|  | TestLocalThrows("if (true) {} else let x;", SyntaxError); | 
|  | TestLocalThrows("do let x; while (false)", SyntaxError); | 
|  | TestLocalThrows("while (false) let x;", SyntaxError); | 
|  | TestLocalThrows("label: let x;", SyntaxError); | 
|  | TestLocalThrows("for (;false;) let x;", SyntaxError); | 
|  | TestLocalDoesNotThrow("switch (true) { case true: let x; }"); | 
|  | TestLocalDoesNotThrow("switch (true) { default: let x; }"); | 
|  |  | 
|  | // Test const declarations with initialisers in statement positions. | 
|  | TestLocalThrows("if (true) const x = 1;", SyntaxError); | 
|  | TestLocalThrows("if (true) {} else const x = 1;", SyntaxError); | 
|  | TestLocalThrows("do const x = 1; while (false)", SyntaxError); | 
|  | TestLocalThrows("while (false) const x = 1;", SyntaxError); | 
|  | TestLocalThrows("label: const x = 1;", SyntaxError); | 
|  | TestLocalThrows("for (;false;) const x = 1;", SyntaxError); | 
|  | TestLocalDoesNotThrow("switch (true) { case true: const x = 1; }"); | 
|  | TestLocalDoesNotThrow("switch (true) { default: const x = 1; }"); | 
|  |  | 
|  | // Test const declarations without initialisers. | 
|  | TestLocalThrows("const x;", SyntaxError); | 
|  | TestLocalThrows("const x = 1, y;", SyntaxError); | 
|  | TestLocalThrows("const x, y = 1;", SyntaxError); | 
|  |  | 
|  | // Test const declarations without initialisers in statement positions. | 
|  | TestLocalThrows("if (true) const x;", SyntaxError); | 
|  | TestLocalThrows("if (true) {} else const x;", SyntaxError); | 
|  | TestLocalThrows("do const x; while (false)", SyntaxError); | 
|  | TestLocalThrows("while (false) const x;", SyntaxError); | 
|  | TestLocalThrows("label: const x;", SyntaxError); | 
|  | TestLocalThrows("for (;false;) const x;", SyntaxError); | 
|  | TestLocalThrows("switch (true) { case true: const x; }", SyntaxError); | 
|  | TestLocalThrows("switch (true) { default: const x; }", SyntaxError); | 
|  |  | 
|  | // Test var declarations in statement positions. | 
|  | TestLocalDoesNotThrow("if (true) var x;"); | 
|  | TestLocalDoesNotThrow("if (true) {} else var x;"); | 
|  | TestLocalDoesNotThrow("do var x; while (false)"); | 
|  | TestLocalDoesNotThrow("while (false) var x;"); | 
|  | TestLocalDoesNotThrow("label: var x;"); | 
|  | TestLocalDoesNotThrow("for (;false;) var x;"); | 
|  | TestLocalDoesNotThrow("switch (true) { case true: var x; }"); | 
|  | TestLocalDoesNotThrow("switch (true) { default: var x; }"); | 
|  |  | 
|  | // Test class declarations with initialisers in statement positions. | 
|  | TestLocalThrows("if (true) class x { };", SyntaxError); | 
|  | TestLocalThrows("if (true) {} else class x { };", SyntaxError); | 
|  | TestLocalThrows("do class x { }; while (false)", SyntaxError); | 
|  | TestLocalThrows("while (false) class x { };", SyntaxError); | 
|  | TestLocalThrows("label: class x { };", SyntaxError); | 
|  | TestLocalThrows("for (;false;) class x { };", SyntaxError); | 
|  | TestLocalDoesNotThrow("switch (true) { case true: class x { }; }"); | 
|  | TestLocalDoesNotThrow("switch (true) { default: class x { }; }"); | 
|  |  | 
|  | // Test that redeclarations of functions are only allowed in outermost scope. | 
|  | TestLocalThrows("{ let f; var f; }", SyntaxError); | 
|  | TestLocalThrows("{ var f; let f; }", SyntaxError); | 
|  | TestLocalThrows("{ function f() {} let f; }", SyntaxError); | 
|  | TestLocalThrows("{ let f; function f() {} }", SyntaxError); | 
|  | TestLocalThrows("{ function f() {} var f; }", SyntaxError); | 
|  | TestLocalThrows("{ var f; function f() {} }", SyntaxError); | 
|  | TestLocalThrows("{ function f() {} class f {} }", SyntaxError); | 
|  | TestLocalThrows("{ class f {}; function f() {} }", SyntaxError); | 
|  | TestLocalThrows("{ function f() {} function f() {} }", SyntaxError); | 
|  | TestLocalThrows("function f() {} let f;", SyntaxError); | 
|  | TestLocalThrows("let f; function f() {}", SyntaxError); | 
|  | TestLocalThrows("function f() {} class f {}", SyntaxError); | 
|  | TestLocalThrows("class f {}; function f() {}", SyntaxError); | 
|  | TestLocalDoesNotThrow("function arg() {}"); | 
|  | TestLocalDoesNotThrow("function f() {} var f;"); | 
|  | TestLocalDoesNotThrow("var f; function f() {}"); | 
|  | TestLocalDoesNotThrow("function f() {} function f() {}"); | 
|  |  | 
|  | function g(f) { | 
|  | function f() { return 1 } | 
|  | return f() | 
|  | } | 
|  | assertEquals(1, g(function() { return 2 })) | 
|  |  | 
|  |  | 
|  | // Test function declarations in source element and | 
|  | // sloppy statement positions. | 
|  | function f() { | 
|  | // Sloppy source element positions. | 
|  | function g0() { | 
|  | "use strict"; | 
|  | // Strict source element positions. | 
|  | function h() { } | 
|  | { | 
|  | function h1() { } | 
|  | } | 
|  | } | 
|  | { | 
|  | function g1() { } | 
|  | } | 
|  | } | 
|  | f(); | 
|  |  | 
|  | // Test function declarations in statement position in strict mode. | 
|  | TestLocalThrows("function f() { if (true) function g() {} }", SyntaxError); | 
|  | TestLocalThrows("function f() { if (true) {} else function g() {} }", SyntaxError); | 
|  | TestLocalThrows("function f() { do function g() {} while (false) }", SyntaxError); | 
|  | TestLocalThrows("function f() { while (false) function g() {} }", SyntaxError); | 
|  | TestLocalThrows("function f() { label: function g() {} }", SyntaxError); | 
|  | TestLocalThrows("function f() { for (;false;) function g() {} }", SyntaxError); | 
|  | TestLocalDoesNotThrow("function f() { switch (true) { case true: function g() {} } }"); | 
|  | TestLocalDoesNotThrow("function f() { switch (true) { default: function g() {} } }"); |