Add exponentiation operator

This commit is contained in:
Anthony Van de Gejuchte
2016-06-18 00:25:18 +02:00
committed by Richard van Velzen
parent 2246c79318
commit 6eaeb19a4a
6 changed files with 190 additions and 4 deletions

View File

@@ -1088,6 +1088,7 @@ merge(Compressor.prototype, {
case "^" : return ev(left, c) ^ ev(right, c);
case "+" : return ev(left, c) + ev(right, c);
case "*" : return ev(left, c) * ev(right, c);
case "**" : return Math.pow(ev(left, c), ev(right, c));
case "/" : return ev(left, c) / ev(right, c);
case "%" : return ev(left, c) % ev(right, c);
case "-" : return ev(left, c) - ev(right, c);

View File

@@ -538,7 +538,13 @@ function OutputStream(options) {
PARENS([ AST_Unary, AST_Undefined ], function(output){
var p = output.parent();
return p instanceof AST_PropAccess && p.expression === this
|| p instanceof AST_New;
|| p instanceof AST_New
|| p instanceof AST_Binary
&& p.operator === "**"
&& this instanceof AST_UnaryPrefix
&& p.left === this
&& this.operator !== "++"
&& this.operator !== "--";
});
PARENS(AST_Seq, function(output){

View File

@@ -80,6 +80,7 @@ var OPERATORS = makePredicate([
"|",
"^",
"*",
"**",
"/",
"%",
">>",
@@ -99,6 +100,7 @@ var OPERATORS = makePredicate([
"-=",
"/=",
"*=",
"**=",
"%=",
">>=",
"<<=",
@@ -694,7 +696,7 @@ var UNARY_PREFIX = makePredicate([
var UNARY_POSTFIX = makePredicate([ "--", "++" ]);
var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]);
var ASSIGNMENT = makePredicate([ "=", "+=", "-=", "/=", "*=", "**=", "%=", ">>=", "<<=", ">>>=", "|=", "^=", "&=" ]);
var PRECEDENCE = (function(a, ret){
for (var i = 0; i < a.length; ++i) {
@@ -715,7 +717,8 @@ var PRECEDENCE = (function(a, ret){
["<", ">", "<=", ">=", "in", "instanceof"],
[">>", "<<", ">>>"],
["+", "-"],
["*", "/", "%"]
["*", "/", "%"],
["**"]
],
{}
);
@@ -2015,8 +2018,12 @@ function parse($TEXT, options) {
var expr_op = function(left, min_prec, no_in) {
var op = is("operator") ? S.token.value : null;
if (op == "in" && no_in) op = null;
if (op == "**" && left instanceof AST_UnaryPrefix
&& left.end === S.prev /* unary token in front not allowed, but allowed if prev is for example `)` */
&& left.operator !== "--" && left.operator !== "++")
unexpected(left.start);
var prec = op != null ? PRECEDENCE[op] : null;
if (prec != null && prec > min_prec) {
if (prec != null && (prec > min_prec || (op === "**" && min_prec === prec))) {
next();
var right = expr_op(maybe_unary(true), prec, no_in);
return expr_op(new AST_Binary({

View File

@@ -37,3 +37,91 @@ positive_zero: {
);
}
}
pow: {
options = { evaluate: true }
input: {
var a = 5 ** 3;
}
expect: {
var a = 125;
}
}
pow_sequence: {
options = {
evaluate: true
}
input: {
var a = 2 ** 3 ** 2;
}
expect: {
var a = 512;
}
}
pow_mixed: {
options = {
evaluate: true
}
input: {
var a = 5 + 2 ** 3 + 5;
var b = 5 * 3 ** 2;
var c = 5 ** 3 * 2;
var d = 5 ** +3;
}
expect: {
var a = 18;
var b = 45;
var c = 250;
var d = 125;
}
}
pow_with_right_side_evaluating_to_unary: {
options = {
evaluate: true
}
input: {
var a = (4 - 7) ** foo;
var b = ++bar ** 3;
var c = --baz ** 2;
}
expect_exact: "var a=(-3)**foo;var b=++bar**3;var c=--baz**2;"
}
pow_with_number_constants: {
options = {
evaluate: true
}
input: {
var a = 5 ** NaN; /* NaN exponent results to NaN */
var b = 42 ** +0; /* +0 exponent results to NaN */
var c = 42 ** -0; /* -0 exponent results to NaN */
var d = NaN ** 1; /* NaN with non-zero exponent is NaN */
var e = 2 ** Infinity; /* abs(base) > 1 with Infinity as exponent is Infinity */
var f = 2 ** -Infinity; /* abs(base) > 1 with -Infinity as exponent is +0 */
var g = (-7) ** (0.5);
var h = 2324334 ** 34343443;
var i = (-2324334) ** 34343443;
var j = 2 ** (-3);
var k = 2.0 ** -3;
var l = 2.0 ** (5 - 7);
var m = 3 ** -10; // Result will be 0.000016935087808430286, which is too long
}
expect: {
var a = NaN;
var b = 1;
var c = 1;
var d = NaN;
var e = Infinity;
var f = 0;
var g = NaN;
var h = Infinity;
var i = -Infinity;
var j = .125;
var k = .125;
var l = .25;
var m = 3 ** -10;
}
}

View File

@@ -0,0 +1,52 @@
pow: {
input: {
var a = 2 ** 7;
var b = 3;
b **= 2;
}
expect: {
var a = 2 ** 7;
var b = 3;
b **= 2;
}
}
pow_with_number_constants: {
input: {
var a = 5 ** NaN;
var b = 42 ** +0;
var c = 42 ** -0;
var d = NaN ** 1;
var e = 2 ** Infinity;
var f = 2 ** -Infinity;
}
expect: {
var a = 5 ** NaN;
var b = 42 ** +0;
var c = 42 ** -0;
var d = NaN ** 1;
var e = 2 ** (1/0);
var f = 2 ** -(1/0);
}
}
pow_with_parentheses: {
input: {
var g = (-7) ** (0.5);
var h = 2324334 ** 34343443;
var i = (-2324334) ** 34343443;
var j = 2 ** (-3);
var k = 2.0 ** -3;
var l = 2.0 ** (5 - 7);
}
expect_exact: "var g=(-7)**.5;var h=2324334**34343443;var i=(-2324334)**34343443;var j=2**-3;var k=2**-3;var l=2**(5-7);"
}
pow_with_unary_between_brackets: {
input: {
var a = (-(+5)) ** 3;
}
expect: {
var a = (-+5)**3;
}
}

32
test/mocha/expression.js Normal file
View File

@@ -0,0 +1,32 @@
var assert = require("assert");
var uglify = require("../../");
describe("Expression", function() {
it("Should not allow the first exponentiation operator to be prefixed with an unary operator", function() {
var tests = [
"+5 ** 3",
"-5 ** 3",
"~5 ** 3",
"!5 ** 3",
"void 5 ** 3",
"typeof 5 ** 3",
"delete 5 ** 3",
"var a = -(5) ** 3;"
];
var fail = function(e) {
return e instanceof uglify.JS_Parse_Error &&
/^SyntaxError: Unexpected token: operator \((?:[!+~-]|void|typeof|delete)\)/.test(e.message);
}
var exec = function(test) {
return function() {
uglify.parse(test);
}
}
for (var i = 0; i < tests.length; i++) {
assert.throws(exec(tests[i]), fail, tests[i]);
}
});
});