1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is JavaScript Engine testing utilities.
17 * The Initial Developer of the Original Code is
19 * Portions created by the Initial Developer are Copyright (C) 2007
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s): Jesse Ruderman
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 var gTestfile
= 'regress-380237-04.js';
39 //-----------------------------------------------------------------------------
40 var BUGNUMBER
= 380237;
41 var summary
= 'Generator expressions parenthesization test';
48 Given that parentheization seems so fragile *and* the rules for where
49 genexps are allowed keep changing, I thought it would be good to have
52 1) unparenthesized genexps are allowed in some places and the
53 decompilation is sane and not over-parenthesized
55 2) unparenthesized genexps are disallowed in many places and when
56 there are parens, the decompilation is sane and not over-parenthesized
60 // |genexp| must have the exact same whitespace the decompiler uses
61 genexp
= "x * x for (x in [])";
62 genexpParened
= "(" + genexp
+ ")";
63 genexpParenedTwice
= "(" + genexpParened
+ ")";
65 // Warning: be careful not to put [] around stuff, because that would
66 // cause it to be treated as an array comprehension instead of a
67 // generator expression!
70 doesNotNeedParens(1, "if (xx) { }");
71 needParens(2, "if (1, xx) { }");
72 needParens(3, "if (xx, 1) { }");
73 doesNotNeedParens(4, "do { } while (xx);");
74 doesNotNeedParens(5, "while (xx) { }");
75 doesNotNeedParens(6, "switch (xx) { }");
76 doesNotNeedParens(7, "with (xx) { }");
77 needParens(8, "switch (x) { case xx: }");
78 needParens(9, "return xx;");
79 needParens(10, "yield xx;");
80 needParens(11, "for (xx;;) { }");
81 needParens(12, "for (;xx;) { }", "function anonymous() {\n for (;;) {\n }\n}");
82 needParens(13, "for (;;xx) { }");
83 needParens(14, "for (i in xx) { }");
84 needParens(15, "throw xx");
85 needParens(16, "try { } catch (e if xx) { }");
86 needParens(17, "let (x=3) xx");
87 needParens(18, "let (x=xx) 3");
90 doesNotNeedParens(19, "f(xx);");
91 needParens(20, "f(xx, 1);");
92 needParens(21, "f(1, xx);");
93 doesNotNeedParens(22, "/x/(xx);");
94 needParens(23, "/x/(xx, 1);");
95 needParens(24, "/x/(1, xx);");
97 // eval is special and often confuses the decompiler.
98 doesNotNeedParens(25, "eval(xx);");
99 needParens(26, "eval(xx, 1);");
100 needParens(27, "eval(1, xx);");
103 needParens(28, "xx;"); // ???
104 needParens(29, "var g = xx;"); // ???
105 needParens(30, "g += xx;");
106 needParens(31, "xx();");
107 needParens(32, "xx() = 3;");
108 needParens(33, "a ? xx : c");
109 needParens(34, "xx ? b : c");
110 needParens(35, "a ? b : xx");
111 needParens(36, "1 ? xx : c");
112 needParens(37, "0 ? b : xx");
113 needParens(38, "1 + xx");
114 needParens(39, "xx + 1");
115 needParens(40, "1, xx");
116 doesNotNeedParens(41, "+(xx)");
117 doesNotNeedParens(42, "!(xx)");
118 needParens(43, "xx, 1");
119 needParens(44, "[1, xx]");
120 needParens(45, "[xx, 1]");
121 needParens(46, "[#1=xx,3]");
122 needParens(47, "[#1=xx,#1#]");
123 needParens(48, "xx.p");
124 needParens(49, "xx.@p");
125 needParens(50, "typeof xx;");
126 needParens(51, "void xx;");
127 needParens(52, "({ a: xx })");
128 needParens(53, "({ a: 1, b: xx })");
129 needParens(54, "({ a: xx, b: 1 })");
130 needParens(55, "({ a getter: xx })");
131 needParens(56, "<x a={xx}/>");
132 doesNotNeedParens(57, "new (xx);");
133 doesNotNeedParens(58, "new a(xx);");
136 // Generator expressions cannot be used as LHS, even though they're syntactic
137 // sugar for something that looks a lot like an "lvalue return": (f() = 3).
139 rejectLHS(59, "++ (xx);");
140 rejectLHS(60, "delete xx;");
141 rejectLHS(61, "delete (xx);");
142 rejectLHS(62, "for (xx in []) { }");
143 rejectLHS(63, "for ((xx) in []) { }");
144 rejectLHS(64, "try { } catch(xx) { }");
145 rejectLHS(65, "try { } catch([(xx)]) { }");
146 rejectLHS(66, "xx += 3;");
147 rejectLHS(67, "(xx) += 3;");
148 rejectLHS(68, "xx = 3;");
151 rejectLHS(69, " (xx) = 3;");
152 rejectLHS(70, "var (xx) = 3;");
153 rejectLHS(71, "const (xx) = 3;");
154 rejectLHS(72, "let (xx) = 3;");
156 // Destructuring assignment
157 rejectLHS(73, " [(xx)] = 3;");
158 rejectLHS(74, "var [(xx)] = 3;");
159 rejectLHS(75, "const [(xx)] = 3;");
160 rejectLHS(76, "let [(xx)] = 3;");
162 // Group assignment (Spidermonkey optimization for certain
163 // destructuring assignments)
164 rejectLHS(77, " [(xx)] = [3];");
165 rejectLHS(78, "var [(xx)] = [3];");
166 rejectLHS(79, "const [(xx)] = [3];");
167 rejectLHS(80, "let [(xx)] = [3];");
169 // Destructuring & group assignment for array comprehensions, just for kicks.
170 rejectLHS(81, " [xx] = [3];");
171 rejectLHS(82, "var [xx] = [3];");
172 rejectLHS(83, "const [xx] = [3];");
173 rejectLHS(84, "let [xx] = 3;");
174 rejectLHS(85, " [xx] = 3;");
175 rejectLHS(86, "var [xx] = 3;");
176 rejectLHS(87, "const [xx] = 3;");
177 rejectLHS(88, "let [xx] = 3;");
179 // This is crazy, ambiguous, and/or buggy.
180 // See https://bugzilla.mozilla.org/show_bug.cgi?id=380237#c23 et seq.
181 //doesNotNeedParens("(yield xx);");
185 function doesNotNeedParens(section
, pat
)
187 print("Testing section " + section
+ " pattern " + pat
);
190 sanityCheck(section
, pat
);
194 ft
= pat
.replace(/xx/, genexp
);
196 f
= new Function(ft
);
199 print("Unparenthesized genexp SHOULD have been accepted here!");
202 reportCompare(expect
, actual
, summary
+ ': doesNotNeedParens section ' + section
+ ' pattern ' + pat
);
204 roundTripTest(section
, f
);
206 // Make sure the decompilation is not over-parenthesized.
208 if (pat
.indexOf("(xx)") != -1)
209 overParenTest(section
, f
);
211 // 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.")
214 function needParens(section
, pat
, exp
)
216 print("Testing section " + section
+ " pattern " + pat
);
219 sanityCheck(section
, pat
);
221 expect
= 'SyntaxError';
223 ft
= pat
.replace(/xx/, genexp
);
225 f
= new Function(ft
);
226 print("Unparenthesized genexp should NOT have been accepted here!");
228 /* expected to throw */
231 reportCompare(expect
, actual
, summary
+ ': needParens section ' + section
+ ' pattern ' + pat
);
235 ft
= pat
.replace(/xx/, genexpParened
);
237 f
= new Function(ft
);
243 reportCompare(expect
, actual
, summary
+ ': needParens section ' + section
+ ' ft ' + ft
);
245 roundTripTest(section
, f
, exp
);
246 overParenTest(section
, f
, exp
);
249 function rejectLHS(section
, pat
)
251 print("Testing section " + section
+ " pattern " + pat
);
253 // sanityCheck(pat); // because 'z' should be accepted as an LHS or binding
257 expect
= 'SyntaxError';
259 ft
= pat
.replace(/xx/, genexp
)
262 print("That should have been a syntax error!");
267 reportCompare(expect
, actual
, summary
+ ': rejectLHS section ' + section
);
271 function overParenTest(section
, f
, exp
)
277 if (uf
.indexOf(genexp
) == -1) {
278 print('openParenTest: section ' + section
+ ' expected ' + exp
+ ' uf ' + uf
+ ' genexp optimized away');
282 reportCompare(false, uf
.indexOf(genexpParened
) == -1, summary
+
283 ': overParenTest genexp snugly in parentheses: section ' + section
+ ' uf ' + uf
);
285 if (uf
.indexOf(genexpParened
) != -1) {
286 reportCompare(true, uf
.indexOf(genexpParenedTwice
) == -1, summary
+
287 ': overParensTest decompilation should not be over-parenthesized: section ' + ' uf ' + uf
);
291 function sanityCheck(section
, pat
)
296 if (pat
.indexOf("xx") == -1)
298 actual
+= "No 'xx' in this pattern? ";
302 ft
= pat
.replace(/xx/, "z");
304 f
= new Function(ft
);
306 actual
+= "Yowzers! Probably a bogus test!";
308 reportCompare(expect
, actual
, summary
+ ': sanityCheck section ' + section
+ ' pattern ' + pat
);
311 function roundTripTest(section
, f
, exp
)
321 euf
= eval("(" + uf
+ ")");
323 reportCompare(expect
, actual
, summary
+ ': roundTripTest: section ' + section
+ ' uf ' + uf
);
326 reportCompare(expect
, actual
, summary
+ ': roundTripTest: section ' + section
+ ' uf ' + uf
);
330 // Decompile again and make sure the decompilations match exactly.
333 reportCompare(expect
, actual
, summary
+ ': roundTripTest no round-trip change: section ' + section
);