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