From 757545a6124f285829e41932f0ffefaf43cd39e8 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Thu, 24 Jul 2014 01:44:22 +0300 Subject: [PATCH] Basic ES6 Arrow Expressions support. Added Property type to ObjectExpression properties. Reserved ES6 properties in Property type. --- acorn.js | 87 +++++++++++++++++++++++++++++++++++++------ test/tests-harmony.js | 35 ++++++++--------- 2 files changed, 93 insertions(+), 29 deletions(-) diff --git a/acorn.js b/acorn.js index 2aa13ece6d..19a2bbccc4 100644 --- a/acorn.js +++ b/acorn.js @@ -313,6 +313,7 @@ var _braceR = {type: "}"}, _parenL = {type: "(", beforeExpr: true}, _parenR = {type: ")"}; var _comma = {type: ",", beforeExpr: true}, _semi = {type: ";", beforeExpr: true}; var _colon = {type: ":", beforeExpr: true}, _dot = {type: "."}, _ellipsis = {type: "..."}, _question = {type: "?", beforeExpr: true}; + var _arrow = {type: "=>", beforeExpr: true}; // Operators. These carry several kinds of properties to help the // parser use them properly (the presence of these properties is @@ -667,9 +668,13 @@ return finishOp(_relational, size); } - function readToken_eq_excl(code) { // '=!' + function readToken_eq_excl(code) { // '=!', '=>' var next = input.charCodeAt(tokPos + 1); if (next === 61) return finishOp(_equality, input.charCodeAt(tokPos + 2) === 61 ? 3 : 2); + if (code === 61 && next === 62 && options.ecmaVersion >= 6) { // '=>' + tokPos += 2; + return finishToken(_arrow); + } return finishOp(code === 61 ? _eq : _prefix, 1); } @@ -1134,8 +1139,8 @@ // Raise an unexpected token error. - function unexpected() { - raise(tokStart, "Unexpected token"); + function unexpected(pos) { + raise(pos != null ? pos : tokStart, "Unexpected token"); } // Verify that a node is an lval — something that can be assigned @@ -1656,8 +1661,14 @@ var node = startNode(); next(); return finishNode(node, "ThisExpression"); + case _name: - return parseIdent(); + var id = parseIdent(); + if (eat(_arrow)) { + return parseArrowExpression(startNodeFrom(id), [id]); + } + return id; + case _num: case _string: case _regexp: var node = startNode(); node.value = tokVal; @@ -1673,18 +1684,27 @@ return finishNode(node, "Literal"); case _parenL: - var tokStartLoc1 = tokStartLoc, tokStart1 = tokStart; + var node = startNode(), tokStartLoc1 = tokStartLoc, tokStart1 = tokStart, val; next(); - var val = parseExpression(); + if (tokType !== _parenR) { + val = parseExpression(); + } + expect(_parenR); + if (eat(_arrow)) { + val = parseArrowExpression(node, !val ? [] : val.type === "SequenceExpression" ? val.expressions : [val]); + } else + // disallow '()' before everything but error + if (!val) { + unexpected(tokPos - 1); + } val.start = tokStart1; - val.end = tokEnd; + val.end = lastEnd; if (options.locations) { val.loc.start = tokStartLoc1; - val.loc.end = tokEndLoc; + val.loc.end = lastEndLoc; } if (options.ranges) - val.range = [tokStart1, tokEnd]; - expect(_parenR); + val.range = [tokStart1, lastEnd]; return val; case _bracketL: @@ -1734,7 +1754,8 @@ if (options.allowTrailingCommas && eat(_braceR)) break; } else first = false; - var prop = {key: parsePropertyName()}, isGetSet = false, kind; + var prop = startNode(), isGetSet = false, kind; + prop.key = parsePropertyName(); if (eat(_colon)) { prop.value = parseExpression(true); kind = prop.kind = "init"; @@ -1762,7 +1783,12 @@ } } } - node.properties.push(prop); + if (options.ecmaVersion >= 6) { + prop.method = false; + prop.shorthand = false; + prop.computed = false; + } + node.properties.push(finishNode(prop, "Property")); } return finishNode(node, "ObjectExpression"); } @@ -1835,6 +1861,43 @@ return finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression"); } + // Parse arrow function expression with given parameters. + + function parseArrowExpression(node, params) { + var defaults = [], hasDefaults = false; + + for (var i = 0; i < params.length; i++) { + var param = params[i]; + + switch (param.type) { + case "Identifier": + defaults.push(null); + break; + + case "AssignmentExpression": + defaults.push(param.right); + hasDefaults = true; + params[i] = param.left; + break; + + default: + unexpected(param.start); + } + } + + var isExpression = tokType !== _braceL; + var body = isExpression ? parseExpression() : parseBlock(true); + + node.id = null; + node.params = params; + node.defaults = hasDefaults ? defaults : []; + node.rest = null; + node.body = body; + node.generator = false; + node.expression = isExpression; + return finishNode(node, "ArrowFunctionExpression"); + } + // Parses a comma-separated list of expressions, and returns them as // an array. `close` is the token type that ends the list, and // `allowEmpty` can be turned on to allow subsequent commas with diff --git a/test/tests-harmony.js b/test/tests-harmony.js index 2678593c64..1abcf22bd6 100644 --- a/test/tests-harmony.js +++ b/test/tests-harmony.js @@ -35,7 +35,8 @@ if (typeof exports != "undefined") { } /* - Tests below are automatically converted from https://github.com/ariya/esprima/blob/2bb17ef9a45c88e82d72c2c61b7b7af93caef028/test/harmonytest.js. + Tests below were automatically converted from https://github.com/ariya/esprima/blob/2bb17ef9a45c88e82d72c2c61b7b7af93caef028/test/harmonytest.js. + Locations for parenthesized expressions and expression statements were manually fixed. */ // ES6 Unicode Code Point Escape Sequence @@ -1504,10 +1505,10 @@ test("e => ({ property: 42 })", { end: {line: 1, column: 20} } }], - range: [6, 22], + range: [5, 23], loc: { - start: {line: 1, column: 6}, - end: {line: 1, column: 22} + start: {line: 1, column: 5}, + end: {line: 1, column: 23} } }, rest: null, @@ -1578,16 +1579,16 @@ test("e => { label: 42 }", { end: {line: 1, column: 16} } }, - range: [14, 17], + range: [14, 16], loc: { start: {line: 1, column: 14}, - end: {line: 1, column: 17} + end: {line: 1, column: 16} } }, - range: [7, 17], + range: [7, 16], loc: { start: {line: 1, column: 7}, - end: {line: 1, column: 17} + end: {line: 1, column: 16} } }], range: [5, 18], @@ -2323,10 +2324,10 @@ test("(x => x)", { rest: null, generator: false, expression: true, - range: [1, 7], + range: [0, 8], loc: { - start: {line: 1, column: 1}, - end: {line: 1, column: 7} + start: {line: 1, column: 0}, + end: {line: 1, column: 8} } }, range: [0, 8], @@ -2493,19 +2494,19 @@ test("(x) => ((y, z) => (x, y, z))", { } } ], - range: [19, 26], + range: [18, 27], loc: { - start: {line: 1, column: 19}, - end: {line: 1, column: 26} + start: {line: 1, column: 18}, + end: {line: 1, column: 27} } }, rest: null, generator: false, expression: true, - range: [8, 27], + range: [7, 28], loc: { - start: {line: 1, column: 8}, - end: {line: 1, column: 27} + start: {line: 1, column: 7}, + end: {line: 1, column: 28} } }, rest: null,