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 24description( 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 29function 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 39function 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 49var removesExtraParentheses = compileAndSerialize("(a + b) + c") == "a + b + c"; 50 51function testKeepParentheses(expression) 52{ 53 shouldBe("compileAndSerialize('" + expression + "')", 54 "'" + expression + "'"); 55} 56 57function testOptionalParentheses(expression) 58{ 59 stripped_expression = removesExtraParentheses 60 ? expression.replace(/\(/g, '').replace(/\)/g, '') 61 : expression; 62 shouldBe("compileAndSerialize('" + expression + "')", 63 "'" + stripped_expression + "'"); 64} 65 66function 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 73function 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 80function 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 87function 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 94var binaryOperators = [ 95 [ "*", "/", "%" ], [ "+", "-" ], 96 [ "<<", ">>", ">>>" ], 97 [ "<", ">", "<=", ">=", "instanceof", "in" ], 98 [ "==", "!=", "===", "!==" ], 99 [ "&" ], [ "^" ], [ "|" ], 100 [ "&&" ], [ "||" ] 101]; 102 103for (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 121var assignmentOperators = [ "=", "*=", "/=" , "%=", "+=", "-=", "<<=", ">>=", ">>>=", "&=", "^=", "|=" ]; 122 123for (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 134var prefixOperators = [ "delete", "void", "typeof", "++", "--", "+", "-", "~", "!" ]; 135var prefixOperatorSpace = [ " ", " ", " ", "", "", " ", " ", "", "" ]; 136 137for (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 147testKeepParentheses("!a++"); 148testOptionalParentheses("!(a++)"); 149testKeepParentheses("(!a)++"); 150 151testKeepParentheses("!a--"); 152testOptionalParentheses("!(a--)"); 153testKeepParentheses("(!a)--"); 154 155testKeepParentheses("(-1)[a]"); 156testKeepParentheses("(-1)[a] = b"); 157testKeepParentheses("(-1)[a] += b"); 158testKeepParentheses("(-1)[a]++"); 159testKeepParentheses("++(-1)[a]"); 160testKeepParentheses("(-1)[a]()"); 161 162testKeepParentheses("new (-1)()"); 163 164testKeepParentheses("(-1).a"); 165testKeepParentheses("(-1).a = b"); 166testKeepParentheses("(-1).a += b"); 167testKeepParentheses("(-1).a++"); 168testKeepParentheses("++(-1).a"); 169testKeepParentheses("(-1).a()"); 170 171testKeepParentheses("(- 0)[a]"); 172testKeepParentheses("(- 0)[a] = b"); 173testKeepParentheses("(- 0)[a] += b"); 174testKeepParentheses("(- 0)[a]++"); 175testKeepParentheses("++(- 0)[a]"); 176testKeepParentheses("(- 0)[a]()"); 177 178testKeepParentheses("new (- 0)()"); 179 180testKeepParentheses("(- 0).a"); 181testKeepParentheses("(- 0).a = b"); 182testKeepParentheses("(- 0).a += b"); 183testKeepParentheses("(- 0).a++"); 184testKeepParentheses("++(- 0).a"); 185testKeepParentheses("(- 0).a()"); 186 187testOptionalParentheses("(1)[a]"); 188testOptionalParentheses("(1)[a] = b"); 189testOptionalParentheses("(1)[a] += b"); 190testOptionalParentheses("(1)[a]++"); 191testOptionalParentheses("++(1)[a]"); 192 193shouldBe("compileAndSerialize('(1)[a]()')", 194 removesExtraParentheses ? "'1[a]()'" : "'(1)[a]()'"); 195 196shouldBe("compileAndSerialize('new (1)()')", 197 removesExtraParentheses ? "'new 1()'" : "'new (1)()'"); 198 199testKeepParentheses("(1).a"); 200testKeepParentheses("(1).a = b"); 201testKeepParentheses("(1).a += b"); 202testKeepParentheses("(1).a++"); 203testKeepParentheses("++(1).a"); 204testKeepParentheses("(1).a()"); 205 206for (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 213shouldBe("compileAndSerializeLeftmostTest('({ }).x')", "'({ }).x'"); 214shouldBe("compileAndSerializeLeftmostTest('x = { }')", "'x = { }'"); 215shouldBe("compileAndSerializeLeftmostTest('(function () { })()')", "'(function () { })()'"); 216shouldBe("compileAndSerializeLeftmostTest('x = function () { }')", "'x = function () { }'"); 217 218shouldBe("compileAndSerializeLeftmostTest('var a')", "'var a'"); 219shouldBe("compileAndSerializeLeftmostTest('var a = 1')", "'var a = 1'"); 220shouldBe("compileAndSerializeLeftmostTest('var a, b')", "'var a, b'"); 221shouldBe("compileAndSerializeLeftmostTest('var a = 1, b = 2')", "'var a = 1, b = 2'"); 222shouldBe("compileAndSerializeLeftmostTest('var a, b, c')", "'var a, b, c'"); 223shouldBe("compileAndSerializeLeftmostTest('var a = 1, b = 2, c = 3')", "'var a = 1, b = 2, c = 3'"); 224 225shouldBe("compileAndSerializeLeftmostTest('const a = 1')", "'const a = 1'"); 226shouldBe("compileAndSerializeLeftmostTest('const a = (1, 2)')", "'const a = (1, 2)'"); 227shouldBe("compileAndSerializeLeftmostTest('const a, b = 1')", "'const a, b = 1'"); 228shouldBe("compileAndSerializeLeftmostTest('const a = 1, b')", "'const a = 1, b'"); 229shouldBe("compileAndSerializeLeftmostTest('const a = 1, b = 1')", "'const a = 1, b = 1'"); 230shouldBe("compileAndSerializeLeftmostTest('const a = (1, 2), b = 1')", "'const a = (1, 2), b = 1'"); 231shouldBe("compileAndSerializeLeftmostTest('const a = 1, b = (1, 2)')", "'const a = 1, b = (1, 2)'"); 232shouldBe("compileAndSerializeLeftmostTest('const a = (1, 2), b = (1, 2)')", "'const a = (1, 2), b = (1, 2)'"); 233 234shouldBe("compileAndSerialize('(function () { new (a.b()).c })')", "'(function () { new (a.b()).c })'"); 235