blob: 8f9079912e165389016676c5644a3a5b1a769065 [file] [log] [blame]
description(
"This test checks that parentheses are preserved when significant, and not added where inappropriate. " +
"We need this test because the JavaScriptCore parser removes all parentheses and the serializer then adds them back."
);
function compileAndSerialize(expression)
{
var f = eval("(function () { return " + expression + "; })");
var serializedString = f.toString();
serializedString = serializedString.replace(/[ \t\r\n]+/g, " ");
serializedString = serializedString.replace("function () { return ", "");
serializedString = serializedString.replace("; }", "");
serializedString = serializedString.replace(/^\s*|\s*$/g, ''); // Opera adds whitespace
return serializedString;
}
function compileAndSerializeLeftmostTest(expression)
{
var f = eval("(function () { " + expression + "; })");
var serializedString = f.toString();
serializedString = serializedString.replace(/[ \t\r\n]+/g, " ");
serializedString = serializedString.replace("function () { ", "");
serializedString = serializedString.replace("; }", "");
serializedString = serializedString.replace(/^\s*|\s*$/g, ''); // Opera adds whitespace
return serializedString;
}
var removesExtraParentheses = compileAndSerialize("(a + b) + c") == "a + b + c";
function testLeftAssociativeSame(opA, opB)
{
shouldBe("compileAndSerialize('a " + opA + " b " + opB + " c')",
"'a " + opA + " b " + opB + " c'");
shouldBe("compileAndSerialize('(a " + opA + " b) " + opB + " c')",
removesExtraParentheses
? "'a " + opA + " b " + opB + " c'"
: "'(a " + opA + " b) " + opB + " c'"
);
shouldBe("compileAndSerialize('a " + opA + " (b " + opB + " c)')",
"'a " + opA + " (b " + opB + " c)'");
}
function testRightAssociativeSame(opA, opB)
{
shouldBe("compileAndSerialize('a " + opA + " b " + opB + " c')",
"'a " + opA + " b " + opB + " c'");
shouldBe("compileAndSerialize('(a " + opA + " b) " + opB + " c')",
"'(a " + opA + " b) " + opB + " c'");
shouldBe("compileAndSerialize('a " + opA + " (b " + opB + " c)')",
removesExtraParentheses
? "'a " + opA + " b " + opB + " c'"
: "'a " + opA + " (b " + opB + " c)'"
);
}
function testHigherFirst(opHigher, opLower)
{
shouldBe("compileAndSerialize('a " + opHigher + " b " + opLower + " c')",
"'a " + opHigher + " b " + opLower + " c'");
shouldBe("compileAndSerialize('(a " + opHigher + " b) " + opLower + " c')",
removesExtraParentheses
? "'a " + opHigher + " b " + opLower + " c'"
: "'(a " + opHigher + " b) " + opLower + " c'"
);
shouldBe("compileAndSerialize('a " + opHigher + " (b " + opLower + " c)')",
"'a " + opHigher + " (b " + opLower + " c)'");
}
function testLowerFirst(opLower, opHigher)
{
shouldBe("compileAndSerialize('a " + opLower + " b " + opHigher + " c')",
"'a " + opLower + " b " + opHigher + " c'");
shouldBe("compileAndSerialize('(a " + opLower + " b) " + opHigher + " c')",
"'(a " + opLower + " b) " + opHigher + " c'");
shouldBe("compileAndSerialize('a " + opLower + " (b " + opHigher + " c)')",
removesExtraParentheses
? "'a " + opLower + " b " + opHigher + " c'"
: "'a " + opLower + " (b " + opHigher + " c)'"
);
}
var binaryOperators = [
[ "*", "/", "%" ], [ "+", "-" ],
[ "<<", ">>", ">>>" ],
[ "<", ">", "<=", ">=", "instanceof", "in" ],
[ "==", "!=", "===", "!==" ],
[ "&" ], [ "^" ], [ "|" ],
[ "&&" ], [ "||" ]
];
for (i = 0; i < binaryOperators.length; ++i) {
var ops = binaryOperators[i];
for (j = 0; j < ops.length; ++j) {
var op = ops[j];
testLeftAssociativeSame(op, op);
if (j != 0)
testLeftAssociativeSame(ops[0], op);
if (i < binaryOperators.length - 1) {
var nextOps = binaryOperators[i + 1];
if (j == 0)
for (k = 0; k < nextOps.length; ++k)
testHigherFirst(op, nextOps[k]);
else
testHigherFirst(op, nextOps[0]);
}
}
}
var assignmentOperators = [ "=", "*=", "/=" , "%=", "+=", "-=", "<<=", ">>=", ">>>=", "&=", "^=", "|=" ];
for (i = 0; i < assignmentOperators.length; ++i) {
var op = assignmentOperators[i];
testRightAssociativeSame(op, op);
if (i != 0)
testRightAssociativeSame("=", op);
testLowerFirst(op, "+");
shouldThrow("compileAndSerialize('a + b " + op + " c')");
shouldBe("compileAndSerialize('(a + b) " + op + " c')",
"'(a + b) " + op + " c'");
shouldBe("compileAndSerialize('a + (b " + op + " c)')",
"'a + (b " + op + " c)'");
}
var prefixOperators = [ "delete", "void", "typeof", "++", "--", "+", "-", "~", "!" ];
var prefixOperatorSpace = [ " ", " ", " ", "", "", " ", " ", "", "" ];
for (i = 0; i < prefixOperators.length; ++i) {
var op = prefixOperators[i] + prefixOperatorSpace[i];
shouldBe("compileAndSerialize('" + op + "a + b')", "'" + op + "a + b'");
shouldBe("compileAndSerialize('(" + op + "a) + b')",
removesExtraParentheses ?
"'" + op + "a + b'" :
"'(" + op + "a) + b'");
shouldBe("compileAndSerialize('" + op + "(a + b)')", "'" + op + "(a + b)'");
shouldBe("compileAndSerialize('!" + op + "a')", "'!" + op + "a'");
shouldBe("compileAndSerialize('!(" + op + "a)')",
removesExtraParentheses ? "'!" + op + "a'" : "'!(" + op + "a)'");
}
shouldBe("compileAndSerialize('!a++')", "'!a++'");
shouldBe("compileAndSerialize('!(a++)')", removesExtraParentheses ? "'!a++'" : "'!(a++)'" );
shouldBe("compileAndSerialize('(!a)++')", "'(!a)++'");
shouldBe("compileAndSerialize('!a--')", "'!a--'");
shouldBe("compileAndSerialize('!(a--)')", removesExtraParentheses ? "'!a--'" : "'!(a--)'");
shouldBe("compileAndSerialize('(!a)--')", "'(!a)--'");
shouldBe("compileAndSerialize('(-1)[a]')", "'(-1)[a]'");
shouldBe("compileAndSerialize('(-1)[a] = b')", "'(-1)[a] = b'");
shouldBe("compileAndSerialize('(-1)[a] += b')", "'(-1)[a] += b'");
shouldBe("compileAndSerialize('(-1)[a]++')", "'(-1)[a]++'");
shouldBe("compileAndSerialize('++(-1)[a]')", "'++(-1)[a]'");
shouldBe("compileAndSerialize('(-1)[a]()')", "'(-1)[a]()'");
shouldBe("compileAndSerialize('new (-1)()')", "'new (-1)()'");
shouldBe("compileAndSerialize('(-1).a')", "'(-1).a'");
shouldBe("compileAndSerialize('(-1).a = b')", "'(-1).a = b'");
shouldBe("compileAndSerialize('(-1).a += b')", "'(-1).a += b'");
shouldBe("compileAndSerialize('(-1).a++')", "'(-1).a++'");
shouldBe("compileAndSerialize('++(-1).a')", "'++(-1).a'");
shouldBe("compileAndSerialize('(-1).a()')", "'(-1).a()'");
shouldBe("compileAndSerialize('(- 0)[a]')", "'(- 0)[a]'");
shouldBe("compileAndSerialize('(- 0)[a] = b')", "'(- 0)[a] = b'");
shouldBe("compileAndSerialize('(- 0)[a] += b')", "'(- 0)[a] += b'");
shouldBe("compileAndSerialize('(- 0)[a]++')", "'(- 0)[a]++'");
shouldBe("compileAndSerialize('++(- 0)[a]')", "'++(- 0)[a]'");
shouldBe("compileAndSerialize('(- 0)[a]()')", "'(- 0)[a]()'");
shouldBe("compileAndSerialize('new (- 0)()')", "'new (- 0)()'");
shouldBe("compileAndSerialize('(- 0).a')", "'(- 0).a'");
shouldBe("compileAndSerialize('(- 0).a = b')", "'(- 0).a = b'");
shouldBe("compileAndSerialize('(- 0).a += b')", "'(- 0).a += b'");
shouldBe("compileAndSerialize('(- 0).a++')", "'(- 0).a++'");
shouldBe("compileAndSerialize('++(- 0).a')", "'++(- 0).a'");
shouldBe("compileAndSerialize('(- 0).a()')", "'(- 0).a()'");
shouldBe("compileAndSerialize('(1)[a]')", removesExtraParentheses ? "'1[a]'" : "'(1)[a]'");
shouldBe("compileAndSerialize('(1)[a] = b')", removesExtraParentheses ? "'1[a] = b'" : "'(1)[a] = b'");
shouldBe("compileAndSerialize('(1)[a] += b')", removesExtraParentheses ? "'1[a] += b'" : "'(1)[a] += b'");
shouldBe("compileAndSerialize('(1)[a]++')", removesExtraParentheses ? "'1[a]++'" : "'(1)[a]++'");
shouldBe("compileAndSerialize('++(1)[a]')", removesExtraParentheses ? "'++1[a]'" : "'++(1)[a]'");
shouldBe("compileAndSerialize('(1)[a]()')", removesExtraParentheses ? "'1[a]()'" : "'(1)[a]()'");
shouldBe("compileAndSerialize('new (1)()')", removesExtraParentheses ? "'new 1()'" : "'new (1)()'");
shouldBe("compileAndSerialize('(1).a')", "'(1).a'");
shouldBe("compileAndSerialize('(1).a = b')", "'(1).a = b'");
shouldBe("compileAndSerialize('(1).a += b')", "'(1).a += b'");
shouldBe("compileAndSerialize('(1).a++')", "'(1).a++'");
shouldBe("compileAndSerialize('++(1).a')", "'++(1).a'");
shouldBe("compileAndSerialize('(1).a()')", "'(1).a()'");
for (i = 0; i < assignmentOperators.length; ++i) {
var op = assignmentOperators[i];
shouldBe("compileAndSerialize('(-1) " + op + " a')", "'(-1) " + op + " a'");
shouldBe("compileAndSerialize('(- 0) " + op + " a')", "'(- 0) " + op + " a'");
shouldBe("compileAndSerialize('1 " + op + " a')", "'1 " + op + " a'");
}
shouldBe("compileAndSerializeLeftmostTest('({ }).x')", "'({ }).x'");
shouldBe("compileAndSerializeLeftmostTest('x = { }')", "'x = { }'");
shouldBe("compileAndSerializeLeftmostTest('(function () { })()')", "'(function () { })()'");
shouldBe("compileAndSerializeLeftmostTest('x = function () { }')", "'x = function () { }'");
shouldBe("compileAndSerializeLeftmostTest('var a')", "'var a'");
shouldBe("compileAndSerializeLeftmostTest('var a = 1')", "'var a = 1'");
shouldBe("compileAndSerializeLeftmostTest('var a, b')", "'var a, b'");
shouldBe("compileAndSerializeLeftmostTest('var a = 1, b = 2')", "'var a = 1, b = 2'");
shouldBe("compileAndSerializeLeftmostTest('var a, b, c')", "'var a, b, c'");
shouldBe("compileAndSerializeLeftmostTest('var a = 1, b = 2, c = 3')", "'var a = 1, b = 2, c = 3'");
shouldBe("compileAndSerializeLeftmostTest('const a = 1')", "'const a = 1'");
shouldBe("compileAndSerializeLeftmostTest('const a = (1, 2)')", "'const a = (1, 2)'");
shouldBe("compileAndSerializeLeftmostTest('const a, b = 1')", "'const a, b = 1'");
shouldBe("compileAndSerializeLeftmostTest('const a = 1, b')", "'const a = 1, b'");
shouldBe("compileAndSerializeLeftmostTest('const a = 1, b = 1')", "'const a = 1, b = 1'");
shouldBe("compileAndSerializeLeftmostTest('const a = (1, 2), b = 1')", "'const a = (1, 2), b = 1'");
shouldBe("compileAndSerializeLeftmostTest('const a = 1, b = (1, 2)')", "'const a = 1, b = (1, 2)'");
shouldBe("compileAndSerializeLeftmostTest('const a = (1, 2), b = (1, 2)')", "'const a = (1, 2), b = (1, 2)'");
var successfullyParsed = true;