From 62cb3952470a82e24ea08a966639cdf59d46ad85 Mon Sep 17 00:00:00 2001 From: sanex3339 Date: Wed, 29 Jan 2020 23:02:03 +0300 Subject: [PATCH 1/3] Fixed exponentiation operator precedence --- escodegen.js | 20 ++-- test/compare-acorn-es7.js | 92 +++++++++++++++++++ .../exponentiation-precedence.expected.js | 6 ++ .../exponentiation-precedence.js | 6 ++ 4 files changed, 115 insertions(+), 9 deletions(-) create mode 100644 test/compare-acorn-es7.js create mode 100644 test/compare-acorn-es7/exponentiation-precedence.expected.js create mode 100644 test/compare-acorn-es7/exponentiation-precedence.js diff --git a/escodegen.js b/escodegen.js index ec612d1f..97f61116 100644 --- a/escodegen.js +++ b/escodegen.js @@ -95,14 +95,15 @@ BitwiseSHIFT: 10, Additive: 11, Multiplicative: 12, - Await: 13, - Unary: 13, - Postfix: 14, - Call: 15, - New: 16, - TaggedTemplate: 17, - Member: 18, - Primary: 19 + Exponentiation: 13, + Await: 14, + Unary: 14, + Postfix: 15, + Call: 16, + New: 17, + TaggedTemplate: 18, + Member: 19, + Primary: 20 }; BinaryPrecedence = { @@ -130,7 +131,8 @@ '-': Precedence.Additive, '*': Precedence.Multiplicative, '%': Precedence.Multiplicative, - '/': Precedence.Multiplicative + '/': Precedence.Multiplicative, + '**': Precedence.Exponentiation }; //Flags diff --git a/test/compare-acorn-es7.js b/test/compare-acorn-es7.js new file mode 100644 index 00000000..ee7b2405 --- /dev/null +++ b/test/compare-acorn-es7.js @@ -0,0 +1,92 @@ +/* + Copyright (C) 2012-2013 Yusuke Suzuki + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +'use strict'; + +var fs = require('fs'), + acorn = require('acorn'), + escodegen = require('./loader'), + chai = require('chai'), + expect = chai.expect; + +function test(code, expected) { + var tree, actual, options, StringObject; + + // alias, so that JSLint does not complain. + StringObject = String; + + options = { + ranges: true, + locations: false, + ecmaVersion: 7 + }; + + tree = acorn.parse(code, options); + + // for UNIX text comment + actual = escodegen.generate(tree).replace(/[\n\r]$/, '') + '\n'; + expect(actual).to.be.equal(expected); +} + +function testMin(code, expected) { + var tree, actual, options, StringObject; + + // alias, so that JSLint does not complain. + StringObject = String; + + options = { + ranges: true, + locations: false, + ecmaVersion: 7 + }; + + tree = acorn.parse(code, options); + + // for UNIX text comment + actual = escodegen.generate(tree, { + format: escodegen.FORMAT_MINIFY, + raw: false + }).replace(/[\n\r]$/, '') + '\n'; + expect(actual).to.be.equal(expected); +} + +describe('compare acorn es7 test', function () { + fs.readdirSync(__dirname + '/compare-acorn-es7').sort().forEach(function(file) { + var code, expected, exp, min; + if (/\.js$/.test(file) && !/expected\.js$/.test(file) && !/expected\.min\.js$/.test(file)) { + it(file, function () { + exp = file.replace(/\.js$/, '.expected.js'); + min = file.replace(/\.js$/, '.expected.min.js'); + code = fs.readFileSync(__dirname + '/compare-acorn-es7/' + file, 'utf-8'); + expected = fs.readFileSync(__dirname + '/compare-acorn-es7/' + exp, 'utf-8'); + test(code, expected); + if (fs.existsSync(__dirname + '/compare-acorn-es7/' + min)) { + expected = fs.readFileSync(__dirname + '/compare-acorn-es7/' + min, 'utf-8'); + testMin(code, expected); + } + }); + } + }); +}); +/* vim: set sw=4 ts=4 et tw=80 : */ diff --git a/test/compare-acorn-es7/exponentiation-precedence.expected.js b/test/compare-acorn-es7/exponentiation-precedence.expected.js new file mode 100644 index 00000000..109abbd6 --- /dev/null +++ b/test/compare-acorn-es7/exponentiation-precedence.expected.js @@ -0,0 +1,6 @@ +x ** y * z; +x ** (y * z); +(x * y) ** z; +x * y ** z; +x ** y * z; +x * y ** z; diff --git a/test/compare-acorn-es7/exponentiation-precedence.js b/test/compare-acorn-es7/exponentiation-precedence.js new file mode 100644 index 00000000..9f8219d4 --- /dev/null +++ b/test/compare-acorn-es7/exponentiation-precedence.js @@ -0,0 +1,6 @@ +(x ** y) * z; +x ** (y * z); +(x * y) ** z; +x * (y ** z); +x ** y * z; +x * y ** z; From 60c92d9b0f1fff41266d3821a78b9a4695afc249 Mon Sep 17 00:00:00 2001 From: sanex3339 Date: Sat, 1 Feb 2020 13:12:37 +0300 Subject: [PATCH 2/3] Fixed and added test cases for LHS expression of exponentiation operator --- escodegen.js | 8 +++++++- .../exponentiation-precedence.expected.js | 4 ++++ test/compare-acorn-es7/exponentiation-precedence.js | 4 ++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/escodegen.js b/escodegen.js index 97f61116..2d017076 100644 --- a/escodegen.js +++ b/escodegen.js @@ -1840,7 +1840,13 @@ flags |= F_ALLOW_IN; } - fragment = this.generateExpression(expr.left, currentPrecedence, flags); + if (expr.operator === '**' && expr.left.operator) { + var leftExpressionPrecedence = BinaryPrecedence[expr.left.operator]; + + fragment = ['(', this.generateExpression(expr.left, leftExpressionPrecedence), ')']; + } else { + fragment = this.generateExpression(expr.left, currentPrecedence, flags); + } leftSource = fragment.toString(); diff --git a/test/compare-acorn-es7/exponentiation-precedence.expected.js b/test/compare-acorn-es7/exponentiation-precedence.expected.js index 109abbd6..0e531945 100644 --- a/test/compare-acorn-es7/exponentiation-precedence.expected.js +++ b/test/compare-acorn-es7/exponentiation-precedence.expected.js @@ -4,3 +4,7 @@ x ** (y * z); x * y ** z; x ** y * z; x * y ** z; +var foo = (-1) ** 0; +var foo = 0 ** -1; +var foo = 1 ** 0; +var foo = 0 ** 1; diff --git a/test/compare-acorn-es7/exponentiation-precedence.js b/test/compare-acorn-es7/exponentiation-precedence.js index 9f8219d4..084dccc8 100644 --- a/test/compare-acorn-es7/exponentiation-precedence.js +++ b/test/compare-acorn-es7/exponentiation-precedence.js @@ -4,3 +4,7 @@ x ** (y * z); x * (y ** z); x ** y * z; x * y ** z; +var foo = (-1) ** 0; +var foo = 0 ** (-1); +var foo = (1) ** 0; +var foo = 0 ** (1); \ No newline at end of file From 35e77393dc72106d01dbf7f34d48c30c0cde8e9a Mon Sep 17 00:00:00 2001 From: Michael Ficarra Date: Wed, 5 Feb 2020 07:53:40 -1000 Subject: [PATCH 3/3] fix exponentiation PR --- escodegen.js | 14 +++++--------- .../exponentiation-precedence.expected.js | 11 +++++------ .../compare-acorn-es7/exponentiation-precedence.js | 14 ++++++++------ 3 files changed, 18 insertions(+), 21 deletions(-) diff --git a/escodegen.js b/escodegen.js index 2d017076..16a05b17 100644 --- a/escodegen.js +++ b/escodegen.js @@ -1833,20 +1833,16 @@ }, BinaryExpression: function (expr, precedence, flags) { - var result, currentPrecedence, fragment, leftSource; + var result, leftPrecedence, rightPrecedence, currentPrecedence, fragment, leftSource; currentPrecedence = BinaryPrecedence[expr.operator]; + leftPrecedence = expr.operator === '**' ? Precedence.Postfix : currentPrecedence + 1; + rightPrecedence = expr.operator === '**' ? currentPrecedence : currentPrecedence + 1; if (currentPrecedence < precedence) { flags |= F_ALLOW_IN; } - if (expr.operator === '**' && expr.left.operator) { - var leftExpressionPrecedence = BinaryPrecedence[expr.left.operator]; - - fragment = ['(', this.generateExpression(expr.left, leftExpressionPrecedence), ')']; - } else { - fragment = this.generateExpression(expr.left, currentPrecedence, flags); - } + fragment = this.generateExpression(expr.left, leftPrecedence, flags); leftSource = fragment.toString(); @@ -1856,7 +1852,7 @@ result = join(fragment, expr.operator); } - fragment = this.generateExpression(expr.right, currentPrecedence + 1, flags); + fragment = this.generateExpression(expr.right, rightPrecedence, flags); if (expr.operator === '/' && fragment.toString().charAt(0) === '/' || expr.operator.slice(-1) === '<' && fragment.toString().slice(0, 3) === '!--') { diff --git a/test/compare-acorn-es7/exponentiation-precedence.expected.js b/test/compare-acorn-es7/exponentiation-precedence.expected.js index 0e531945..99f90256 100644 --- a/test/compare-acorn-es7/exponentiation-precedence.expected.js +++ b/test/compare-acorn-es7/exponentiation-precedence.expected.js @@ -2,9 +2,8 @@ x ** y * z; x ** (y * z); (x * y) ** z; x * y ** z; -x ** y * z; -x * y ** z; -var foo = (-1) ** 0; -var foo = 0 ** -1; -var foo = 1 ** 0; -var foo = 0 ** 1; +x ** y ** z; +(x ** y) ** z; +(-1) ** 0; +a++ ** b; +0 ** -1; diff --git a/test/compare-acorn-es7/exponentiation-precedence.js b/test/compare-acorn-es7/exponentiation-precedence.js index 084dccc8..4a35c41b 100644 --- a/test/compare-acorn-es7/exponentiation-precedence.js +++ b/test/compare-acorn-es7/exponentiation-precedence.js @@ -1,10 +1,12 @@ (x ** y) * z; x ** (y * z); + (x * y) ** z; x * (y ** z); -x ** y * z; -x * y ** z; -var foo = (-1) ** 0; -var foo = 0 ** (-1); -var foo = (1) ** 0; -var foo = 0 ** (1); \ No newline at end of file + +x ** (y ** z); +(x ** y) ** z; + +(-1) ** 0; +a++ ** b; +0 ** (-1);