load(libdir + 'asserts.js'); load(libdir + 'eqArrayHelper.js'); assertThrowsInstanceOf(() => new Function('[...a, ,] = []'), SyntaxError, 'trailing elision'); assertThrowsInstanceOf(() => new Function('[a, ...b, c] = []'), SyntaxError, 'trailing param'); assertThrowsInstanceOf(() => new Function('[...a=b] = []'), SyntaxError, 'assignment expression'); assertThrowsInstanceOf(() => new Function('[...a()] = []'), SyntaxError, 'call expression'); assertThrowsInstanceOf(() => new Function('[...(a,b)] = []'), SyntaxError, 'comma expression'); assertThrowsInstanceOf(() => new Function('[...a++] = []'), SyntaxError, 'postfix expression'); assertThrowsInstanceOf(() => new Function('[...!a] = []'), SyntaxError, 'unary expression'); assertThrowsInstanceOf(() => new Function('[...a+b] = []'), SyntaxError, 'binary expression'); assertThrowsInstanceOf(() => new Function('var [...a.x] = []'), SyntaxError, 'lvalue expression in declaration'); assertThrowsInstanceOf(() => new Function('var [...(b)] = []'), SyntaxError); assertThrowsInstanceOf(() => new Function('[...b,] = []'), SyntaxError); assertThrowsInstanceOf(() => { try { eval('let [...[...x]] = (() => { throw "foo"; } )();'); } catch(e) { assertEq(e, "foo"); } x; }, ReferenceError); var inputArray = [1, 2, 3]; var inputDeep = [1, inputArray]; var inputObject = {a: inputArray}; var inputStr = 'str'; function *inputGenerator() { yield 1; yield 2; yield 3; } var o = {prop: null, call: function () { return o; }}; var expected = [2, 3]; var expectedStr = ['t', 'r']; function testAll(fn) { testDeclaration(fn); o.prop = null; assertEqArray(fn('[, ...(o.prop)]', inputArray, 'o.prop'), expected); o.prop = null; assertEqArray(fn('[, ...(o.call().prop)]', inputArray, 'o.prop'), expected); o.prop = null; assertEqArray(fn('[, ...[...(o.prop)]]', inputArray, 'o.prop'), expected); o.prop = null; assertEqArray(fn('[, ...[...(o.call().prop)]]', inputArray, 'o.prop'), expected); } function testDeclaration(fn) { testStr(fn); assertEqArray(fn('[, ...rest]', inputArray), expected); assertEqArray(fn('[, ...rest]', inputGenerator()), expected); assertEqArray(fn('[, [, ...rest]]', inputDeep), expected); assertEqArray(fn('{a: [, ...rest]}', inputObject), expected); assertEqArray(fn('[, ...[...rest]]', inputArray), expected); assertEqArray(fn('[, ...[...rest]]', inputGenerator()), expected); assertEqArray(fn('[, [, ...[...rest]]]', inputDeep), expected); assertEqArray(fn('{a: [, ...[...rest]]}', inputObject), expected); assertEqArray(fn('[, ...{0: a, 1: b}]', inputArray, '[a, b]'), expected); assertEqArray(fn('[, ...{0: a, 1: b}]', inputGenerator(), '[a, b]'), expected); assertEqArray(fn('[, [, ...{0: a, 1: b}]]', inputDeep, '[a, b]'), expected); assertEqArray(fn('{a: [, ...{0: a, 1: b}]}', inputObject, '[a, b]'), expected); } function testStr(fn) { assertEqArray(fn('[, ...rest]', inputStr), expectedStr); assertEqArray(fn('[, ...[...rest]]', inputStr), expectedStr); assertEqArray(fn('[, ...{0: a, 1: b}]', inputStr, '[a, b]'), expectedStr); } function testForIn(pattern, input, binding) { binding = binding || 'rest'; return new Function('input', 'for (var ' + pattern + ' in {[input]: 1}) {}' + 'return ' + binding )(input); } testStr(testForIn); function testVar(pattern, input, binding) { binding = binding || 'rest'; return new Function('input', 'var ' + pattern + ' = input;' + 'return ' + binding )(input); } testDeclaration(testVar); function testGlobal(pattern, input, binding) { binding = binding || 'rest'; return new Function('input', '(' + pattern + ' = input);' + 'return ' + binding )(input); } testAll(testGlobal); function testClosure(pattern, input, binding) { binding = binding || 'rest'; const decl = binding.replace('[', '').replace(']', ''); return new Function('input', 'var ' + decl + '; (function () {' + '(' + pattern + ' = input);' + '})();' + 'return ' + binding )(input); } testDeclaration(testClosure); function testArgument(pattern, input, binding) { binding = binding || 'rest'; return new Function('input', 'return (function (' + pattern + ') {' + 'return ' + binding + '; })(input);' )(input); } testDeclaration(testArgument); function testArgumentFunction(pattern, input, binding) { binding = binding || 'rest'; return new Function(pattern, 'return ' + binding )(input); } // ES6 requires the `Function` constructor to accept arbitrary // `BindingElement`s as formal parameters. testDeclaration(testArgumentFunction); function testThrow(pattern, input, binding) { binding = binding || 'rest'; return new Function('input', 'try { throw input }' + 'catch(' + pattern + ') {' + 'return ' + binding + '; }' )(input); } testDeclaration(testThrow);