Imported Upstream version 1.0.0
[platform/upstream/js.git] / js / src / tests / js1_8 / genexps / regress-380237-04.js
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
4  *
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/
9  *
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
13  * License.
14  *
15  * The Original Code is JavaScript Engine testing utilities.
16  *
17  * The Initial Developer of the Original Code is
18  * Mozilla Foundation.
19  * Portions created by the Initial Developer are Copyright (C) 2007
20  * the Initial Developer. All Rights Reserved.
21  *
22  * Contributor(s): Jesse Ruderman
23  *
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.
35  *
36  * ***** END LICENSE BLOCK ***** */
37
38 //-----------------------------------------------------------------------------
39 var BUGNUMBER = 380237;
40 var summary = 'Generator expressions parenthesization test';
41 var actual = '';
42 var expect = '';
43
44
45 /*
46
47 Given that parentheization seems so fragile *and* the rules for where
48 genexps are allowed keep changing, I thought it would be good to have
49 a way to test that:
50
51 1) unparenthesized genexps are allowed in some places and the
52 decompilation is sane and not over-parenthesized
53
54 2) unparenthesized genexps are disallowed in many places and when
55 there are parens, the decompilation is sane and not over-parenthesized
56
57 */
58
59 // |genexp| must have the exact same whitespace the decompiler uses
60 genexp = "x * x for (x in [])";
61 genexpParened = "(" + genexp + ")";
62 genexpParenedTwice = "(" + genexpParened + ")";
63
64 // Warning: be careful not to put [] around stuff, because that would
65 // cause it to be treated as an array comprehension instead of a
66 // generator expression!
67
68 // Statements
69 doesNotNeedParens(1, "if (xx) { }");
70 needParens(2, "if (1, xx) { }");
71 needParens(3, "if (xx, 1) { }");
72 doesNotNeedParens(4, "do { } while (xx);");
73 doesNotNeedParens(5, "while (xx) { }");
74 doesNotNeedParens(6, "switch (xx) { }");
75 doesNotNeedParens(7, "with (xx) { }");
76 needParens(8, "switch (x) { case xx: }");
77 needParens(9, "return xx;");
78 needParens(10, "yield xx;");
79 needParens(11, "for (xx;;) { }");
80 needParens(12, "for (;xx;) { }", "function anonymous() {\n    for (;;) {\n    }\n}");
81 needParens(13, "for (;;xx) { }");
82 needParens(14, "for (i in xx) { }");
83 needParens(15, "throw xx");
84 needParens(16, "try { } catch (e if xx) { }");
85 needParens(17, "let (x=3) xx");
86 needParens(18, "let (x=xx) 3");
87
88 // Function calls
89 doesNotNeedParens(19, "f(xx);");
90 needParens(20, "f(xx, 1);");
91 needParens(21, "f(1, xx);");
92 doesNotNeedParens(22, "/x/(xx);");
93 needParens(23, "/x/(xx, 1);");
94 needParens(24, "/x/(1, xx);");
95
96 // eval is special and often confuses the decompiler.
97 doesNotNeedParens(25, "eval(xx);");
98 needParens(26, "eval(xx, 1);");
99 needParens(27, "eval(1, xx);");
100
101 // Expressions
102 needParens(28, "xx;");            // ???
103 needParens(29, "var g = xx;");    // ???
104 needParens(30, "g += xx;");
105 needParens(31, "xx();");
106 needParens(32, "xx() = 3;");
107 needParens(33, "a ? xx : c");
108 needParens(34, "xx ? b : c");
109 needParens(35, "a ? b : xx");
110 needParens(36, "1 ? xx : c");
111 needParens(37, "0 ? b : xx");
112 needParens(38, "1 + xx");
113 needParens(39, "xx + 1");
114 needParens(40, "1, xx");
115 doesNotNeedParens(41, "+(xx)");
116 doesNotNeedParens(42, "!(xx)");
117 needParens(43, "xx, 1");
118 needParens(44, "[1, xx]");
119 needParens(45, "[xx, 1]");
120 needParens(46, "[#1=xx,3]");
121 needParens(47, "[#1=xx,#1#]");
122 needParens(48, "xx.p");
123 needParens(49, "xx.@p");
124 needParens(50, "typeof xx;");
125 needParens(51, "void xx;");
126 needParens(52, "({ a: xx })");
127 needParens(53, "({ a: 1, b: xx })");
128 needParens(54, "({ a: xx, b: 1 })");
129 needParens(55, "({ a getter: xx })");
130 needParens(56, "<x a={xx}/>");
131 doesNotNeedParens(57, "new (xx);");
132 doesNotNeedParens(58, "new a(xx);");
133
134
135 // Generator expressions cannot be used as LHS, even though they're syntactic 
136 // sugar for something that looks a lot like an "lvalue return": (f() = 3).
137
138 rejectLHS(59, "++ (xx);");
139 rejectLHS(60, "delete xx;");
140 rejectLHS(61, "delete (xx);");
141 rejectLHS(62, "for (xx in []) { }");
142 rejectLHS(63, "for ((xx) in []) { }");
143 rejectLHS(64, "try { } catch(xx) { }");
144 rejectLHS(65, "try { } catch([(xx)]) { }");
145 rejectLHS(66, "xx += 3;");
146 rejectLHS(67, "(xx) += 3;");
147 rejectLHS(68, "xx = 3;");
148
149 // Assignment
150 rejectLHS(69, "        (xx) = 3;");
151 rejectLHS(70, "var     (xx) = 3;");
152 rejectLHS(71, "const   (xx) = 3;");
153 rejectLHS(72, "let     (xx) = 3;");
154
155 // Destructuring assignment
156 rejectLHS(73, "        [(xx)] = 3;");
157 rejectLHS(74, "var     [(xx)] = 3;");
158 rejectLHS(75, "const   [(xx)] = 3;");
159 rejectLHS(76, "let     [(xx)] = 3;");
160
161 // Group assignment (Spidermonkey optimization for certain
162 // destructuring assignments)
163 rejectLHS(77, "        [(xx)] = [3];");
164 rejectLHS(78, "var     [(xx)] = [3];");
165 rejectLHS(79, "const   [(xx)] = [3];");
166 rejectLHS(80, "let     [(xx)] = [3];");
167
168 // Destructuring & group assignment for array comprehensions, just for kicks.
169 rejectLHS(81, "        [xx] = [3];");
170 rejectLHS(82, "var     [xx] = [3];");
171 rejectLHS(83, "const   [xx] = [3];");
172 rejectLHS(84, "let     [xx] = 3;");
173 rejectLHS(85, "        [xx] = 3;");
174 rejectLHS(86, "var     [xx] = 3;");
175 rejectLHS(87, "const   [xx] = 3;");
176 rejectLHS(88, "let     [xx] = 3;");
177
178 // This is crazy, ambiguous, and/or buggy.
179 // See https://bugzilla.mozilla.org/show_bug.cgi?id=380237#c23 et seq.
180 //doesNotNeedParens("(yield xx);");
181
182 print("Done!");
183
184 function doesNotNeedParens(section, pat)
185 {
186   print("Testing section " + section + " pattern " + pat);
187
188   var f, ft;
189   sanityCheck(section, pat);
190
191   expect = 'No Error';
192   actual = '';
193   ft = pat.replace(/xx/, genexp);
194     try {
195       f = new Function(ft);
196       actual = 'No Error';
197     } catch(e) {
198       print("Unparenthesized genexp SHOULD have been accepted here!");
199       actual = e + '';
200     }
201   reportCompare(expect, actual, summary + ': doesNotNeedParens section ' + section + ' pattern ' + pat);
202
203   roundTripTest(section, f);
204
205   // Make sure the decompilation is not over-parenthesized.
206   var uf = "" + f;
207   if (pat.indexOf("(xx)") != -1)
208     overParenTest(section, f);
209   //  else
210   //    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.")
211 }
212
213 function needParens(section, pat, exp)
214 {
215   print("Testing section " + section + " pattern " + pat);
216
217   var f, ft;
218   sanityCheck(section, pat);
219
220   expect = 'SyntaxError';
221   actual = '';
222   ft = pat.replace(/xx/, genexp);
223   try {
224     f = new Function(ft);
225     print("Unparenthesized genexp should NOT have been accepted here!");
226   } catch(e) { 
227     /* expected to throw */ 
228     actual = e.name;
229   }
230   reportCompare(expect, actual, summary + ': needParens section ' + section + ' pattern ' + pat);
231
232   expect = 'No Error';
233   actual = '';
234   ft = pat.replace(/xx/, genexpParened);
235   try {
236     f = new Function(ft);
237     actual = 'No Error';
238   } catch(e) { 
239     print("Yikes!"); 
240     actual = e + '';
241   }
242   reportCompare(expect, actual, summary + ': needParens section ' + section + ' ft ' + ft);
243
244   roundTripTest(section, f, exp);
245   overParenTest(section, f, exp);
246 }
247
248 function rejectLHS(section, pat)
249 {
250   print("Testing section " + section + " pattern " + pat);
251
252   // sanityCheck(pat); // because 'z' should be accepted as an LHS or binding
253     
254   var ft;
255     
256   expect = 'SyntaxError';
257   actual = '';
258   ft = pat.replace(/xx/, genexp)
259     try {
260       new Function(ft);
261       print("That should have been a syntax error!");
262       actual = 'No Error';
263     } catch(e) { 
264       actual = e.name;
265     }
266   reportCompare(expect, actual, summary + ': rejectLHS section ' + section);
267 }
268
269
270 function overParenTest(section, f, exp)
271 {
272   var uf = "" + f;
273   if (uf == exp)
274     return;
275
276   reportCompare(false, uf.indexOf(genexpParened) == -1, summary + 
277                 ': overParenTest genexp snugly in parentheses: section ' + section + ' uf ' + uf);
278
279   if (uf.indexOf(genexpParened) != -1) {
280     reportCompare(true, uf.indexOf(genexpParenedTwice) == -1, summary + 
281       ': overParensTest decompilation should not be over-parenthesized: section ' + ' uf ' + uf);
282   }
283 }
284
285 function sanityCheck(section, pat)
286 {
287   expect = '';
288   actual = '';
289
290   if (pat.indexOf("xx") == -1)
291   {
292     actual += "No 'xx' in this pattern? ";
293   }
294
295   var f, ft;
296   ft = pat.replace(/xx/, "z");
297   try {
298     f = new Function(ft);
299   } catch(e) { 
300     actual += "Yowzers! Probably a bogus test!";
301   }
302   reportCompare(expect, actual, summary + ': sanityCheck section ' + section + ' pattern ' + pat);
303 }
304
305 function roundTripTest(section, f, exp)
306 {
307   // Decompile
308   var uf = "" + f;
309
310   // Recompile
311   expect = 'No Error';
312   actual = '';
313   var euf;
314   try {
315     euf = eval("(" + uf + ")");
316     actual = 'No Error';
317     reportCompare(expect, actual, summary + ': roundTripTest: section ' + section + ' uf ' + uf);
318   } catch(e) {
319     actual = e + '';
320     reportCompare(expect, actual, summary + ': roundTripTest: section ' + section + ' uf ' + uf);
321     return;
322   }
323
324   // Decompile again and make sure the decompilations match exactly.
325   expect = exp || uf;
326   actual = "" + euf;
327   reportCompare(expect, actual, summary + ': roundTripTest no round-trip change: section ' + section);
328 }