OLD | NEW |
(Empty) | |
| 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 var gTestfile = 'regress-380237-04.js'; |
| 39 //----------------------------------------------------------------------------- |
| 40 var BUGNUMBER = 380237; |
| 41 var summary = 'Generator expressions parenthesization test'; |
| 42 var actual = ''; |
| 43 var expect = ''; |
| 44 |
| 45 |
| 46 /* |
| 47 |
| 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 |
| 50 a way to test that: |
| 51 |
| 52 1) unparenthesized genexps are allowed in some places and the |
| 53 decompilation is sane and not over-parenthesized |
| 54 |
| 55 2) unparenthesized genexps are disallowed in many places and when |
| 56 there are parens, the decompilation is sane and not over-parenthesized |
| 57 |
| 58 */ |
| 59 |
| 60 // |genexp| must have the exact same whitespace the decompiler uses |
| 61 genexp = "x * x for (x in [])"; |
| 62 genexpParened = "(" + genexp + ")"; |
| 63 genexpParenedTwice = "(" + genexpParened + ")"; |
| 64 |
| 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! |
| 68 |
| 69 // Statements |
| 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"); |
| 88 |
| 89 // Function calls |
| 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);"); |
| 96 |
| 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);"); |
| 101 |
| 102 // Expressions |
| 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);"); |
| 134 |
| 135 |
| 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). |
| 138 |
| 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;"); |
| 149 |
| 150 // Assignment |
| 151 rejectLHS(69, " (xx) = 3;"); |
| 152 rejectLHS(70, "var (xx) = 3;"); |
| 153 rejectLHS(71, "const (xx) = 3;"); |
| 154 rejectLHS(72, "let (xx) = 3;"); |
| 155 |
| 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;"); |
| 161 |
| 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];"); |
| 168 |
| 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;"); |
| 178 |
| 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);"); |
| 182 |
| 183 print("Done!"); |
| 184 |
| 185 function doesNotNeedParens(section, pat) |
| 186 { |
| 187 print("Testing section " + section + " pattern " + pat); |
| 188 |
| 189 var f, ft; |
| 190 sanityCheck(section, pat); |
| 191 |
| 192 expect = 'No Error'; |
| 193 actual = ''; |
| 194 ft = pat.replace(/xx/, genexp); |
| 195 try { |
| 196 f = new Function(ft); |
| 197 actual = 'No Error'; |
| 198 } catch(e) { |
| 199 print("Unparenthesized genexp SHOULD have been accepted here!"); |
| 200 actual = e + ''; |
| 201 } |
| 202 reportCompare(expect, actual, summary + ': doesNotNeedParens section ' + secti
on + ' pattern ' + pat); |
| 203 |
| 204 roundTripTest(section, f); |
| 205 |
| 206 // Make sure the decompilation is not over-parenthesized. |
| 207 var uf = "" + f; |
| 208 if (pat.indexOf("(xx)") != -1) |
| 209 overParenTest(section, f); |
| 210 // else |
| 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 a
round it.") |
| 212 } |
| 213 |
| 214 function needParens(section, pat, exp) |
| 215 { |
| 216 print("Testing section " + section + " pattern " + pat); |
| 217 |
| 218 var f, ft; |
| 219 sanityCheck(section, pat); |
| 220 |
| 221 expect = 'SyntaxError'; |
| 222 actual = ''; |
| 223 ft = pat.replace(/xx/, genexp); |
| 224 try { |
| 225 f = new Function(ft); |
| 226 print("Unparenthesized genexp should NOT have been accepted here!"); |
| 227 } catch(e) { |
| 228 /* expected to throw */ |
| 229 actual = e.name; |
| 230 } |
| 231 reportCompare(expect, actual, summary + ': needParens section ' + section + '
pattern ' + pat); |
| 232 |
| 233 expect = 'No Error'; |
| 234 actual = ''; |
| 235 ft = pat.replace(/xx/, genexpParened); |
| 236 try { |
| 237 f = new Function(ft); |
| 238 actual = 'No Error'; |
| 239 } catch(e) { |
| 240 print("Yikes!"); |
| 241 actual = e + ''; |
| 242 } |
| 243 reportCompare(expect, actual, summary + ': needParens section ' + section + '
ft ' + ft); |
| 244 |
| 245 roundTripTest(section, f, exp); |
| 246 overParenTest(section, f, exp); |
| 247 } |
| 248 |
| 249 function rejectLHS(section, pat) |
| 250 { |
| 251 print("Testing section " + section + " pattern " + pat); |
| 252 |
| 253 // sanityCheck(pat); // because 'z' should be accepted as an LHS or binding |
| 254 |
| 255 var ft; |
| 256 |
| 257 expect = 'SyntaxError'; |
| 258 actual = ''; |
| 259 ft = pat.replace(/xx/, genexp) |
| 260 try { |
| 261 new Function(ft); |
| 262 print("That should have been a syntax error!"); |
| 263 actual = 'No Error'; |
| 264 } catch(e) { |
| 265 actual = e.name; |
| 266 } |
| 267 reportCompare(expect, actual, summary + ': rejectLHS section ' + section); |
| 268 } |
| 269 |
| 270 |
| 271 function overParenTest(section, f, exp) |
| 272 { |
| 273 var uf = "" + f; |
| 274 if (uf == exp) |
| 275 return; |
| 276 |
| 277 if (uf.indexOf(genexp) == -1) { |
| 278 print('openParenTest: section ' + section + ' expected ' + exp + ' uf ' + uf
+ ' genexp optimized away'); |
| 279 return; |
| 280 } |
| 281 |
| 282 reportCompare(false, uf.indexOf(genexpParened) == -1, summary + |
| 283 ': overParenTest genexp snugly in parentheses: section ' + secti
on + ' uf ' + uf); |
| 284 |
| 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); |
| 288 } |
| 289 } |
| 290 |
| 291 function sanityCheck(section, pat) |
| 292 { |
| 293 expect = ''; |
| 294 actual = ''; |
| 295 |
| 296 if (pat.indexOf("xx") == -1) |
| 297 { |
| 298 actual += "No 'xx' in this pattern? "; |
| 299 } |
| 300 |
| 301 var f, ft; |
| 302 ft = pat.replace(/xx/, "z"); |
| 303 try { |
| 304 f = new Function(ft); |
| 305 } catch(e) { |
| 306 actual += "Yowzers! Probably a bogus test!"; |
| 307 } |
| 308 reportCompare(expect, actual, summary + ': sanityCheck section ' + section + '
pattern ' + pat); |
| 309 } |
| 310 |
| 311 function roundTripTest(section, f, exp) |
| 312 { |
| 313 // Decompile |
| 314 var uf = "" + f; |
| 315 |
| 316 // Recompile |
| 317 expect = 'No Error'; |
| 318 actual = ''; |
| 319 var euf; |
| 320 try { |
| 321 euf = eval("(" + uf + ")"); |
| 322 actual = 'No Error'; |
| 323 reportCompare(expect, actual, summary + ': roundTripTest: section ' + sectio
n + ' uf ' + uf); |
| 324 } catch(e) { |
| 325 actual = e + ''; |
| 326 reportCompare(expect, actual, summary + ': roundTripTest: section ' + sectio
n + ' uf ' + uf); |
| 327 return; |
| 328 } |
| 329 |
| 330 // Decompile again and make sure the decompilations match exactly. |
| 331 expect = exp || uf; |
| 332 actual = "" + euf; |
| 333 reportCompare(expect, actual, summary + ': roundTripTest no round-trip change:
section ' + section); |
| 334 } |
OLD | NEW |