Skip to content

Commit

Permalink
Add support for ** under ecmaVersion 7
Browse files Browse the repository at this point in the history
This adds support for the exponentiation operator, which is currently
Stage 4 for ES7. The supported operators are ** and **=.

Fixes #381
  • Loading branch information
nzakas authored and marijnh committed Feb 9, 2016
1 parent bed0042 commit a8ce3a1
Show file tree
Hide file tree
Showing 7 changed files with 318 additions and 8 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ object referring to that same position.
[estree]: https://github.com/estree/estree

- **ecmaVersion**: Indicates the ECMAScript version to parse. Must be
either 3, 5, or 6. This influences support for strict mode, the set
either 3, 5, 6, or 7. This influences support for strict mode, the set
of reserved words, and support for new syntax features. Default is 5.

- **sourceType**: Indicate the mode the code should be parsed in. Can be
Expand Down Expand Up @@ -304,7 +304,7 @@ The `bin/acorn` utility can be used to parse a file from the command
line. It accepts as arguments its input file and the following
options:

- `--ecma3|--ecma5|--ecma6`: Sets the ECMAScript version to parse. Default is
- `--ecma3|--ecma5|--ecma6|--ecma7`: Sets the ECMAScript version to parse. Default is
version 5.

- `--module`: Sets the parsing mode to `"module"`. Is set to `"script"` otherwise.
Expand Down
3 changes: 2 additions & 1 deletion src/bin/acorn.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const options = {}

function help(status) {
const print = (status == 0) ? console.log : console.error
print("usage: " + basename(process.argv[1]) + " [--ecma3|--ecma5|--ecma6]")
print("usage: " + basename(process.argv[1]) + " [--ecma3|--ecma5|--ecma6|--ecma7]")
print(" [--tokenize] [--locations] [---allow-hash-bang] [--compact] [--silent] [--module] [--help] [--] [infile]")
process.exit(status)
}
Expand All @@ -21,6 +21,7 @@ for (let i = 2; i < process.argv.length; ++i) {
else if (arg == "--ecma3") options.ecmaVersion = 3
else if (arg == "--ecma5") options.ecmaVersion = 5
else if (arg == "--ecma6") options.ecmaVersion = 6
else if (arg == "--ecma7") options.ecmaVersion = 7
else if (arg == "--locations") options.locations = true
else if (arg == "--allow-hash-bang") options.allowHashBang = true
else if (arg == "--silent") silent = true
Expand Down
8 changes: 8 additions & 0 deletions src/expression.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
// [opp]: http://en.wikipedia.org/wiki/Operator-precedence_parser

import {types as tt} from "./tokentype"
import {types as tc} from "./tokencontext"
import {Parser} from "./state"

const pp = Parser.prototype
Expand Down Expand Up @@ -162,12 +163,19 @@ pp.parseExprOp = function(left, leftStartPos, leftStartLoc, minPrec, noIn) {
let startPos = this.start, startLoc = this.startLoc
node.right = this.parseExprOp(this.parseMaybeUnary(), startPos, startLoc, prec, noIn)
this.finishNode(node, (op === tt.logicalOR || op === tt.logicalAND) ? "LogicalExpression" : "BinaryExpression")
if (this.options.ecmaVersion >= 7 && op === tt.starstar)
this.checkExponentiationOperand(node.left)
return this.parseExprOp(node, leftStartPos, leftStartLoc, minPrec, noIn)
}
}
return left
}

pp.checkExponentiationOperand = function(node) {
if (node.type === "UnaryExpression" && node.operator !== "++" && node.operator !== "--")
this.raiseRecoverable(node.start, "Base operand of ** cannot use a unary expression")
}

// Parse unary operators, both prefix and postfix.

pp.parseMaybeUnary = function(refDestructuringErrors) {
Expand Down
18 changes: 14 additions & 4 deletions src/tokenize.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,20 @@ pp.readToken_slash = function() { // '/'
return this.finishOp(tt.slash, 1)
}

pp.readToken_mult_modulo = function(code) { // '%*'
pp.readToken_mult_modulo_exp = function(code) { // '%*'
let next = this.input.charCodeAt(this.pos + 1)
if (next === 61) return this.finishOp(tt.assign, 2)
return this.finishOp(code === 42 ? tt.star : tt.modulo, 1)
let size = 1
let tokentype = code === 42 ? tt.star : tt.modulo

// exponentiation operator ** and **=
if (this.options.ecmaVersion >= 7 && next === 42) {
++size
tokentype = tt.starstar
next = this.input.charCodeAt(this.pos + 2)
}

if (next === 61) return this.finishOp(tt.assign, size + 1)
return this.finishOp(tokentype, size)
}

pp.readToken_pipe_amp = function(code) { // '|&'
Expand Down Expand Up @@ -343,7 +353,7 @@ pp.getTokenFromCode = function(code) {
return this.readToken_slash()

case 37: case 42: // '%*'
return this.readToken_mult_modulo(code)
return this.readToken_mult_modulo_exp(code)

case 124: case 38: // '|&'
return this.readToken_pipe_amp(code)
Expand Down
3 changes: 2 additions & 1 deletion src/tokentype.js
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,8 @@ export const types = {
plusMin: new TokenType("+/-", {beforeExpr: true, binop: 9, prefix: true, startsExpr: true}),
modulo: binop("%", 10),
star: binop("*", 10),
slash: binop("/", 10)
slash: binop("/", 10),
starstar: binop("**", 11)
}

// Map keyword names to token types.
Expand Down
1 change: 1 addition & 0 deletions test/run.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
driver = require("./driver.js");
require("./tests.js");
require("./tests-harmony.js");
require("./tests-es7.js");
require("babel-core/register")
acorn = require("../src")
require("../src/loose")
Expand Down
Loading

0 comments on commit a8ce3a1

Please sign in to comment.