// |reftest| skip-if(!xulRuntime.shell) /* * Any copyright is dedicated to the Public Domain. * http://creativecommons.org/licenses/publicdomain/ */ var BUGNUMBER = 1135708; var summary = "Implement the exponentiation operator"; print(BUGNUMBER + ": " + summary); // Constant folding assertEq(2 ** 2 ** 3, 256); assertEq(1 ** 1 ** 4, 1); // No folding var two = 2; var three = 3; var four = 4; assertEq(two ** two ** three, 256); assertEq(1 ** 1 ** four, 1); // Operator precedence assertEq(2 ** 3 / 2 ** 3, 1); assertEq(2 ** 3 * 2 ** 3, 64); assertEq(2 ** 3 + 2 ** 3, 16); // With parentheses assertEq((2 ** 3) ** 2, 64); assertEq(2 ** (3 ** 2), 512); // Assignment operator var x = 2; assertEq(x **= 2 ** 3, 256); assertEq(x, 256); // Loop to test baseline and ION for (var i=0; i<10000; i++) { assertEq((2 ** 3) ** 2, 64); assertEq(2 ** (3 ** 2), 512); var x = 2; assertEq(x **= 2 ** 3, 256); assertEq(x, 256); } // Comments should not be confused with exp operator var a, c, e; a = c = e = 2; assertEq(a**/**b**/c/**/**/**d**/e, 16); // Two stars separated should not parse as exp operator assertThrowsInstanceOf(function() { return Reflect.parse("2 * * 3"); }, SyntaxError); // Left-hand side expression must not be a unary expression. for (let unaryOp of ["delete", "typeof", "void", "+", "-", "!", "~"]) { assertThrowsInstanceOf(() => eval(unaryOp + " a ** 2"), SyntaxError); assertThrowsInstanceOf(() => eval(unaryOp + " " + unaryOp + " a ** 2"), SyntaxError); } // Test the other |delete| operators (DELETENAME and DELETEEXPR are already tested above). assertThrowsInstanceOf(() => eval("delete a.name ** 2"), SyntaxError); assertThrowsInstanceOf(() => eval("delete a[0] ** 2"), SyntaxError); // Unary expression lhs is valid if parenthesized. for (let unaryOp of ["delete", "void", "+", "-", "!", "~"]) { let a = 0; eval("(" + unaryOp + " a) ** 2"); eval("(" + unaryOp + " " + unaryOp + " a) ** 2"); } { let a = {}; (delete a.name) ** 2; (delete a[0]) ** 2; } // Check if error propagation works var thrower = { get value() { throw new Error(); } }; assertThrowsInstanceOf(function() { return thrower.value ** 2; }, Error); assertThrowsInstanceOf(function() { return 2 ** thrower.value; }, Error); assertThrowsInstanceOf(function() { return 2 ** thrower.value ** 2; }, Error); var convertibleToPrimitive = { valueOf: function() { throw new Error("oops"); } }; assertThrowsInstanceOf(function() { return convertibleToPrimitive ** 3; }, Error); assertThrowsInstanceOf(function() { return 3 ** convertibleToPrimitive; }, Error); assertEq(NaN ** 2, NaN); assertEq(2 ** NaN, NaN); assertEq(2 ** "3", 8); assertEq("2" ** 3, 8); // Reflect.parse generates a correct parse tree for simplest case var parseTree = Reflect.parse("a ** b"); assertEq(parseTree.body[0].type, "ExpressionStatement"); assertEq(parseTree.body[0].expression.operator, "**"); assertEq(parseTree.body[0].expression.left.name, "a"); assertEq(parseTree.body[0].expression.right.name, "b"); // Reflect.parse generates a tree following the right-associativity rule var parseTree = Reflect.parse("a ** b ** c"); assertEq(parseTree.body[0].type, "ExpressionStatement"); assertEq(parseTree.body[0].expression.left.name, "a"); assertEq(parseTree.body[0].expression.right.operator, "**"); assertEq(parseTree.body[0].expression.right.left.name, "b"); assertEq(parseTree.body[0].expression.right.right.name, "c"); if (typeof reportCompare === "function") reportCompare(true, true);