Index: mozilla-tests/js1_8_1/decompilation/regress-380237-04.js |
=================================================================== |
--- mozilla-tests/js1_8_1/decompilation/regress-380237-04.js (revision 0) |
+++ mozilla-tests/js1_8_1/decompilation/regress-380237-04.js (revision 0) |
@@ -0,0 +1,334 @@ |
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
+/* ***** BEGIN LICENSE BLOCK ***** |
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1 |
+ * |
+ * The contents of this file are subject to the Mozilla Public License Version |
+ * 1.1 (the "License"); you may not use this file except in compliance with |
+ * the License. You may obtain a copy of the License at |
+ * http://www.mozilla.org/MPL/ |
+ * |
+ * Software distributed under the License is distributed on an "AS IS" basis, |
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License |
+ * for the specific language governing rights and limitations under the |
+ * License. |
+ * |
+ * The Original Code is JavaScript Engine testing utilities. |
+ * |
+ * The Initial Developer of the Original Code is |
+ * Mozilla Foundation. |
+ * Portions created by the Initial Developer are Copyright (C) 2007 |
+ * the Initial Developer. All Rights Reserved. |
+ * |
+ * Contributor(s): Jesse Ruderman |
+ * |
+ * Alternatively, the contents of this file may be used under the terms of |
+ * either the GNU General Public License Version 2 or later (the "GPL"), or |
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), |
+ * in which case the provisions of the GPL or the LGPL are applicable instead |
+ * of those above. If you wish to allow use of your version of this file only |
+ * under the terms of either the GPL or the LGPL, and not to allow others to |
+ * use your version of this file under the terms of the MPL, indicate your |
+ * decision by deleting the provisions above and replace them with the notice |
+ * and other provisions required by the GPL or the LGPL. If you do not delete |
+ * the provisions above, a recipient may use your version of this file under |
+ * the terms of any one of the MPL, the GPL or the LGPL. |
+ * |
+ * ***** END LICENSE BLOCK ***** */ |
+ |
+var gTestfile = 'regress-380237-04.js'; |
+//----------------------------------------------------------------------------- |
+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, "[#1=xx,3]"); |
+needParens(47, "[#1=xx,#1#]"); |
+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, "<x a={xx}/>"); |
+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; |
+ |
+ if (uf.indexOf(genexp) == -1) { |
+ print('openParenTest: section ' + section + ' expected ' + exp + ' uf ' + uf + ' genexp optimized away'); |
+ 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); |
+} |