From a87f6f6fddc0bd84f099638dd267db241d43565f Mon Sep 17 00:00:00 2001 From: Sebastian McKenzie Date: Sun, 22 Mar 2015 04:08:35 +1100 Subject: [PATCH] clean up statement to expression explosion --- src/babel/traversal/path/index.js | 17 +++--- src/babel/traversal/scope.js | 3 +- src/babel/types/converters.js | 97 +++++++++++++++++++------------ src/babel/types/retrievers.js | 2 - 4 files changed, 71 insertions(+), 48 deletions(-) diff --git a/src/babel/traversal/path/index.js b/src/babel/traversal/path/index.js index 9122169812..fb75e6c12a 100644 --- a/src/babel/traversal/path/index.js +++ b/src/babel/traversal/path/index.js @@ -18,9 +18,7 @@ var hoistVariablesVisitor = { if (this.isVariableDeclaration() && node.kind === "var") { var bindings = this.getBindingIdentifiers(); for (var key in bindings) { - scope.push({ - id: bindings[key].identifiers - }); + scope.push({ id: bindings[key] }); } var exprs = []; @@ -210,16 +208,18 @@ export default class TraversalPath { var paths = []; var add = function (path) { - paths = paths.concat(path.getLastStatements()); + if (path) paths = paths.concat(path.getLastStatements()); }; if (this.isIfStatement()) { add(this.get("consequent")); add(this.get("alternate")); - } else if (this.isFor() || this.isWhile()) { + } else if (this.isDoExpression()) { add(this.get("body")); } else if (this.isProgram() || this.isBlockStatement()) { add(this.get("body").pop()); + } else { + paths.push(this); } return paths; @@ -231,9 +231,8 @@ export default class TraversalPath { if (toSequenceExpression) { return this.node = toSequenceExpression; } else { - var container = t.shadowFunctionExpression(null, [], t.blockStatement(nodes)); - - this.node = t.callExpression(container, []); + var container = t.functionExpression(null, [], t.blockStatement(nodes)); + container.shadow = true; // add implicit returns to all ending expression statements var last = this.getLastStatements(); @@ -244,6 +243,8 @@ export default class TraversalPath { } } + this.node = t.callExpression(container, []); + this.traverse(hoistVariablesVisitor); return this.node; diff --git a/src/babel/traversal/scope.js b/src/babel/traversal/scope.js index e5c5adad87..e6e119209a 100644 --- a/src/babel/traversal/scope.js +++ b/src/babel/traversal/scope.js @@ -510,7 +510,7 @@ export default class Scope { getFunctionParent() { var scope = this; - while (scope.parent && !t.isFunction(scope.block) && !t.isShadowFunctionExpression(scope.block)) { + while (scope.parent && !t.isFunction(scope.block)) { scope = scope.parent; } return scope; @@ -627,6 +627,7 @@ export default class Scope { if (!name) return false; if (this.hasOwnBinding(name)) return true; if (this.parentHasBinding(name)) return true; + if (this.uids[name]) return true; if (includes(Scope.globals, name)) return true; if (includes(Scope.contextVariables, name)) return true; return false; diff --git a/src/babel/types/converters.js b/src/babel/types/converters.js index 8d653566c6..a528497088 100644 --- a/src/babel/types/converters.js +++ b/src/babel/types/converters.js @@ -28,50 +28,73 @@ export function toComputedKey(node: Object, key: Object = node.key || node.prope export function toSequenceExpression(nodes: Array, scope: Scope): Object { var declars = []; - var exprs = []; + var bailed = false; - for (let i = 0; i < nodes.length; i++) { - var node = nodes[i]; - if (t.isExpression(node)) { - exprs.push(node); - } else if (t.isExpressionStatement(node)) { - exprs.push(node.expression); - } else if (t.isVariableDeclaration(node)) { - if (node.kind !== "var") return; // bailed - - each(node.declarations, function (declar) { - declars.push({ - kind: node.kind, - id: declar.id - }); - exprs.push(t.assignmentExpression("=", declar.id, declar.init)); - }); - } else if (t.isIfStatement(node)) { - exprs.push(t.conditionalExpression( - node.test, - node.consequent ? t.toSequenceExpression([node.consequent]) : t.identifier("undefined"), - node.alternate ? t.toSequenceExpression([node.alternate]) : t.identifier("undefined") - )); - } else if (t.isBlockStatement(node)) { - exprs.push(t.toSequenceExpression(node.body)); - } else { - // bailed, we can't understand this - return; - } - } - - // + var result = convert(nodes); + if (bailed) return; for (let i = 0; i < declars.length; i++) { scope.push(declars[i]); } - // + return result; - if (exprs.length === 1) { - return exprs[0]; - } else { - return t.sequenceExpression(exprs); + function convert(nodes) { + var ensureLastUndefined = false; + var exprs = []; + + for (let i = 0; i < nodes.length; i++) { + var node = nodes[i]; + if (t.isExpression(node)) { + exprs.push(node); + } else if (t.isExpressionStatement(node)) { + exprs.push(node.expression); + } else if (t.isVariableDeclaration(node)) { + if (node.kind !== "var") return bailed = true; // bailed + + each(node.declarations, function (declar) { + var bindings = t.getBindingIdentifiers(declar); + for (var key in bindings) { + declars.push({ + kind: node.kind, + id: bindings[key] + }); + } + + if (declar.init) { + exprs.push(t.assignmentExpression("=", declar.id, declar.init)); + } + }); + + ensureLastUndefined = true; + continue; + } else if (t.isIfStatement(node)) { + var consequent = node.consequent ? convert([node.consequent]) : t.identifier("undefined"); + var alternate = node.alternate ? convert([node.alternate]) : t.identifier("undefined"); + if (!consequent || !alternate) return bailed = true; + + exprs.push(t.conditionalExpression(node.test, consequent, alternate)); + } else if (t.isBlockStatement(node)) { + exprs.push(convert(node.body)); + } else { + // bailed, we can't understand this + return bailed = true; + } + + ensureLastUndefined = false; + } + + if (ensureLastUndefined) { + exprs.push(t.identifier("undefined")); + } + + // + + if (exprs.length === 1) { + return exprs[0]; + } else { + return t.sequenceExpression(exprs); + } } } diff --git a/src/babel/types/retrievers.js b/src/babel/types/retrievers.js index f67830a8d3..384e705f86 100644 --- a/src/babel/types/retrievers.js +++ b/src/babel/types/retrievers.js @@ -72,8 +72,6 @@ export function getLastStatements(node: Object): Array { if (t.isIfStatement(node)) { add(node.consequent); add(node.alternate); - } else if (t.isFor(node) || t.isWhile(node)) { - add(node.body); } else if (t.isProgram(node) || t.isBlockStatement(node)) { add(node.body[node.body.length - 1]); } else if (node) {