Home | History | Annotate | Download | only in js
      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