From 4df23339388d7b1147b6f1a7716b23b91fea5f59 Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Thu, 9 Oct 2014 22:26:23 +1100 Subject: [PATCH] support destructuring in AssignmentStatement and ForOf loops --- lib/6to5/transform.js | 2 +- lib/6to5/transformers/destructuring.js | 45 +++++++++++++------ lib/6to5/transformers/for-of.js | 27 +++++++++-- lib/6to5/util.js | 14 ++++-- .../destructuring/assignment/actual.js | 1 + .../destructuring/assignment/expected.js | 3 ++ test/fixtures/destructuring/for-in/actual.js | 3 ++ .../fixtures/destructuring/for-in/expected.js | 4 ++ test/fixtures/destructuring/for-of/actual.js | 3 ++ .../fixtures/destructuring/for-of/expected.js | 5 +++ 10 files changed, 86 insertions(+), 21 deletions(-) create mode 100644 test/fixtures/destructuring/assignment/actual.js create mode 100644 test/fixtures/destructuring/assignment/expected.js create mode 100644 test/fixtures/destructuring/for-in/actual.js create mode 100644 test/fixtures/destructuring/for-in/expected.js create mode 100644 test/fixtures/destructuring/for-of/actual.js create mode 100644 test/fixtures/destructuring/for-of/expected.js diff --git a/lib/6to5/transform.js b/lib/6to5/transform.js index 93a506bfc2..e23dd7f718 100644 --- a/lib/6to5/transform.js +++ b/lib/6to5/transform.js @@ -114,10 +114,10 @@ transform.transformers = { templateLiterals: require("./transformers/template-literals"), propertyMethodAssignment: require("./transformers/property-method-assignment"), defaultParameters: require("./transformers/default-parameters"), - destructuring: require("./transformers/destructuring"), generators: require("./transformers/generators"), blockBinding: require("./transformers/block-binding"), restParameters: require("./transformers/rest-parameters"), forOf: require("./transformers/for-of"), + destructuring: require("./transformers/destructuring"), unicodeRegex: require("./transformers/unicode-regex") }; diff --git a/lib/6to5/transformers/destructuring.js b/lib/6to5/transformers/destructuring.js index e1dfa703e5..bbc7de07f0 100644 --- a/lib/6to5/transformers/destructuring.js +++ b/lib/6to5/transformers/destructuring.js @@ -2,15 +2,14 @@ var util = require("../util"); var b = require("ast-types").builders; var _ = require("lodash"); -var isPattern = function (id) { - return id.type === "ArrayPattern" || id.type === "ObjectPattern"; -}; - - var buildVariableAssign = function (kind, id, init) { - return b.variableDeclaration(kind, [ - b.variableDeclarator(id, init) - ]); + if (kind === false) { + return b.expressionStatement(b.assignmentExpression("=", id, init)); + } else { + return b.variableDeclaration(kind, [ + b.variableDeclarator(id, init) + ]); + } }; var push = function (kind, nodes, pattern, parentId) { @@ -26,7 +25,7 @@ var pushObjectPattern = function (kind, nodes, pattern, parentId) { var pattern2 = prop.value; var patternId2 = b.memberExpression(parentId, prop.key, false); - if (isPattern(pattern2)) { + if (util.isPattern(pattern2)) { push(kind, nodes, pattern2, patternId2); } else { nodes.push(buildVariableAssign(kind, pattern2, patternId2)); @@ -69,7 +68,7 @@ exports.FunctionExpression = function (node, parent, opts, generateUid) { var nodes = []; node.params = node.params.map(function (pattern) { - if (!isPattern(pattern)) return pattern; + if (!util.isPattern(pattern)) return pattern; var parentId = b.identifier(generateUid("ref")); @@ -78,15 +77,35 @@ exports.FunctionExpression = function (node, parent, opts, generateUid) { return parentId; }); - block.body = nodes.concat(block.body); + block.body = nodes.concat(block.body || []); +}; + +exports.ExpressionStatement = function (node, parent, opts, generateUid) { + var expr = node.expression; + if (expr.type !== "AssignmentExpression") return; + + if (!util.isPattern(expr.left)) return; + + var nodes = []; + + var ref = b.identifier(generateUid("ref")); + nodes.push(b.variableDeclaration("var", [ + b.variableDeclarator(ref, expr.right) + ])); + + push(false, nodes, expr.left, ref); + + return nodes; }; exports.VariableDeclaration = function (node, parent, opts, generateUid) { + if (parent.type === "ForInStatement") return; + var nodes = []; var hasPattern = false; _.each(node.declarations, function (declar) { - if (isPattern(declar.id)) { + if (util.isPattern(declar.id)) { hasPattern = true; return false; } @@ -96,7 +115,7 @@ exports.VariableDeclaration = function (node, parent, opts, generateUid) { _.each(node.declarations, function (declar) { var patternId = declar.init; var pattern = declar.id; - if (isPattern(pattern)) { + if (util.isPattern(pattern) && patternId) { pushPattern(node.kind, nodes, pattern, patternId, generateUid); } else { nodes.push(buildVariableAssign(node.kind, declar.id, declar.init)); diff --git a/lib/6to5/transformers/for-of.js b/lib/6to5/transformers/for-of.js index 8b18294647..26a3937ce1 100644 --- a/lib/6to5/transformers/for-of.js +++ b/lib/6to5/transformers/for-of.js @@ -1,18 +1,39 @@ var util = require("../util"); +var b = require("ast-types").builders; exports.ForOfStatement = function (node, parent, opts, generateUid) { + var declar; + var isPattern = false; + + var key; + if (node.left.type === "VariableDeclaration") { + declar = node.left; + key = declar.declarations[0].id; + } else { + isPattern = true; + declar = node.left[0]; + key = b.identifier(generateUid("ref")); + } + var node2 = util.template("for-of", { ITERATOR_KEY: generateUid("iterator"), STEP_KEY: generateUid("step"), OBJECT: node.right, - KEY: node.left.declarations[0].id + KEY: key }); var block = node2.body; - block.body = block.body.concat(node.body.body); + + if (isPattern) { + block.body.push(b.variableDeclaration(declar.kind, [ + b.variableDeclarator(declar.declarations[0].id, key) + ])); + } + + block.body = block.body.concat(node.body.body || []); var declar = block.body[0]; - declar.kind = node.left.kind; + declar.kind = declar.kind; return node2; }; diff --git a/lib/6to5/util.js b/lib/6to5/util.js index 74225cad0e..7de095b1a9 100644 --- a/lib/6to5/util.js +++ b/lib/6to5/util.js @@ -11,15 +11,15 @@ _.each(esprima.Syntax, function (name) { estraverse.VisitorKeys[name] = estraverse.VisitorKeys[name] || []; }); -exports.parse = function (filename, code, callback) { +exports.parse = function (filename, code, callback, opts) { try { - var ast = esprima.parse(code, { + var ast = esprima.parse(code, _.extend(opts || {}, { comment: true, source: filename, tokens: true, range: true, loc: true - }); + })); estraverse.attachComments(ast, ast.comments, ast.tokens); @@ -41,6 +41,10 @@ exports.parse = function (filename, code, callback) { } }; +exports.isPattern = function (node) { + return node.type === "ArrayPattern" || node.type === "ObjectPattern"; +}; + exports.generate = function (ast, opts) { opts = opts || {}; @@ -218,6 +222,8 @@ try { var loc = templatesLoc + "/" + name; var code = fs.readFileSync(loc, "utf8"); - exports.templates[key] = exports.removeProperties(exports.parse(loc, code)); + exports.templates[key] = exports.removeProperties(exports.parse(loc, code, null, { + tolerant: true + })); }); } diff --git a/test/fixtures/destructuring/assignment/actual.js b/test/fixtures/destructuring/assignment/actual.js new file mode 100644 index 0000000000..d14ce7e47d --- /dev/null +++ b/test/fixtures/destructuring/assignment/actual.js @@ -0,0 +1 @@ +[a, b] = f(); diff --git a/test/fixtures/destructuring/assignment/expected.js b/test/fixtures/destructuring/assignment/expected.js new file mode 100644 index 0000000000..c086e01429 --- /dev/null +++ b/test/fixtures/destructuring/assignment/expected.js @@ -0,0 +1,3 @@ +var _ref = f(); +a = _ref[0]; +b = _ref[1]; diff --git a/test/fixtures/destructuring/for-in/actual.js b/test/fixtures/destructuring/for-in/actual.js new file mode 100644 index 0000000000..87fe7e7dde --- /dev/null +++ b/test/fixtures/destructuring/for-in/actual.js @@ -0,0 +1,3 @@ +for (var [name, value] in obj) { + print("Name: " + name + ", Value: " + value); +} diff --git a/test/fixtures/destructuring/for-in/expected.js b/test/fixtures/destructuring/for-in/expected.js new file mode 100644 index 0000000000..b4d357111f --- /dev/null +++ b/test/fixtures/destructuring/for-in/expected.js @@ -0,0 +1,4 @@ +for (var name in obj) { + var value = obj[name]; + print("Name: " + name + ", Value: " + value); +} diff --git a/test/fixtures/destructuring/for-of/actual.js b/test/fixtures/destructuring/for-of/actual.js new file mode 100644 index 0000000000..5873553d65 --- /dev/null +++ b/test/fixtures/destructuring/for-of/actual.js @@ -0,0 +1,3 @@ +for (var [ name, before, after ] of this.test.expectation.registers) { + +} diff --git a/test/fixtures/destructuring/for-of/expected.js b/test/fixtures/destructuring/for-of/expected.js new file mode 100644 index 0000000000..5f0004fccd --- /dev/null +++ b/test/fixtures/destructuring/for-of/expected.js @@ -0,0 +1,5 @@ +for (var _iterator = this.test.expectation.registers[Symbol.iterator](), _step; !(_step = _iterator.next()).done;) { + var name = _step.value[0]; + var before = _step.value[1]; + var after = _step.value[2]; +}