c272b7484f17278e76c7dfc19511eee8f92c6671
[WebKit-https.git] / LayoutTests / fast / js / resources / function-toString-parentheses.js
1 description(
2 "This test checks that parentheses are preserved when significant, and not added where inappropriate. " +
3 "We need this test because the JavaScriptCore parser removes all parentheses and the serializer then adds them back."
4 );
5
6 function compileAndSerialize(expression)
7 {
8     var f = eval("(function () { return " + expression + "; })");
9     var serializedString = f.toString();
10     serializedString = serializedString.replace(/[ \t\r\n]+/g, " ");
11     serializedString = serializedString.replace("function () { return ", "");
12     serializedString = serializedString.replace("; }", "");
13     serializedString = serializedString.replace(/^\s*|\s*$/g, ''); // Opera adds whitespace
14     return serializedString;
15 }
16
17 function compileAndSerializeLeftmostTest(expression)
18 {
19     var f = eval("(function () { " + expression + "; })");
20     var serializedString = f.toString();
21     serializedString = serializedString.replace(/[ \t\r\n]+/g, " ");
22     serializedString = serializedString.replace("function () { ", "");
23     serializedString = serializedString.replace("; }", "");
24     serializedString = serializedString.replace(/^\s*|\s*$/g, ''); // Opera adds whitespace
25     return serializedString;
26 }
27
28 var removesExtraParentheses = compileAndSerialize("(a + b) + c") == "a + b + c";
29
30 function testLeftAssociativeSame(opA, opB)
31 {
32     shouldBe("compileAndSerialize('a " + opA + " b " + opB + " c')",
33         "'a " + opA + " b " + opB + " c'");
34     shouldBe("compileAndSerialize('(a " + opA + " b) " + opB + " c')",
35         removesExtraParentheses
36             ? "'a " + opA + " b " + opB + " c'"
37             : "'(a " + opA + " b) " + opB + " c'"
38     );
39     shouldBe("compileAndSerialize('a " + opA + " (b " + opB + " c)')",
40         "'a " + opA + " (b " + opB + " c)'");
41 }
42
43 function testRightAssociativeSame(opA, opB)
44 {
45     shouldBe("compileAndSerialize('a " + opA + " b " + opB + " c')",
46         "'a " + opA + " b " + opB + " c'");
47     shouldBe("compileAndSerialize('(a " + opA + " b) " + opB + " c')",
48         "'(a " + opA + " b) " + opB + " c'");
49     shouldBe("compileAndSerialize('a " + opA + " (b " + opB + " c)')",
50         removesExtraParentheses
51             ? "'a " + opA + " b " + opB + " c'"
52             : "'a " + opA + " (b " + opB + " c)'"
53     );
54 }
55
56 function testHigherFirst(opHigher, opLower)
57 {
58     shouldBe("compileAndSerialize('a " + opHigher + " b " + opLower + " c')",
59         "'a " + opHigher + " b " + opLower + " c'");
60     shouldBe("compileAndSerialize('(a " + opHigher + " b) " + opLower + " c')",
61         removesExtraParentheses
62             ? "'a " + opHigher + " b " + opLower + " c'"
63             : "'(a " + opHigher + " b) " + opLower + " c'"
64     );
65     shouldBe("compileAndSerialize('a " + opHigher + " (b " + opLower + " c)')",
66         "'a " + opHigher + " (b " + opLower + " c)'");
67 }
68
69 function testLowerFirst(opLower, opHigher)
70 {
71     shouldBe("compileAndSerialize('a " + opLower + " b " + opHigher + " c')",
72         "'a " + opLower + " b " + opHigher + " c'");
73     shouldBe("compileAndSerialize('(a " + opLower + " b) " + opHigher + " c')",
74         "'(a " + opLower + " b) " + opHigher + " c'");
75     shouldBe("compileAndSerialize('a " + opLower + " (b " + opHigher + " c)')",
76         removesExtraParentheses
77             ? "'a " + opLower + " b " + opHigher + " c'"
78             : "'a " + opLower + " (b " + opHigher + " c)'"
79     );
80 }
81
82 var binaryOperators = [
83     [ "*", "/", "%" ], [ "+", "-" ],
84     [ "<<", ">>", ">>>" ],
85     [ "<", ">", "<=", ">=", "instanceof", "in" ],
86     [ "==", "!=", "===", "!==" ],
87     [ "&" ], [ "^" ], [ "|" ],
88     [ "&&" ], [ "||" ]
89 ];
90
91 for (i = 0; i < binaryOperators.length; ++i) {
92     var ops = binaryOperators[i];
93     for (j = 0; j < ops.length; ++j) {
94         var op = ops[j];
95         testLeftAssociativeSame(op, op);
96         if (j != 0)
97             testLeftAssociativeSame(ops[0], op);
98         if (i < binaryOperators.length - 1) {
99             var nextOps = binaryOperators[i + 1];
100             if (j == 0)
101                 for (k = 0; k < nextOps.length; ++k)
102                     testHigherFirst(op, nextOps[k]);
103             else
104                 testHigherFirst(op, nextOps[0]);
105         }
106     }
107 }
108
109 var assignmentOperators = [ "=", "*=", "/=" , "%=", "+=", "-=", "<<=", ">>=", ">>>=", "&=", "^=", "|=" ];
110
111 for (i = 0; i < assignmentOperators.length; ++i) {
112     var op = assignmentOperators[i];
113     testRightAssociativeSame(op, op);
114     if (i != 0)
115         testRightAssociativeSame("=", op);
116     testLowerFirst(op, "+");
117     shouldThrow("compileAndSerialize('a + b " + op + " c')");
118     shouldBe("compileAndSerialize('(a + b) " + op + " c')",
119         "'(a + b) " + op + " c'");
120     shouldBe("compileAndSerialize('a + (b " + op + " c)')",
121         "'a + (b " + op + " c)'");
122 }
123
124 var prefixOperators = [ "delete", "void", "typeof", "++", "--", "+", "-", "~", "!" ];
125 var prefixOperatorSpace = [ " ", " ", " ", "", "", " ", " ", "", "" ];
126
127 for (i = 0; i < prefixOperators.length; ++i) {
128     var op = prefixOperators[i] + prefixOperatorSpace[i];
129     shouldBe("compileAndSerialize('" + op + "a + b')", "'" + op + "a + b'");
130     shouldBe("compileAndSerialize('(" + op + "a) + b')", 
131              removesExtraParentheses ?
132              "'" + op + "a + b'" :
133              "'(" + op + "a) + b'");
134     shouldBe("compileAndSerialize('" + op + "(a + b)')", "'" + op + "(a + b)'");
135     shouldBe("compileAndSerialize('!" + op + "a')", "'!" + op + "a'");
136     shouldBe("compileAndSerialize('!(" + op + "a)')", 
137              removesExtraParentheses ? "'!" + op + "a'" : "'!(" + op + "a)'");
138 }
139
140 shouldBe("compileAndSerialize('!a++')", "'!a++'");
141 shouldBe("compileAndSerialize('!(a++)')", removesExtraParentheses ? "'!a++'" : "'!(a++)'" );
142 shouldBe("compileAndSerialize('(!a)++')", "'(!a)++'");
143 shouldBe("compileAndSerialize('!a--')", "'!a--'");
144 shouldBe("compileAndSerialize('!(a--)')", removesExtraParentheses ? "'!a--'" : "'!(a--)'");
145 shouldBe("compileAndSerialize('(!a)--')", "'(!a)--'");
146
147 shouldBe("compileAndSerialize('(-1)[a]')", "'(-1)[a]'");
148 shouldBe("compileAndSerialize('(-1)[a] = b')", "'(-1)[a] = b'");
149 shouldBe("compileAndSerialize('(-1)[a] += b')", "'(-1)[a] += b'");
150 shouldBe("compileAndSerialize('(-1)[a]++')", "'(-1)[a]++'");
151 shouldBe("compileAndSerialize('++(-1)[a]')", "'++(-1)[a]'");
152 shouldBe("compileAndSerialize('(-1)[a]()')", "'(-1)[a]()'");
153
154 shouldBe("compileAndSerialize('new (-1)()')", "'new (-1)()'");
155
156 shouldBe("compileAndSerialize('(-1).a')", "'(-1).a'");
157 shouldBe("compileAndSerialize('(-1).a = b')", "'(-1).a = b'");
158 shouldBe("compileAndSerialize('(-1).a += b')", "'(-1).a += b'");
159 shouldBe("compileAndSerialize('(-1).a++')", "'(-1).a++'");
160 shouldBe("compileAndSerialize('++(-1).a')", "'++(-1).a'");
161 shouldBe("compileAndSerialize('(-1).a()')", "'(-1).a()'");
162
163 shouldBe("compileAndSerialize('(- 0)[a]')", "'(- 0)[a]'");
164 shouldBe("compileAndSerialize('(- 0)[a] = b')", "'(- 0)[a] = b'");
165 shouldBe("compileAndSerialize('(- 0)[a] += b')", "'(- 0)[a] += b'");
166 shouldBe("compileAndSerialize('(- 0)[a]++')", "'(- 0)[a]++'");
167 shouldBe("compileAndSerialize('++(- 0)[a]')", "'++(- 0)[a]'");
168 shouldBe("compileAndSerialize('(- 0)[a]()')", "'(- 0)[a]()'");
169
170 shouldBe("compileAndSerialize('new (- 0)()')", "'new (- 0)()'");
171
172 shouldBe("compileAndSerialize('(- 0).a')", "'(- 0).a'");
173 shouldBe("compileAndSerialize('(- 0).a = b')", "'(- 0).a = b'");
174 shouldBe("compileAndSerialize('(- 0).a += b')", "'(- 0).a += b'");
175 shouldBe("compileAndSerialize('(- 0).a++')", "'(- 0).a++'");
176 shouldBe("compileAndSerialize('++(- 0).a')", "'++(- 0).a'");
177 shouldBe("compileAndSerialize('(- 0).a()')", "'(- 0).a()'");
178
179 shouldBe("compileAndSerialize('(1)[a]')", removesExtraParentheses ? "'1[a]'" : "'(1)[a]'");
180 shouldBe("compileAndSerialize('(1)[a] = b')", removesExtraParentheses ? "'1[a] = b'" : "'(1)[a] = b'");
181 shouldBe("compileAndSerialize('(1)[a] += b')", removesExtraParentheses ? "'1[a] += b'" : "'(1)[a] += b'");
182 shouldBe("compileAndSerialize('(1)[a]++')", removesExtraParentheses ? "'1[a]++'" : "'(1)[a]++'");
183 shouldBe("compileAndSerialize('++(1)[a]')", removesExtraParentheses ? "'++1[a]'" : "'++(1)[a]'");
184 shouldBe("compileAndSerialize('(1)[a]()')", removesExtraParentheses ? "'1[a]()'" : "'(1)[a]()'");
185
186 shouldBe("compileAndSerialize('new (1)()')", removesExtraParentheses ? "'new 1()'" : "'new (1)()'");
187
188 shouldBe("compileAndSerialize('(1).a')", "'(1).a'");
189 shouldBe("compileAndSerialize('(1).a = b')", "'(1).a = b'");
190 shouldBe("compileAndSerialize('(1).a += b')", "'(1).a += b'");
191 shouldBe("compileAndSerialize('(1).a++')", "'(1).a++'");
192 shouldBe("compileAndSerialize('++(1).a')", "'++(1).a'");
193 shouldBe("compileAndSerialize('(1).a()')", "'(1).a()'");
194
195 for (i = 0; i < assignmentOperators.length; ++i) {
196     var op = assignmentOperators[i];
197     shouldBe("compileAndSerialize('(-1) " + op + " a')", "'(-1) " + op + " a'");
198     shouldBe("compileAndSerialize('(- 0) " + op + " a')", "'(- 0) " + op + " a'");
199     shouldBe("compileAndSerialize('1 " + op + " a')", "'1 " + op + " a'");
200 }
201
202 shouldBe("compileAndSerializeLeftmostTest('({ }).x')", "'({ }).x'");
203 shouldBe("compileAndSerializeLeftmostTest('x = { }')", "'x = { }'");
204 shouldBe("compileAndSerializeLeftmostTest('(function () { })()')", "'(function () { })()'");
205 shouldBe("compileAndSerializeLeftmostTest('x = function () { }')", "'x = function () { }'");
206
207 shouldBe("compileAndSerializeLeftmostTest('var a')", "'var a'");
208 shouldBe("compileAndSerializeLeftmostTest('var a = 1')", "'var a = 1'");
209 shouldBe("compileAndSerializeLeftmostTest('var a, b')", "'var a, b'");
210 shouldBe("compileAndSerializeLeftmostTest('var a = 1, b = 2')", "'var a = 1, b = 2'");
211 shouldBe("compileAndSerializeLeftmostTest('var a, b, c')", "'var a, b, c'");
212 shouldBe("compileAndSerializeLeftmostTest('var a = 1, b = 2, c = 3')", "'var a = 1, b = 2, c = 3'");
213
214 shouldBe("compileAndSerializeLeftmostTest('const a = 1')", "'const a = 1'");
215 shouldBe("compileAndSerializeLeftmostTest('const a = (1, 2)')", "'const a = (1, 2)'");
216 shouldBe("compileAndSerializeLeftmostTest('const a, b = 1')", "'const a, b = 1'");
217 shouldBe("compileAndSerializeLeftmostTest('const a = 1, b')", "'const a = 1, b'");
218 shouldBe("compileAndSerializeLeftmostTest('const a = 1, b = 1')", "'const a = 1, b = 1'");
219 shouldBe("compileAndSerializeLeftmostTest('const a = (1, 2), b = 1')", "'const a = (1, 2), b = 1'");
220 shouldBe("compileAndSerializeLeftmostTest('const a = 1, b = (1, 2)')", "'const a = 1, b = (1, 2)'");
221 shouldBe("compileAndSerializeLeftmostTest('const a = (1, 2), b = (1, 2)')", "'const a = (1, 2), b = (1, 2)'");
222
223 shouldBe("compileAndSerialize('(function () { new (a.b()).c })')", "'(function () { new (a.b()).c })'");
224
225 var successfullyParsed = true;