diff --git a/escodegen.js b/escodegen.js index ec612d1f..16a05b17 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 @@ -1831,14 +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; } - fragment = this.generateExpression(expr.left, currentPrecedence, flags); + fragment = this.generateExpression(expr.left, leftPrecedence, flags); leftSource = fragment.toString(); @@ -1848,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.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..99f90256 --- /dev/null +++ b/test/compare-acorn-es7/exponentiation-precedence.expected.js @@ -0,0 +1,9 @@ +x ** y * z; +x ** (y * z); +(x * y) ** z; +x * y ** z; +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 new file mode 100644 index 00000000..4a35c41b --- /dev/null +++ b/test/compare-acorn-es7/exponentiation-precedence.js @@ -0,0 +1,12 @@ +(x ** y) * z; +x ** (y * z); + +(x * y) ** z; +x * (y ** z); + +x ** (y ** z); +(x ** y) ** z; + +(-1) ** 0; +a++ ** b; +0 ** (-1);