Skip to content

Commit

Permalink
issue #254 - fixed bugs in esprima transform
Browse files Browse the repository at this point in the history
  • Loading branch information
bjouhier committed Mar 1, 2015
1 parent a61e8cb commit 66ef19e
Showing 1 changed file with 51 additions and 33 deletions.
84 changes: 51 additions & 33 deletions lib/callbacks/transform-esprima.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ if (typeof exports !== 'undefined') {
// EmptyStatement: ;
// ObjectExpression: object initializer
// Property: prop: inside ObjectExpression
// SwitchCase: case inside SwitchStatement
// WithStatement


Expand Down Expand Up @@ -357,7 +356,7 @@ if (typeof exports !== 'undefined') {
return node.right;
}
// !_ -> false
if (node.type === Syntax.UnaryExpression && node.operator === '!' && _isMarker(argument)) {
if (node.type === Syntax.UnaryExpression && node.operator === '!' && _isMarker(node.argument)) {
options.needsTransform = true;
node.type = Syntax.Literal;
node.value = false;
Expand Down Expand Up @@ -483,7 +482,7 @@ if (typeof exports !== 'undefined') {
if (parent.type === Syntax.AssignmentExpression) {
n = parent.left;
var s = "";
while ((isDot(n) && (nn = n.property).type === Syntax.Identifier) || (isIndex(n) && (nn = n.property).type === Literal)) {
while ((isDot(n) && (nn = n.property).type === Syntax.Identifier) || (isIndex(n) && (nn = n.property).type === Syntax.Literal)) {
s = s ? (nn.name || nn.value) + "_" + s : (nn.name || nn.value);
n = n.object;
}
Expand Down Expand Up @@ -573,14 +572,15 @@ if (typeof exports !== 'undefined') {
$lhs: _identifier(child.id.name),
$rhs: child.init
});
// ???
//if (parent.type === Syntax.ForStatement) child = child.expression;
if (parent.type === Syntax.ForStatement) child = child.expression;
return child;
}).filter(function(child) {
return child != null;
});
if (declarations.length == 0) {
return;
// leave variable if `for (var x in y)`
return parent.type === Syntax.ForInStatement //
? node.declarations[node.declarations.length - 1].id : undefined;
}
var result;
if (parent.type == Syntax.BlockStatement || parent.type === Syntax.Program) {
Expand Down Expand Up @@ -636,6 +636,12 @@ if (typeof exports !== 'undefined') {
_convertApply(node, options);
// fall through
default:
if (node.type === Syntax.SwitchCase) {
// wrap consequent into a block, to reuse block logic in subsequent steps
node.consequent = [_node(node, Syntax.BlockStatement, {
body: node.consequent,
})];
}
// todo: set breaks flag
node = _propagate(node, _doIt);
_setBreaks(node);
Expand Down Expand Up @@ -764,8 +770,8 @@ if (typeof exports !== 'undefined') {
var ident = child.test.left;
if (ident.type !== Syntax.Identifier) return false;
if (child.test.right.type !== Syntax.Literal || child.test.right.value !== null) return false;
if (!child.consequent.body || child.consequent.body.length !== 1) return false;
var assign = child.consequent.body[0];
if (!child.consequent || child.consequent.length !== 1) return false;
var assign = child.consequent[0];
if (assign.type !== Syntax.ExpressionStatement) return false;
assign = assign.expression;
if (assign.type !== Syntax.AssignmentExpression) if (assign.left.type !== Syntax.Identifier) return false;
Expand Down Expand Up @@ -845,19 +851,19 @@ if (typeof exports !== 'undefined') {
break;
case Syntax.SwitchStatement:
for (var i = 0; i < node.cases.length; i++) {
var stmts = node.cases[i].consequent;
if (node._async && stmts.body.length > 0 && !stmts._breaks) {
var stmts = node.cases[i];
if (node._async && stmts.consequent.length > 0 && !stmts._breaks) {
// narcissus has the strange idea of inserting an empty default after last case.
// If we detect this and if the last case is not terminated by a break, we do not consider it an error
// and we just fix it by adding a break.
if (i == node.cases.length - 2 && node.cases[i + 1].test == null //
&& node.cases[i + 1].consequent.body.length === 1 //
&& node.cases[i + 1].consequent.body[0].type === Syntax.ExpressionStatement //
&& node.cases[i + 1].consequent.body[0].expression == null) {
stmts.body.push(_node(node, Syntax.BreakStatement));
&& node.cases[i + 1].consequent.length === 1 //
&& node.cases[i + 1].consequent[0].type === Syntax.ExpressionStatement //
&& node.cases[i + 1].consequent[0].expression == null) {
stmts.consequent.push(_node(node, Syntax.BreakStatement));
stmts._breaks = true;
} else if (i === node.cases.length - 1) {
stmts.body.push(_node(node, Syntax.BreakStatement));
stmts.consequent.push(_node(node, Syntax.BreakStatement));
stmts._breaks = true;
} else {
// we rewrite:
Expand All @@ -873,14 +879,16 @@ if (typeof exports !== 'undefined') {
// if (__B) no_break_B
// breaking_C
var v = _identifier(_genId(node));
node.cases[i].consequent = _switchVarTemplate.generate(node.cases[i], {
$v: v,
});
node.cases[i].consequent = [_node(node, Syntax.BlockStatement, {
body: [_switchVarTemplate.generate(node.cases[i], {
$v: v,
})],
})];
var ifStmt = _switchIfTemplate.generate(node.cases[i], {
$v: v,
$block: stmts,
$block: stmts.consequent[0],
});
node.cases[i + 1].consequent.body.splice(0, 0, ifStmt);
node.cases[i + 1].consequent[0].body.splice(0, 0, ifStmt);
}
}
}
Expand All @@ -894,6 +902,10 @@ if (typeof exports !== 'undefined') {
node._breaks |= child._breaks;
});
break;
case Syntax.SwitchCase:
if (node.consequent.length !== 1) throw new Error("internal error: SwitchCase not wrapped: " + node.consequent.length);
node._breaks |= node.consequent[0]._breaks;
break;
case Syntax.ReturnStatement:
case Syntax.ThrowStatement:
case Syntax.BreakStatement:
Expand Down Expand Up @@ -1050,14 +1062,14 @@ if (typeof exports !== 'undefined') {
})[0];
if (!def) {
def = _node(node, Syntax.SwitchCase, {
consequent: _node(node, Syntax.BlockStatement, {
body: []
}),
consequent: [_node(node, Syntax.BlockStatement, {
body: [],
})],
});
node.cases.push(def);
}
if (!def._breaks) {
def.consequent.body.push(_node(node, Syntax.BreakStatement))
def.consequent.push(_node(node, Syntax.BreakStatement));
}
}
break;
Expand Down Expand Up @@ -1102,8 +1114,8 @@ if (typeof exports !== 'undefined') {
case Syntax.ForInStatement:
node.body = _blockify(node.body);
if (node._async) {
if (node.iterator.type != Syntax.Identifier) {
throw new Error("unsupported 'for ... in' syntax: type=" + node.iterator.type);
if (node.left.type != Syntax.Identifier) {
throw new Error("unsupported 'for ... in' syntax: type=" + node.left.type);
}
node = _flowsTemplates.FOR_IN.generate(node, {
$array: _identifier(_genId(node)),
Expand Down Expand Up @@ -1486,7 +1498,7 @@ if (typeof exports !== 'undefined') {
_extractTail(parent, i);
if (node.label) {
node = _cbTemplates.LABELLED_BREAK.generate(node, {
$break: _safeName(options.precious, '__break__' + node.label)
$break: _safeName(options.precious, '__break__' + node.label.name)
});
} else {
node = _cbTemplates.BREAK.generate(node, {});
Expand All @@ -1499,8 +1511,8 @@ if (typeof exports !== 'undefined') {
_extractTail(parent, i);
if (node.label) {
node = _cbTemplates.LABELLED_CONTINUE.generate(node, {
$loop: _safeName(options.precious, '__loop__' + node.label),
$more: _safeName(options.precious, '__more__' + node.label),
$loop: _safeName(options.precious, '__loop__' + node.label.name),
$more: _safeName(options.precious, '__more__' + node.label.name),
});
} else {
node = _cbTemplates.CONTINUE.generate(node, {});
Expand Down Expand Up @@ -1550,7 +1562,7 @@ if (typeof exports !== 'undefined') {
break;
case Syntax.LabeledStatement:
var l = label;
label = node.label;
label = node.label.name;
node = _cbTemplates.LABEL.generate(node, {
$name: "__$" + node._scope.name,
$statement: node.body,
Expand Down Expand Up @@ -1600,7 +1612,7 @@ if (typeof exports !== 'undefined') {
_assert(call.type === Syntax.CallExpression)
return _restructureCall(call, tail);
default:
throw new Error("internal error: bad node type: " + _tag(node) + ": " + escodegen.generate(node));
throw new Error("internal error: bad node type: " + node.type + ": " + escodegen.generate(node));
}
}
}
Expand Down Expand Up @@ -1790,9 +1802,12 @@ if (typeof exports !== 'undefined') {
options.precious = {}; // identifiers found inside source
//console.log("TRANSFORMING " + options.sourceName)
//console.log("source=" + source);
var node = esprima.parse(source + "\n", {
// esprima does not like return at top level so we wrap into a function
// also \n is needed before } in case last line ends on a // comment
var node = esprima.parse("function dummy(){" + source + "\n}", {
loc: true,
}); // final newline avoids infinite loop if unterminated string literal at the end
});
node = node.body[0].body;
//console.log(JSON.stringify(node, null, ' '));
var strict = node.body[0] && node.body[0].expression && node.body[0].expression.value == "use strict";
strict && node.body.splice(0, 1);
Expand All @@ -1814,6 +1829,9 @@ if (typeof exports !== 'undefined') {
node = _simplify(node, options, used);

var result = escodegen.generate(node); //, options.lines);
// remove curly braces around generated source
result = result.substring(1, result.length - 1);


// add helpers at beginning so that __g is initialized before any other code
if (!options.noHelpers) {
Expand Down

0 comments on commit 66ef19e

Please sign in to comment.