1 // Copyright 2013 the V8 project authors. All rights reserved. 2 // Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions 6 // are met: 7 // 1. Redistributions of source code must retain the above copyright 8 // notice, this list of conditions and the following disclaimer. 9 // 2. Redistributions in binary form must reproduce the above copyright 10 // notice, this list of conditions and the following disclaimer in the 11 // documentation and/or other materials provided with the distribution. 12 // 13 // THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY 14 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 // DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY 17 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 24 description( 25 "This test checks that parentheses are preserved when significant, and not added where inappropriate. " + 26 "We need this test because the JavaScriptCore parser removes all parentheses and the serializer then adds them back." 27 ); 28 29 function compileAndSerialize(expression) 30 { 31 var f = eval("(function () { return " + expression + "; })"); 32 var serializedString = f.toString(); 33 serializedString = serializedString.replace(/[ \t\r\n]+/g, " "); 34 serializedString = serializedString.replace("function () { return ", ""); 35 serializedString = serializedString.replace("; }", ""); 36 return serializedString; 37 } 38 39 function compileAndSerializeLeftmostTest(expression) 40 { 41 var f = eval("(function () { " + expression + "; })"); 42 var serializedString = f.toString(); 43 serializedString = serializedString.replace(/[ \t\r\n]+/g, " "); 44 serializedString = serializedString.replace("function () { ", ""); 45 serializedString = serializedString.replace("; }", ""); 46 return serializedString; 47 } 48 49 var removesExtraParentheses = compileAndSerialize("(a + b) + c") == "a + b + c"; 50 51 function testKeepParentheses(expression) 52 { 53 shouldBe("compileAndSerialize('" + expression + "')", 54 "'" + expression + "'"); 55 } 56 57 function testOptionalParentheses(expression) 58 { 59 stripped_expression = removesExtraParentheses 60 ? expression.replace(/\(/g, '').replace(/\)/g, '') 61 : expression; 62 shouldBe("compileAndSerialize('" + expression + "')", 63 "'" + stripped_expression + "'"); 64 } 65 66 function testLeftAssociativeSame(opA, opB) 67 { 68 testKeepParentheses("a " + opA + " b " + opB + " c"); 69 testOptionalParentheses("(a " + opA + " b) " + opB + " c"); 70 testKeepParentheses("a " + opA + " (b " + opB + " c)"); 71 } 72 73 function testRightAssociativeSame(opA, opB) 74 { 75 testKeepParentheses("a " + opA + " b " + opB + " c"); 76 testKeepParentheses("(a " + opA + " b) " + opB + " c"); 77 testOptionalParentheses("a " + opA + " (b " + opB + " c)"); 78 } 79 80 function testHigherFirst(opHigher, opLower) 81 { 82 testKeepParentheses("a " + opHigher + " b " + opLower + " c"); 83 testOptionalParentheses("(a " + opHigher + " b) " + opLower + " c"); 84 testKeepParentheses("a " + opHigher + " (b " + opLower + " c)"); 85 } 86 87 function testLowerFirst(opLower, opHigher) 88 { 89 testKeepParentheses("a " + opLower + " b " + opHigher + " c"); 90 testKeepParentheses("(a " + opLower + " b) " + opHigher + " c"); 91 testOptionalParentheses("a " + opLower + " (b " + opHigher + " c)"); 92 } 93 94 var binaryOperators = [ 95 [ "*", "/", "%" ], [ "+", "-" ], 96 [ "<<", ">>", ">>>" ], 97 [ "<", ">", "<=", ">=", "instanceof", "in" ], 98 [ "==", "!=", "===", "!==" ], 99 [ "&" ], [ "^" ], [ "|" ], 100 [ "&&" ], [ "||" ] 101 ]; 102 103 for (i = 0; i < binaryOperators.length; ++i) { 104 var ops = binaryOperators[i]; 105 for (j = 0; j < ops.length; ++j) { 106 var op = ops[j]; 107 testLeftAssociativeSame(op, op); 108 if (j != 0) 109 testLeftAssociativeSame(ops[0], op); 110 if (i < binaryOperators.length - 1) { 111 var nextOps = binaryOperators[i + 1]; 112 if (j == 0) 113 for (k = 0; k < nextOps.length; ++k) 114 testHigherFirst(op, nextOps[k]); 115 else 116 testHigherFirst(op, nextOps[0]); 117 } 118 } 119 } 120 121 var assignmentOperators = [ "=", "*=", "/=" , "%=", "+=", "-=", "<<=", ">>=", ">>>=", "&=", "^=", "|=" ]; 122 123 for (i = 0; i < assignmentOperators.length; ++i) { 124 var op = assignmentOperators[i]; 125 testRightAssociativeSame(op, op); 126 if (i != 0) 127 testRightAssociativeSame("=", op); 128 testLowerFirst(op, "+"); 129 shouldThrow("compileAndSerialize('a + b " + op + " c')"); 130 testKeepParentheses("(a + b) " + op + " c"); 131 testKeepParentheses("a + (b " + op + " c)"); 132 } 133 134 var prefixOperators = [ "delete", "void", "typeof", "++", "--", "+", "-", "~", "!" ]; 135 var prefixOperatorSpace = [ " ", " ", " ", "", "", " ", " ", "", "" ]; 136 137 for (i = 0; i < prefixOperators.length; ++i) { 138 var op = prefixOperators[i] + prefixOperatorSpace[i]; 139 testKeepParentheses("" + op + "a + b"); 140 testOptionalParentheses("(" + op + "a) + b"); 141 testKeepParentheses("" + op + "(a + b)"); 142 testKeepParentheses("!" + op + "a"); 143 testOptionalParentheses("!(" + op + "a)"); 144 } 145 146 147 testKeepParentheses("!a++"); 148 testOptionalParentheses("!(a++)"); 149 testKeepParentheses("(!a)++"); 150 151 testKeepParentheses("!a--"); 152 testOptionalParentheses("!(a--)"); 153 testKeepParentheses("(!a)--"); 154 155 testKeepParentheses("(-1)[a]"); 156 testKeepParentheses("(-1)[a] = b"); 157 testKeepParentheses("(-1)[a] += b"); 158 testKeepParentheses("(-1)[a]++"); 159 testKeepParentheses("++(-1)[a]"); 160 testKeepParentheses("(-1)[a]()"); 161 162 testKeepParentheses("new (-1)()"); 163 164 testKeepParentheses("(-1).a"); 165 testKeepParentheses("(-1).a = b"); 166 testKeepParentheses("(-1).a += b"); 167 testKeepParentheses("(-1).a++"); 168 testKeepParentheses("++(-1).a"); 169 testKeepParentheses("(-1).a()"); 170 171 testKeepParentheses("(- 0)[a]"); 172 testKeepParentheses("(- 0)[a] = b"); 173 testKeepParentheses("(- 0)[a] += b"); 174 testKeepParentheses("(- 0)[a]++"); 175 testKeepParentheses("++(- 0)[a]"); 176 testKeepParentheses("(- 0)[a]()"); 177 178 testKeepParentheses("new (- 0)()"); 179 180 testKeepParentheses("(- 0).a"); 181 testKeepParentheses("(- 0).a = b"); 182 testKeepParentheses("(- 0).a += b"); 183 testKeepParentheses("(- 0).a++"); 184 testKeepParentheses("++(- 0).a"); 185 testKeepParentheses("(- 0).a()"); 186 187 testOptionalParentheses("(1)[a]"); 188 testOptionalParentheses("(1)[a] = b"); 189 testOptionalParentheses("(1)[a] += b"); 190 testOptionalParentheses("(1)[a]++"); 191 testOptionalParentheses("++(1)[a]"); 192 193 shouldBe("compileAndSerialize('(1)[a]()')", 194 removesExtraParentheses ? "'1[a]()'" : "'(1)[a]()'"); 195 196 shouldBe("compileAndSerialize('new (1)()')", 197 removesExtraParentheses ? "'new 1()'" : "'new (1)()'"); 198 199 testKeepParentheses("(1).a"); 200 testKeepParentheses("(1).a = b"); 201 testKeepParentheses("(1).a += b"); 202 testKeepParentheses("(1).a++"); 203 testKeepParentheses("++(1).a"); 204 testKeepParentheses("(1).a()"); 205 206 for (i = 0; i < assignmentOperators.length; ++i) { 207 var op = assignmentOperators[i]; 208 testKeepParentheses("(-1) " + op + " a"); 209 testKeepParentheses("(- 0) " + op + " a"); 210 testKeepParentheses("1 " + op + " a"); 211 } 212 213 shouldBe("compileAndSerializeLeftmostTest('({ }).x')", "'({ }).x'"); 214 shouldBe("compileAndSerializeLeftmostTest('x = { }')", "'x = { }'"); 215 shouldBe("compileAndSerializeLeftmostTest('(function () { })()')", "'(function () { })()'"); 216 shouldBe("compileAndSerializeLeftmostTest('x = function () { }')", "'x = function () { }'"); 217 218 shouldBe("compileAndSerializeLeftmostTest('var a')", "'var a'"); 219 shouldBe("compileAndSerializeLeftmostTest('var a = 1')", "'var a = 1'"); 220 shouldBe("compileAndSerializeLeftmostTest('var a, b')", "'var a, b'"); 221 shouldBe("compileAndSerializeLeftmostTest('var a = 1, b = 2')", "'var a = 1, b = 2'"); 222 shouldBe("compileAndSerializeLeftmostTest('var a, b, c')", "'var a, b, c'"); 223 shouldBe("compileAndSerializeLeftmostTest('var a = 1, b = 2, c = 3')", "'var a = 1, b = 2, c = 3'"); 224 225 shouldBe("compileAndSerializeLeftmostTest('const a = 1')", "'const a = 1'"); 226 shouldBe("compileAndSerializeLeftmostTest('const a = (1, 2)')", "'const a = (1, 2)'"); 227 shouldBe("compileAndSerializeLeftmostTest('const a, b = 1')", "'const a, b = 1'"); 228 shouldBe("compileAndSerializeLeftmostTest('const a = 1, b')", "'const a = 1, b'"); 229 shouldBe("compileAndSerializeLeftmostTest('const a = 1, b = 1')", "'const a = 1, b = 1'"); 230 shouldBe("compileAndSerializeLeftmostTest('const a = (1, 2), b = 1')", "'const a = (1, 2), b = 1'"); 231 shouldBe("compileAndSerializeLeftmostTest('const a = 1, b = (1, 2)')", "'const a = 1, b = (1, 2)'"); 232 shouldBe("compileAndSerializeLeftmostTest('const a = (1, 2), b = (1, 2)')", "'const a = (1, 2), b = (1, 2)'"); 233 234 shouldBe("compileAndSerialize('(function () { new (a.b()).c })')", "'(function () { new (a.b()).c })'"); 235