diff -r 000000000000 -r 6474c204b198 js/src/tests/js1_8/genexps/regress-380237-04.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/js/src/tests/js1_8/genexps/regress-380237-04.js Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,297 @@ +// |reftest| skip -- obsolete test, need to remove minor failures to reenable. +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//----------------------------------------------------------------------------- +var BUGNUMBER = 380237; +var summary = 'Generator expressions parenthesization test'; +var actual = ''; +var expect = ''; + + +/* + +Given that parentheization seems so fragile *and* the rules for where +genexps are allowed keep changing, I thought it would be good to have +a way to test that: + +1) unparenthesized genexps are allowed in some places and the +decompilation is sane and not over-parenthesized + +2) unparenthesized genexps are disallowed in many places and when +there are parens, the decompilation is sane and not over-parenthesized + +*/ + +// |genexp| must have the exact same whitespace the decompiler uses +genexp = "x * x for (x in [])"; +genexpParened = "(" + genexp + ")"; +genexpParenedTwice = "(" + genexpParened + ")"; + +// Warning: be careful not to put [] around stuff, because that would +// cause it to be treated as an array comprehension instead of a +// generator expression! + +// Statements +doesNotNeedParens(1, "if (xx) { }"); +needParens(2, "if (1, xx) { }"); +needParens(3, "if (xx, 1) { }"); +doesNotNeedParens(4, "do { } while (xx);"); +doesNotNeedParens(5, "while (xx) { }"); +doesNotNeedParens(6, "switch (xx) { }"); +doesNotNeedParens(7, "with (xx) { }"); +needParens(8, "switch (x) { case xx: }"); +needParens(9, "return xx;"); +needParens(10, "yield xx;"); +needParens(11, "for (xx;;) { }"); +needParens(12, "for (;xx;) { }", "function anonymous() {\n for (;;) {\n }\n}"); +needParens(13, "for (;;xx) { }"); +needParens(14, "for (i in xx) { }"); +needParens(15, "throw xx"); +needParens(16, "try { } catch (e if xx) { }"); +needParens(17, "let (x=3) xx"); +needParens(18, "let (x=xx) 3"); + +// Function calls +doesNotNeedParens(19, "f(xx);"); +needParens(20, "f(xx, 1);"); +needParens(21, "f(1, xx);"); +doesNotNeedParens(22, "/x/(xx);"); +needParens(23, "/x/(xx, 1);"); +needParens(24, "/x/(1, xx);"); + +// eval is special and often confuses the decompiler. +doesNotNeedParens(25, "eval(xx);"); +needParens(26, "eval(xx, 1);"); +needParens(27, "eval(1, xx);"); + +// Expressions +needParens(28, "xx;"); // ??? +needParens(29, "var g = xx;"); // ??? +needParens(30, "g += xx;"); +needParens(31, "xx();"); +needParens(32, "xx() = 3;"); +needParens(33, "a ? xx : c"); +needParens(34, "xx ? b : c"); +needParens(35, "a ? b : xx"); +needParens(36, "1 ? xx : c"); +needParens(37, "0 ? b : xx"); +needParens(38, "1 + xx"); +needParens(39, "xx + 1"); +needParens(40, "1, xx"); +doesNotNeedParens(41, "+(xx)"); +doesNotNeedParens(42, "!(xx)"); +needParens(43, "xx, 1"); +needParens(44, "[1, xx]"); +needParens(45, "[xx, 1]"); +needParens(46, "[xx,3]"); +needParens(47, "[xx,null]"); +needParens(48, "xx.p"); +needParens(49, "xx.@p"); +needParens(50, "typeof xx;"); +needParens(51, "void xx;"); +needParens(52, "({ a: xx })"); +needParens(53, "({ a: 1, b: xx })"); +needParens(54, "({ a: xx, b: 1 })"); +needParens(55, "({ a getter: xx })"); +needParens(56, ""); +doesNotNeedParens(57, "new (xx);"); +doesNotNeedParens(58, "new a(xx);"); + + +// Generator expressions cannot be used as LHS, even though they're syntactic +// sugar for something that looks a lot like an "lvalue return": (f() = 3). + +rejectLHS(59, "++ (xx);"); +rejectLHS(60, "delete xx;"); +rejectLHS(61, "delete (xx);"); +rejectLHS(62, "for (xx in []) { }"); +rejectLHS(63, "for ((xx) in []) { }"); +rejectLHS(64, "try { } catch(xx) { }"); +rejectLHS(65, "try { } catch([(xx)]) { }"); +rejectLHS(66, "xx += 3;"); +rejectLHS(67, "(xx) += 3;"); +rejectLHS(68, "xx = 3;"); + +// Assignment +rejectLHS(69, " (xx) = 3;"); +rejectLHS(70, "var (xx) = 3;"); +rejectLHS(71, "const (xx) = 3;"); +rejectLHS(72, "let (xx) = 3;"); + +// Destructuring assignment +rejectLHS(73, " [(xx)] = 3;"); +rejectLHS(74, "var [(xx)] = 3;"); +rejectLHS(75, "const [(xx)] = 3;"); +rejectLHS(76, "let [(xx)] = 3;"); + +// Group assignment (Spidermonkey optimization for certain +// destructuring assignments) +rejectLHS(77, " [(xx)] = [3];"); +rejectLHS(78, "var [(xx)] = [3];"); +rejectLHS(79, "const [(xx)] = [3];"); +rejectLHS(80, "let [(xx)] = [3];"); + +// Destructuring & group assignment for array comprehensions, just for kicks. +rejectLHS(81, " [xx] = [3];"); +rejectLHS(82, "var [xx] = [3];"); +rejectLHS(83, "const [xx] = [3];"); +rejectLHS(84, "let [xx] = 3;"); +rejectLHS(85, " [xx] = 3;"); +rejectLHS(86, "var [xx] = 3;"); +rejectLHS(87, "const [xx] = 3;"); +rejectLHS(88, "let [xx] = 3;"); + +// This is crazy, ambiguous, and/or buggy. +// See https://bugzilla.mozilla.org/show_bug.cgi?id=380237#c23 et seq. +//doesNotNeedParens("(yield xx);"); + +print("Done!"); + +function doesNotNeedParens(section, pat) +{ + print("Testing section " + section + " pattern " + pat); + + var f, ft; + sanityCheck(section, pat); + + expect = 'No Error'; + actual = ''; + ft = pat.replace(/xx/, genexp); + try { + f = new Function(ft); + actual = 'No Error'; + } catch(e) { + print("Unparenthesized genexp SHOULD have been accepted here!"); + actual = e + ''; + } + reportCompare(expect, actual, summary + ': doesNotNeedParens section ' + section + ' pattern ' + pat); + + roundTripTest(section, f); + + // Make sure the decompilation is not over-parenthesized. + var uf = "" + f; + if (pat.indexOf("(xx)") != -1) + overParenTest(section, f); + // else + // print("Skipping the over-parenthesization test, because I don't know how to test for over-parenthesization when the pattern doesn't have parens snugly around it.") +} + +function needParens(section, pat, exp) +{ + print("Testing section " + section + " pattern " + pat); + + var f, ft; + sanityCheck(section, pat); + + expect = 'SyntaxError'; + actual = ''; + ft = pat.replace(/xx/, genexp); + try { + f = new Function(ft); + print("Unparenthesized genexp should NOT have been accepted here!"); + } catch(e) { + /* expected to throw */ + actual = e.name; + } + reportCompare(expect, actual, summary + ': needParens section ' + section + ' pattern ' + pat); + + expect = 'No Error'; + actual = ''; + ft = pat.replace(/xx/, genexpParened); + try { + f = new Function(ft); + actual = 'No Error'; + } catch(e) { + print("Yikes!"); + actual = e + ''; + } + reportCompare(expect, actual, summary + ': needParens section ' + section + ' ft ' + ft); + + roundTripTest(section, f, exp); + overParenTest(section, f, exp); +} + +function rejectLHS(section, pat) +{ + print("Testing section " + section + " pattern " + pat); + + // sanityCheck(pat); // because 'z' should be accepted as an LHS or binding + + var ft; + + expect = 'SyntaxError'; + actual = ''; + ft = pat.replace(/xx/, genexp) + try { + new Function(ft); + print("That should have been a syntax error!"); + actual = 'No Error'; + } catch(e) { + actual = e.name; + } + reportCompare(expect, actual, summary + ': rejectLHS section ' + section); +} + + +function overParenTest(section, f, exp) +{ + var uf = "" + f; + if (uf == exp) + return; + + reportCompare(false, uf.indexOf(genexpParened) == -1, summary + + ': overParenTest genexp snugly in parentheses: section ' + section + ' uf ' + uf); + + if (uf.indexOf(genexpParened) != -1) { + reportCompare(true, uf.indexOf(genexpParenedTwice) == -1, summary + + ': overParensTest decompilation should not be over-parenthesized: section ' + ' uf ' + uf); + } +} + +function sanityCheck(section, pat) +{ + expect = ''; + actual = ''; + + if (pat.indexOf("xx") == -1) + { + actual += "No 'xx' in this pattern? "; + } + + var f, ft; + ft = pat.replace(/xx/, "z"); + try { + f = new Function(ft); + } catch(e) { + actual += "Yowzers! Probably a bogus test!"; + } + reportCompare(expect, actual, summary + ': sanityCheck section ' + section + ' pattern ' + pat); +} + +function roundTripTest(section, f, exp) +{ + // Decompile + var uf = "" + f; + + // Recompile + expect = 'No Error'; + actual = ''; + var euf; + try { + euf = eval("(" + uf + ")"); + actual = 'No Error'; + reportCompare(expect, actual, summary + ': roundTripTest: section ' + section + ' uf ' + uf); + } catch(e) { + actual = e + ''; + reportCompare(expect, actual, summary + ': roundTripTest: section ' + section + ' uf ' + uf); + return; + } + + // Decompile again and make sure the decompilations match exactly. + expect = exp || uf; + actual = "" + euf; + reportCompare(expect, actual, summary + ': roundTripTest no round-trip change: section ' + section); +}