2007-05-26 09:10:20 -07:00
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/ * * * * * * B E G I N L I C E N S E B L O C K * * * * *
* 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
2008-10-30 15:17:35 -07:00
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" ) ;
2007-05-26 09:10:20 -07:00
// Function calls
2008-10-30 15:17:35 -07:00
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);" ) ;
2007-05-26 09:10:20 -07:00
// eval is special and often confuses the decompiler.
2008-10-30 15:17:35 -07:00
doesNotNeedParens ( 25 , "eval(xx);" ) ;
needParens ( 26 , "eval(xx, 1);" ) ;
needParens ( 27 , "eval(1, xx);" ) ;
2007-05-26 09:10:20 -07:00
// Expressions
2008-10-30 15:17:35 -07:00
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);" ) ;
2007-05-26 09:10:20 -07:00
// 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).
2008-10-30 15:17:35 -07:00
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;" ) ;
2007-05-26 09:10:20 -07:00
// Assignment
2008-10-30 15:17:35 -07:00
rejectLHS ( 69 , " (xx) = 3;" ) ;
rejectLHS ( 70 , "var (xx) = 3;" ) ;
rejectLHS ( 71 , "const (xx) = 3;" ) ;
rejectLHS ( 72 , "let (xx) = 3;" ) ;
2007-05-26 09:10:20 -07:00
// Destructuring assignment
2008-10-30 15:17:35 -07:00
rejectLHS ( 73 , " [(xx)] = 3;" ) ;
rejectLHS ( 74 , "var [(xx)] = 3;" ) ;
rejectLHS ( 75 , "const [(xx)] = 3;" ) ;
rejectLHS ( 76 , "let [(xx)] = 3;" ) ;
2007-05-26 09:10:20 -07:00
// Group assignment (Spidermonkey optimization for certain
// destructuring assignments)
2008-10-30 15:17:35 -07:00
rejectLHS ( 77 , " [(xx)] = [3];" ) ;
rejectLHS ( 78 , "var [(xx)] = [3];" ) ;
rejectLHS ( 79 , "const [(xx)] = [3];" ) ;
rejectLHS ( 80 , "let [(xx)] = [3];" ) ;
2007-05-26 09:10:20 -07:00
// Destructuring & group assignment for array comprehensions, just for kicks.
2008-10-30 15:17:35 -07:00
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;" ) ;
2007-05-26 09:10:20 -07:00
// 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!" ) ;
2008-10-30 15:17:35 -07:00
function doesNotNeedParens ( section , pat )
2007-05-26 09:10:20 -07:00
{
2008-10-30 15:17:35 -07:00
print ( "Testing section " + section + " pattern " + pat ) ;
2007-05-26 09:10:20 -07:00
var f , ft ;
2008-10-30 15:17:35 -07:00
sanityCheck ( section , pat ) ;
2007-05-26 09:10:20 -07:00
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 + '' ;
}
2008-10-30 15:17:35 -07:00
reportCompare ( expect , actual , summary + ': doesNotNeedParens section ' + section + ' pattern ' + pat ) ;
2007-05-26 09:10:20 -07:00
2008-10-30 15:17:35 -07:00
roundTripTest ( section , f ) ;
2007-05-26 09:10:20 -07:00
// Make sure the decompilation is not over-parenthesized.
var uf = "" + f ;
if ( pat . indexOf ( "(xx)" ) != - 1 )
2008-10-30 15:17:35 -07:00
overParenTest ( section , f ) ;
2007-05-26 09:10:20 -07:00
// 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.")
}
2008-10-30 15:17:35 -07:00
function needParens ( section , pat , exp )
2007-05-26 09:10:20 -07:00
{
2008-10-30 15:17:35 -07:00
print ( "Testing section " + section + " pattern " + pat ) ;
2007-05-26 09:10:20 -07:00
var f , ft ;
2008-10-30 15:17:35 -07:00
sanityCheck ( section , pat ) ;
2007-05-26 09:10:20 -07:00
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 ;
}
2008-10-30 15:17:35 -07:00
reportCompare ( expect , actual , summary + ': needParens section ' + section + ' pattern ' + pat ) ;
2007-05-26 09:10:20 -07:00
expect = 'No Error' ;
actual = '' ;
ft = pat . replace ( /xx/ , genexpParened ) ;
try {
f = new Function ( ft ) ;
actual = 'No Error' ;
} catch ( e ) {
print ( "Yikes!" ) ;
actual = e + '' ;
}
2008-10-30 15:17:35 -07:00
reportCompare ( expect , actual , summary + ': needParens section ' + section + ' ft ' + ft ) ;
2007-05-26 09:10:20 -07:00
2008-10-30 15:17:35 -07:00
roundTripTest ( section , f , exp ) ;
overParenTest ( section , f , exp ) ;
2007-05-26 09:10:20 -07:00
}
2008-10-30 15:17:35 -07:00
function rejectLHS ( section , pat )
2007-05-26 09:10:20 -07:00
{
2008-10-30 15:17:35 -07:00
print ( "Testing section " + section + " pattern " + pat ) ;
2007-05-26 09:10:20 -07:00
// 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 ;
}
2008-10-30 15:17:35 -07:00
reportCompare ( expect , actual , summary + ': rejectLHS section ' + section ) ;
2007-05-26 09:10:20 -07:00
}
2008-10-30 15:17:35 -07:00
function overParenTest ( section , f , exp )
2007-05-26 09:10:20 -07:00
{
var uf = "" + f ;
2008-07-01 13:05:11 -07:00
if ( uf == exp )
return ;
2007-05-26 09:10:20 -07:00
reportCompare ( false , uf . indexOf ( genexpParened ) == - 1 , summary +
2008-10-30 15:17:35 -07:00
': overParenTest genexp snugly in parentheses: section ' + section + ' uf ' + uf ) ;
2007-05-26 09:10:20 -07:00
if ( uf . indexOf ( genexpParened ) != - 1 ) {
reportCompare ( true , uf . indexOf ( genexpParenedTwice ) == - 1 , summary +
2008-10-30 15:17:35 -07:00
': overParensTest decompilation should not be over-parenthesized: section ' + ' uf ' + uf ) ;
2007-05-26 09:10:20 -07:00
}
}
2008-10-30 15:17:35 -07:00
function sanityCheck ( section , pat )
2007-05-26 09:10:20 -07:00
{
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!" ;
}
2008-10-30 15:17:35 -07:00
reportCompare ( expect , actual , summary + ': sanityCheck section ' + section + ' pattern ' + pat ) ;
2007-05-26 09:10:20 -07:00
}
2008-10-30 15:17:35 -07:00
function roundTripTest ( section , f , exp )
2007-05-26 09:10:20 -07:00
{
// Decompile
var uf = "" + f ;
// Recompile
expect = 'No Error' ;
actual = '' ;
var euf ;
try {
euf = eval ( "(" + uf + ")" ) ;
actual = 'No Error' ;
2008-10-30 15:17:35 -07:00
reportCompare ( expect , actual , summary + ': roundTripTest: section ' + section + ' uf ' + uf ) ;
2007-05-26 09:10:20 -07:00
} catch ( e ) {
actual = e + '' ;
2008-10-30 15:17:35 -07:00
reportCompare ( expect , actual , summary + ': roundTripTest: section ' + section + ' uf ' + uf ) ;
2007-05-26 09:10:20 -07:00
return ;
}
// Decompile again and make sure the decompilations match exactly.
2008-07-01 13:05:11 -07:00
expect = exp || uf ;
2007-05-26 09:10:20 -07:00
actual = "" + euf ;
2008-10-30 15:17:35 -07:00
reportCompare ( expect , actual , summary + ': roundTripTest no round-trip change: section ' + section ) ;
2007-05-26 09:10:20 -07:00
}