Skip to content

Commit a25d531

Browse files
Exponentiation operator (estools#407)
* Fixed exponentiation operator precedence * Fixed and added test cases for LHS expression of exponentiation operator * fix exponentiation PR Co-authored-by: Michael Ficarra <github@michael.ficarra.me>
1 parent ba40e5c commit a25d531

File tree

4 files changed

+129
-12
lines changed

4 files changed

+129
-12
lines changed

escodegen.js

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,15 @@
9595
BitwiseSHIFT: 10,
9696
Additive: 11,
9797
Multiplicative: 12,
98-
Await: 13,
99-
Unary: 13,
100-
Postfix: 14,
101-
Call: 15,
102-
New: 16,
103-
TaggedTemplate: 17,
104-
Member: 18,
105-
Primary: 19
98+
Exponentiation: 13,
99+
Await: 14,
100+
Unary: 14,
101+
Postfix: 15,
102+
Call: 16,
103+
New: 17,
104+
TaggedTemplate: 18,
105+
Member: 19,
106+
Primary: 20
106107
};
107108

108109
BinaryPrecedence = {
@@ -130,7 +131,8 @@
130131
'-': Precedence.Additive,
131132
'*': Precedence.Multiplicative,
132133
'%': Precedence.Multiplicative,
133-
'/': Precedence.Multiplicative
134+
'/': Precedence.Multiplicative,
135+
'**': Precedence.Exponentiation
134136
};
135137

136138
//Flags
@@ -1831,14 +1833,16 @@
18311833
},
18321834

18331835
BinaryExpression: function (expr, precedence, flags) {
1834-
var result, currentPrecedence, fragment, leftSource;
1836+
var result, leftPrecedence, rightPrecedence, currentPrecedence, fragment, leftSource;
18351837
currentPrecedence = BinaryPrecedence[expr.operator];
1838+
leftPrecedence = expr.operator === '**' ? Precedence.Postfix : currentPrecedence + 1;
1839+
rightPrecedence = expr.operator === '**' ? currentPrecedence : currentPrecedence + 1;
18361840

18371841
if (currentPrecedence < precedence) {
18381842
flags |= F_ALLOW_IN;
18391843
}
18401844

1841-
fragment = this.generateExpression(expr.left, currentPrecedence, flags);
1845+
fragment = this.generateExpression(expr.left, leftPrecedence, flags);
18421846

18431847
leftSource = fragment.toString();
18441848

@@ -1848,7 +1852,7 @@
18481852
result = join(fragment, expr.operator);
18491853
}
18501854

1851-
fragment = this.generateExpression(expr.right, currentPrecedence + 1, flags);
1855+
fragment = this.generateExpression(expr.right, rightPrecedence, flags);
18521856

18531857
if (expr.operator === '/' && fragment.toString().charAt(0) === '/' ||
18541858
expr.operator.slice(-1) === '<' && fragment.toString().slice(0, 3) === '!--') {

test/compare-acorn-es7.js

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
Copyright (C) 2012-2013 Yusuke Suzuki <utatane.tea@gmail.com>
3+
4+
Redistribution and use in source and binary forms, with or without
5+
modification, are permitted provided that the following conditions are met:
6+
7+
* Redistributions of source code must retain the above copyright
8+
notice, this list of conditions and the following disclaimer.
9+
* Redistributions in binary form must reproduce the above copyright
10+
notice, this list of conditions and the following disclaimer in the
11+
documentation and/or other materials provided with the distribution.
12+
13+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16+
ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
17+
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18+
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20+
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22+
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23+
*/
24+
25+
'use strict';
26+
27+
var fs = require('fs'),
28+
acorn = require('acorn'),
29+
escodegen = require('./loader'),
30+
chai = require('chai'),
31+
expect = chai.expect;
32+
33+
function test(code, expected) {
34+
var tree, actual, options, StringObject;
35+
36+
// alias, so that JSLint does not complain.
37+
StringObject = String;
38+
39+
options = {
40+
ranges: true,
41+
locations: false,
42+
ecmaVersion: 7
43+
};
44+
45+
tree = acorn.parse(code, options);
46+
47+
// for UNIX text comment
48+
actual = escodegen.generate(tree).replace(/[\n\r]$/, '') + '\n';
49+
expect(actual).to.be.equal(expected);
50+
}
51+
52+
function testMin(code, expected) {
53+
var tree, actual, options, StringObject;
54+
55+
// alias, so that JSLint does not complain.
56+
StringObject = String;
57+
58+
options = {
59+
ranges: true,
60+
locations: false,
61+
ecmaVersion: 7
62+
};
63+
64+
tree = acorn.parse(code, options);
65+
66+
// for UNIX text comment
67+
actual = escodegen.generate(tree, {
68+
format: escodegen.FORMAT_MINIFY,
69+
raw: false
70+
}).replace(/[\n\r]$/, '') + '\n';
71+
expect(actual).to.be.equal(expected);
72+
}
73+
74+
describe('compare acorn es7 test', function () {
75+
fs.readdirSync(__dirname + '/compare-acorn-es7').sort().forEach(function(file) {
76+
var code, expected, exp, min;
77+
if (/\.js$/.test(file) && !/expected\.js$/.test(file) && !/expected\.min\.js$/.test(file)) {
78+
it(file, function () {
79+
exp = file.replace(/\.js$/, '.expected.js');
80+
min = file.replace(/\.js$/, '.expected.min.js');
81+
code = fs.readFileSync(__dirname + '/compare-acorn-es7/' + file, 'utf-8');
82+
expected = fs.readFileSync(__dirname + '/compare-acorn-es7/' + exp, 'utf-8');
83+
test(code, expected);
84+
if (fs.existsSync(__dirname + '/compare-acorn-es7/' + min)) {
85+
expected = fs.readFileSync(__dirname + '/compare-acorn-es7/' + min, 'utf-8');
86+
testMin(code, expected);
87+
}
88+
});
89+
}
90+
});
91+
});
92+
/* vim: set sw=4 ts=4 et tw=80 : */
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
x ** y * z;
2+
x ** (y * z);
3+
(x * y) ** z;
4+
x * y ** z;
5+
x ** y ** z;
6+
(x ** y) ** z;
7+
(-1) ** 0;
8+
a++ ** b;
9+
0 ** -1;
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
(x ** y) * z;
2+
x ** (y * z);
3+
4+
(x * y) ** z;
5+
x * (y ** z);
6+
7+
x ** (y ** z);
8+
(x ** y) ** z;
9+
10+
(-1) ** 0;
11+
a++ ** b;
12+
0 ** (-1);

0 commit comments

Comments
 (0)