From da35d9806088335fe5e165dfe4f1e4ec3760b694 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Wed, 10 Feb 2016 15:04:38 -0800 Subject: [PATCH] New: Support ecmaVersion 7 (fixes #246) --- README.md | 6 +- espree.js | 8 +- lib/token-translator.js | 4 + package.json | 2 +- .../not-strict-local-eval-multi.result.js | 2 +- .../7/exponential-plusplus.result.js | 222 ++++++++++++++++ .../7/exponential-plusplus.src.js | 2 + .../7/exponential-precedence.result.js | 250 ++++++++++++++++++ .../7/exponential-precedence.src.js | 2 + .../7/exponential-simple.result.js | 177 +++++++++++++ .../ecma-version/7/exponential-simple.src.js | 1 + .../7/invalid-exponential-unary.result.js | 6 + .../7/invalid-exponential-unary.src.js | 2 + tests/lib/ecma-version.js | 12 +- tools/update-tests.js | 17 +- 15 files changed, 694 insertions(+), 19 deletions(-) create mode 100644 tests/fixtures/ecma-version/7/exponential-plusplus.result.js create mode 100644 tests/fixtures/ecma-version/7/exponential-plusplus.src.js create mode 100644 tests/fixtures/ecma-version/7/exponential-precedence.result.js create mode 100644 tests/fixtures/ecma-version/7/exponential-precedence.src.js create mode 100644 tests/fixtures/ecma-version/7/exponential-simple.result.js create mode 100644 tests/fixtures/ecma-version/7/exponential-simple.src.js create mode 100644 tests/fixtures/ecma-version/7/invalid-exponential-unary.result.js create mode 100644 tests/fixtures/ecma-version/7/invalid-exponential-unary.src.js diff --git a/README.md b/README.md index 09e906c0..80ca0482 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ var ast = espree.parse(code, { // create a top-level tokens array containing all tokens tokens: true, - // specify the language version (3, 5, or 6, default is 5) + // specify the language version (3, 5, 6, or 7, default is 5) ecmaVersion: 5, // specify which type of script you're parsing (script or module, default is script) @@ -130,6 +130,10 @@ We are building on top of Acorn, however, so that we can contribute back and hel All of them. +### What ECMAScript 7 features do you support? + +There is only one ECMAScript 7 syntax change: the exponentiation operator. Espree supports this. + ### How do you determine which experimental features to support? In general, we do not support experimental JavaScript features. We may make exceptions from time to time depending on the maturity of the features. diff --git a/espree.js b/espree.js index 4ea08f40..f955b663 100644 --- a/espree.js +++ b/espree.js @@ -389,7 +389,7 @@ acorn.plugins.espree = function(instance) { * @throws {SyntaxError} A syntax error. * @returns {void} */ - instance.raise = function(pos, message) { + instance.raise = instance.raiseRecoverable = function(pos, message) { var loc = getLineInfo(this.input, pos); var err = new SyntaxError(message); err.index = pos; @@ -509,12 +509,13 @@ function tokenize(code, options) { case 3: case 5: case 6: + case 7: acornOptions.ecmaVersion = options.ecmaVersion; extra.ecmaVersion = options.ecmaVersion; break; default: - throw new Error("ecmaVersion must be 3, 5, or 6."); + throw new Error("ecmaVersion must be 3, 5, 6, or 7."); } } @@ -645,12 +646,13 @@ function parse(code, options) { case 3: case 5: case 6: + case 7: acornOptions.ecmaVersion = options.ecmaVersion; extra.ecmaVersion = options.ecmaVersion; break; default: - throw new Error("ecmaVersion must be 3, 5, or 6."); + throw new Error("ecmaVersion must be 3, 5, 6, or 7."); } } diff --git a/lib/token-translator.js b/lib/token-translator.js index fbae0d80..de6fc081 100644 --- a/lib/token-translator.js +++ b/lib/token-translator.js @@ -131,6 +131,10 @@ TokenTranslator.prototype = { token.type = Token.Keyword; } + if (extra.ecmaVersion > 5 && (token.value === "yield" || token.value === "let")) { + token.type = Token.Keyword; + } + } else if (type === tt.semi || type === tt.comma || type === tt.parenL || type === tt.parenR || type === tt.braceL || type === tt.braceR || diff --git a/package.json b/package.json index 58b508fc..3d8cf95f 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ }, "license": "BSD-2-Clause", "dependencies": { - "acorn": "^2.7.0", + "acorn": "^3.0.4", "acorn-jsx": "^2.0.1" }, "devDependencies": { diff --git a/tests/fixtures/ecma-version/6/defaultParams-and-arrowFunctions/not-strict-local-eval-multi.result.js b/tests/fixtures/ecma-version/6/defaultParams-and-arrowFunctions/not-strict-local-eval-multi.result.js index 0a662121..057e9f4b 100644 --- a/tests/fixtures/ecma-version/6/defaultParams-and-arrowFunctions/not-strict-local-eval-multi.result.js +++ b/tests/fixtures/ecma-version/6/defaultParams-and-arrowFunctions/not-strict-local-eval-multi.result.js @@ -329,4 +329,4 @@ module.exports = { ] } ] -}; +}; \ No newline at end of file diff --git a/tests/fixtures/ecma-version/7/exponential-plusplus.result.js b/tests/fixtures/ecma-version/7/exponential-plusplus.result.js new file mode 100644 index 00000000..ae46fdc2 --- /dev/null +++ b/tests/fixtures/ecma-version/7/exponential-plusplus.result.js @@ -0,0 +1,222 @@ +module.exports = { + "type": "Program", + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 9 + } + }, + "range": [ + 1, + 10 + ], + "body": [ + { + "type": "ExpressionStatement", + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 9 + } + }, + "range": [ + 1, + 10 + ], + "expression": { + "type": "BinaryExpression", + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 8 + } + }, + "range": [ + 1, + 9 + ], + "left": { + "type": "UpdateExpression", + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 3 + } + }, + "range": [ + 1, + 4 + ], + "operator": "++", + "prefix": false, + "argument": { + "type": "Identifier", + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 1 + } + }, + "range": [ + 1, + 2 + ], + "name": "a" + } + }, + "operator": "**", + "right": { + "type": "Literal", + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + }, + "range": [ + 8, + 9 + ], + "value": 2, + "raw": "2" + } + } + } + ], + "sourceType": "script", + "tokens": [ + { + "type": "Identifier", + "value": "a", + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 1 + } + }, + "range": [ + 1, + 2 + ] + }, + { + "type": { + "label": "++/--", + "beforeExpr": false, + "startsExpr": true, + "isLoop": false, + "isAssign": false, + "prefix": true, + "postfix": true, + "binop": null + }, + "value": "++", + "loc": { + "start": { + "line": 2, + "column": 1 + }, + "end": { + "line": 2, + "column": 3 + } + }, + "range": [ + 2, + 4 + ] + }, + { + "type": { + "label": "**", + "beforeExpr": true, + "startsExpr": false, + "isLoop": false, + "isAssign": false, + "prefix": false, + "postfix": false, + "binop": null, + "updateContext": null + }, + "value": "**", + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 6 + } + }, + "range": [ + 5, + 7 + ] + }, + { + "type": "Numeric", + "value": "2", + "loc": { + "start": { + "line": 2, + "column": 7 + }, + "end": { + "line": 2, + "column": 8 + } + }, + "range": [ + 8, + 9 + ] + }, + { + "type": "Punctuator", + "value": ";", + "loc": { + "start": { + "line": 2, + "column": 8 + }, + "end": { + "line": 2, + "column": 9 + } + }, + "range": [ + 9, + 10 + ] + } + ] +}; \ No newline at end of file diff --git a/tests/fixtures/ecma-version/7/exponential-plusplus.src.js b/tests/fixtures/ecma-version/7/exponential-plusplus.src.js new file mode 100644 index 00000000..330e31ee --- /dev/null +++ b/tests/fixtures/ecma-version/7/exponential-plusplus.src.js @@ -0,0 +1,2 @@ + +a++ ** 2; diff --git a/tests/fixtures/ecma-version/7/exponential-precedence.result.js b/tests/fixtures/ecma-version/7/exponential-precedence.result.js new file mode 100644 index 00000000..44ea079d --- /dev/null +++ b/tests/fixtures/ecma-version/7/exponential-precedence.result.js @@ -0,0 +1,250 @@ +module.exports = { + "type": "Program", + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 11 + } + }, + "range": [ + 1, + 12 + ], + "body": [ + { + "type": "ExpressionStatement", + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 11 + } + }, + "range": [ + 1, + 12 + ], + "expression": { + "type": "BinaryExpression", + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 10 + } + }, + "range": [ + 1, + 11 + ], + "left": { + "type": "Literal", + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 1 + } + }, + "range": [ + 1, + 2 + ], + "value": 1, + "raw": "1" + }, + "operator": "*", + "right": { + "type": "BinaryExpression", + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 10 + } + }, + "range": [ + 5, + 11 + ], + "left": { + "type": "Literal", + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 5 + } + }, + "range": [ + 5, + 6 + ], + "value": 5, + "raw": "5" + }, + "operator": "**", + "right": { + "type": "Literal", + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 10 + } + }, + "range": [ + 10, + 11 + ], + "value": 2, + "raw": "2" + } + } + } + } + ], + "sourceType": "script", + "tokens": [ + { + "type": "Numeric", + "value": "1", + "loc": { + "start": { + "line": 2, + "column": 0 + }, + "end": { + "line": 2, + "column": 1 + } + }, + "range": [ + 1, + 2 + ] + }, + { + "type": "Punctuator", + "value": "*", + "loc": { + "start": { + "line": 2, + "column": 2 + }, + "end": { + "line": 2, + "column": 3 + } + }, + "range": [ + 3, + 4 + ] + }, + { + "type": "Numeric", + "value": "5", + "loc": { + "start": { + "line": 2, + "column": 4 + }, + "end": { + "line": 2, + "column": 5 + } + }, + "range": [ + 5, + 6 + ] + }, + { + "type": { + "label": "**", + "beforeExpr": true, + "startsExpr": false, + "isLoop": false, + "isAssign": false, + "prefix": false, + "postfix": false, + "binop": null, + "updateContext": null + }, + "value": "**", + "loc": { + "start": { + "line": 2, + "column": 6 + }, + "end": { + "line": 2, + "column": 8 + } + }, + "range": [ + 7, + 9 + ] + }, + { + "type": "Numeric", + "value": "2", + "loc": { + "start": { + "line": 2, + "column": 9 + }, + "end": { + "line": 2, + "column": 10 + } + }, + "range": [ + 10, + 11 + ] + }, + { + "type": "Punctuator", + "value": ";", + "loc": { + "start": { + "line": 2, + "column": 10 + }, + "end": { + "line": 2, + "column": 11 + } + }, + "range": [ + 11, + 12 + ] + } + ] +}; \ No newline at end of file diff --git a/tests/fixtures/ecma-version/7/exponential-precedence.src.js b/tests/fixtures/ecma-version/7/exponential-precedence.src.js new file mode 100644 index 00000000..d067ebd6 --- /dev/null +++ b/tests/fixtures/ecma-version/7/exponential-precedence.src.js @@ -0,0 +1,2 @@ + +1 * 5 ** 2; diff --git a/tests/fixtures/ecma-version/7/exponential-simple.result.js b/tests/fixtures/ecma-version/7/exponential-simple.result.js new file mode 100644 index 00000000..b2fb4e8a --- /dev/null +++ b/tests/fixtures/ecma-version/7/exponential-simple.result.js @@ -0,0 +1,177 @@ +module.exports = { + "type": "Program", + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 7 + } + }, + "range": [ + 0, + 7 + ], + "body": [ + { + "type": "ExpressionStatement", + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 7 + } + }, + "range": [ + 0, + 7 + ], + "expression": { + "type": "BinaryExpression", + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 6 + } + }, + "range": [ + 0, + 6 + ], + "left": { + "type": "Literal", + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + } + }, + "range": [ + 0, + 1 + ], + "value": 5, + "raw": "5" + }, + "operator": "**", + "right": { + "type": "Literal", + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 6 + } + }, + "range": [ + 5, + 6 + ], + "value": 2, + "raw": "2" + } + } + } + ], + "sourceType": "script", + "tokens": [ + { + "type": "Numeric", + "value": "5", + "loc": { + "start": { + "line": 1, + "column": 0 + }, + "end": { + "line": 1, + "column": 1 + } + }, + "range": [ + 0, + 1 + ] + }, + { + "type": { + "label": "**", + "beforeExpr": true, + "startsExpr": false, + "isLoop": false, + "isAssign": false, + "prefix": false, + "postfix": false, + "binop": null, + "updateContext": null + }, + "value": "**", + "loc": { + "start": { + "line": 1, + "column": 2 + }, + "end": { + "line": 1, + "column": 4 + } + }, + "range": [ + 2, + 4 + ] + }, + { + "type": "Numeric", + "value": "2", + "loc": { + "start": { + "line": 1, + "column": 5 + }, + "end": { + "line": 1, + "column": 6 + } + }, + "range": [ + 5, + 6 + ] + }, + { + "type": "Punctuator", + "value": ";", + "loc": { + "start": { + "line": 1, + "column": 6 + }, + "end": { + "line": 1, + "column": 7 + } + }, + "range": [ + 6, + 7 + ] + } + ] +}; \ No newline at end of file diff --git a/tests/fixtures/ecma-version/7/exponential-simple.src.js b/tests/fixtures/ecma-version/7/exponential-simple.src.js new file mode 100644 index 00000000..23b56e67 --- /dev/null +++ b/tests/fixtures/ecma-version/7/exponential-simple.src.js @@ -0,0 +1 @@ +5 ** 2; diff --git a/tests/fixtures/ecma-version/7/invalid-exponential-unary.result.js b/tests/fixtures/ecma-version/7/invalid-exponential-unary.result.js new file mode 100644 index 00000000..46b9895c --- /dev/null +++ b/tests/fixtures/ecma-version/7/invalid-exponential-unary.result.js @@ -0,0 +1,6 @@ +module.exports = { + "index": 4, + "lineNumber": 2, + "column": 4, + "message": "Unexpected token **" +}; \ No newline at end of file diff --git a/tests/fixtures/ecma-version/7/invalid-exponential-unary.src.js b/tests/fixtures/ecma-version/7/invalid-exponential-unary.src.js new file mode 100644 index 00000000..7c23c8c3 --- /dev/null +++ b/tests/fixtures/ecma-version/7/invalid-exponential-unary.src.js @@ -0,0 +1,2 @@ + +-5 ** 2; diff --git a/tests/lib/ecma-version.js b/tests/lib/ecma-version.js index a6e71ae5..d66cecc4 100644 --- a/tests/lib/ecma-version.js +++ b/tests/lib/ecma-version.js @@ -40,12 +40,12 @@ var leche = require("leche"), // Setup //------------------------------------------------------------------------------ -var FIXTURES_DIR = "./tests/fixtures/ecma-version/6"; +var FIXTURES_DIR = "./tests/fixtures/ecma-version/"; var allTestFiles = shelljs.find(FIXTURES_DIR).filter(function(filename) { return filename.indexOf(".src.js") > -1; }).map(function(filename) { - return filename.substring(FIXTURES_DIR.length - 1, filename.length - 7); // strip off ".src.js" + return filename.substring(FIXTURES_DIR.length - 2, filename.length - 7); // strip off ".src.js" }); var scriptOnlyTestFiles = allTestFiles.filter(function(filename) { @@ -69,18 +69,22 @@ describe("ecmaVersion", function() { loc: true, range: true, tokens: true, - ecmaVersion: 6 + ecmaVersion: 5 }; }); describe("Scripts", function() { leche.withData(scriptOnlyTestFiles, function(filename) { + + var version = filename.substring(0, filename.indexOf("/")); + // Uncomment and fill in filename to focus on a single file // var filename = "newTarget/simple-new-target"; var code = shelljs.cat(path.resolve(FIXTURES_DIR, filename) + ".src.js"); it("should parse correctly when sourceType is script", function() { + config.ecmaVersion = Number(version); var expected = require(path.resolve(__dirname, "../../", FIXTURES_DIR, filename) + ".result.js"); tester.assertMatches(code, config, expected); @@ -94,11 +98,13 @@ describe("ecmaVersion", function() { leche.withData(moduleTestFiles, function(filename) { + var version = filename.substring(0, filename.indexOf("/")); var code = shelljs.cat(path.resolve(FIXTURES_DIR, filename) + ".src.js"); it("should parse correctly when sourceType is module", function() { var expected = require(path.resolve(__dirname, "../../", FIXTURES_DIR, filename) + ".result.js"); + config.ecmaVersion = Number(version); config.sourceType = "module"; // set sourceType of program node to module diff --git a/tools/update-tests.js b/tools/update-tests.js index 803a3001..2690c994 100644 --- a/tools/update-tests.js +++ b/tools/update-tests.js @@ -81,12 +81,12 @@ function outputResult(result, testResultFilename) { //------------------------------------------------------------------------------ var FIXTURES_DIR = "./tests/fixtures/ecma-features", - VERSION_DIR = "./tests/fixtures/ecma-version", + FIXTURES_VERSION_DIR = "./tests/fixtures/ecma-version", COMMENTS_DIR = "./tests/fixtures/attach-comments", LIBRARIES_DIR = "./tests/fixtures/libraries"; var testFiles = getTestFilenames(FIXTURES_DIR), - mixFiles = getTestFilenames(VERSION_DIR), + versionFiles = getTestFilenames(FIXTURES_VERSION_DIR), commentFiles = getTestFilenames(COMMENTS_DIR), libraryFiles = getLibraryFilenames(LIBRARIES_DIR); @@ -142,22 +142,19 @@ testFiles.forEach(function(filename) { outputResult(result, testResultFilename); }); -// update all tests in ecma-version -mixFiles.forEach(function(filename) { +versionFiles.forEach(function(filename) { var feature = path.dirname(filename), - code = shelljs.cat(path.resolve(VERSION_DIR, filename) + ".src.js"), + version = Number(filename.substring(0, filename.indexOf("/"))), + code = shelljs.cat(path.resolve(FIXTURES_VERSION_DIR, filename) + ".src.js"), config = { loc: true, range: true, tokens: true, - ecmaVersion: 6, - ecmaFeatures: {} + ecmaVersion: version }; - // config.ecmaFeatures = require(path.resolve(__dirname, "../", VERSION_DIR, filename) + ".config.js"); - - var testResultFilename = path.resolve(__dirname, "..", VERSION_DIR, filename) + ".result.js", + var testResultFilename = path.resolve(__dirname, "..", FIXTURES_VERSION_DIR, filename) + ".result.js", result = getExpectedResult(code, config); outputResult(result, testResultFilename);