Fix reused nodes - part 2 (#7149)

This commit is contained in:
Nicolò Ribaudo 2018-01-11 19:31:48 +01:00
parent 912bcc186d
commit 252ea5a966
20 changed files with 261 additions and 170 deletions

View File

@ -131,7 +131,7 @@ export default class File {
const res = generator(name); const res = generator(name);
if (res) return res; if (res) return res;
} else if (runtime) { } else if (runtime) {
return t.memberExpression(runtime, t.identifier(name)); return t.memberExpression(t.cloneNode(runtime), t.identifier(name));
} }
const uid = (this.declarations[name] = this.scope.generateUidIdentifier( const uid = (this.declarations[name] = this.scope.generateUidIdentifier(

View File

@ -154,7 +154,7 @@ export default function({ node, parent, scope, id }, localBinding = false) {
scope.getBinding(id.name) === binding scope.getBinding(id.name) === binding
) { ) {
// always going to reference this method // always going to reference this method
node.id = id; node.id = t.cloneNode(id);
node.id[t.NOT_LOCAL_BINDING] = true; node.id[t.NOT_LOCAL_BINDING] = true;
return; return;
} }

View File

@ -22,7 +22,7 @@ const awaitVisitor = {
path.replaceWith( path.replaceWith(
t.yieldExpression( t.yieldExpression(
wrapAwait wrapAwait
? t.callExpression(wrapAwait, [argument.node]) ? t.callExpression(t.cloneNode(wrapAwait), [argument.node])
: argument.node, : argument.node,
), ),
); );
@ -73,7 +73,7 @@ export default function(path: NodePath, file: Object, helpers: Object) {
path.node.async = false; path.node.async = false;
path.node.generator = true; path.node.generator = true;
wrapFunction(path, helpers.wrapAsync); wrapFunction(path, t.cloneNode(helpers.wrapAsync));
const isProperty = const isProperty =
path.isObjectMethod() || path.isObjectMethod() ||

View File

@ -41,7 +41,7 @@ function getPrototypeOfExpression(objectRef, isStatic) {
t.identifier("Object"), t.identifier("Object"),
t.identifier("getPrototypeOf"), t.identifier("getPrototypeOf"),
), ),
[targetRef], [t.cloneNode(targetRef)],
), ),
); );
} }
@ -141,7 +141,7 @@ export default class ReplaceSupers {
}; };
getObjectRef() { getObjectRef() {
return this.opts.objectRef || this.opts.getObjectRef(); return t.cloneNode(this.opts.objectRef || this.opts.getObjectRef());
} }
/** /**
@ -244,7 +244,7 @@ export default class ReplaceSupers {
ref = ref || path.scope.generateUidIdentifier("ref"); ref = ref || path.scope.generateUidIdentifier("ref");
return [ return [
t.variableDeclaration("var", [ t.variableDeclaration("var", [
t.variableDeclarator(t.cloneNode(ref), node.left), t.variableDeclarator(t.cloneNode(ref), t.cloneNode(node.left)),
]), ]),
t.expressionStatement( t.expressionStatement(
t.assignmentExpression( t.assignmentExpression(

View File

@ -33,20 +33,20 @@ const simpleAssignmentVisitor = {
t.assignmentExpression("+=", arg.node, t.numericLiteral(1)), t.assignmentExpression("+=", arg.node, t.numericLiteral(1)),
); );
} else { } else {
const varName = path.scope.generateDeclaredUidIdentifier("old"); const varName = path.scope.generateDeclaredUidIdentifier("old").name;
const assignment = t.binaryExpression( const binary = t.binaryExpression(
path.node.operator.slice(0, 1), path.node.operator.slice(0, 1),
varName, t.identifier(varName),
t.numericLiteral(1), t.numericLiteral(1),
); );
// i++ => (_tmp = i, i = _tmp + 1, _tmp) // i++ => (_tmp = i, i = _tmp + 1, _tmp)
path.replaceWith( path.replaceWith(
t.sequenceExpression([ t.sequenceExpression([
t.assignmentExpression("=", varName, arg.node), t.assignmentExpression("=", t.identifier(varName), arg.node),
t.assignmentExpression("=", arg.node, assignment), t.assignmentExpression("=", t.cloneNode(arg.node), binary),
varName, t.identifier(varName),
]), ]),
); );
} }
@ -78,7 +78,7 @@ const simpleAssignmentVisitor = {
path.node.right = t.binaryExpression( path.node.right = t.binaryExpression(
path.node.operator.slice(0, -1), path.node.operator.slice(0, -1),
path.node.left, t.cloneNode(path.node.left),
path.node.right, path.node.right,
); );
path.node.operator = "="; path.node.operator = "=";

View File

@ -7,23 +7,26 @@ export default function() {
t.isIdentifier(node.meta, { name: "function" }) && t.isIdentifier(node.meta, { name: "function" }) &&
t.isIdentifier(node.property, { name: "sent" }); t.isIdentifier(node.property, { name: "sent" });
const hasBeenReplaced = (node, sentId) =>
t.isAssignmentExpression(node) &&
t.isIdentifier(node.left, { name: sentId });
const yieldVisitor = { const yieldVisitor = {
Function(path) { Function(path) {
path.skip(); path.skip();
}, },
YieldExpression(path) { YieldExpression(path) {
const replaced = t.isAssignmentExpression(path.parent, { if (!hasBeenReplaced(path.parent, this.sentId)) {
left: this.sentId, path.replaceWith(
}); t.assignmentExpression("=", t.identifier(this.sentId), path.node),
if (!replaced) { );
path.replaceWith(t.assignmentExpression("=", this.sentId, path.node));
} }
}, },
MetaProperty(path) { MetaProperty(path) {
if (isFunctionSent(path.node)) { if (isFunctionSent(path.node)) {
path.replaceWith(this.sentId); path.replaceWith(t.identifier(this.sentId));
} }
}, },
}; };
@ -41,12 +44,12 @@ export default function() {
throw new Error("Parent generator function not found"); throw new Error("Parent generator function not found");
} }
const sentId = path.scope.generateUidIdentifier("function.sent"); const sentId = path.scope.generateUid("function.sent");
fnPath.traverse(yieldVisitor, { sentId }); fnPath.traverse(yieldVisitor, { sentId });
fnPath.node.body.body.unshift( fnPath.node.body.body.unshift(
t.variableDeclaration("let", [ t.variableDeclaration("let", [
t.variableDeclarator(sentId, t.yieldExpression()), t.variableDeclarator(t.identifier(sentId), t.yieldExpression()),
]), ]),
); );

View File

@ -43,7 +43,7 @@ export default function(api, opts) {
} else if (t.isLiteral(prop.key)) { } else if (t.isLiteral(prop.key)) {
keys.push(t.stringLiteral(String(prop.key.value))); keys.push(t.stringLiteral(String(prop.key.value)));
} else { } else {
keys.push(prop.key); keys.push(t.cloneNode(prop.key));
allLiteral = false; allLiteral = false;
} }
} }
@ -58,12 +58,10 @@ export default function(api, opts) {
for (const propPath of path.get("properties")) { for (const propPath of path.get("properties")) {
const key = propPath.get("key"); const key = propPath.get("key");
if (propPath.node.computed && !key.isPure()) { if (propPath.node.computed && !key.isPure()) {
const identifier = path.scope.generateUidIdentifierBasedOnNode( const name = path.scope.generateUidBasedOnNode(key.node);
key.node, const declarator = t.variableDeclarator(t.identifier(name), key.node);
);
const declarator = t.variableDeclarator(identifier, key.node);
impureComputedPropertyDeclarators.push(declarator); impureComputedPropertyDeclarators.push(declarator);
key.replaceWith(identifier); key.replaceWith(t.identifier(name));
} }
} }
return impureComputedPropertyDeclarators; return impureComputedPropertyDeclarators;
@ -272,14 +270,14 @@ export default function(api, opts) {
if (leftPath.isObjectPattern() && hasRestElement(leftPath)) { if (leftPath.isObjectPattern() && hasRestElement(leftPath)) {
const nodes = []; const nodes = [];
const ref = path.scope.generateUidIdentifierBasedOnNode( const refName = path.scope.generateUidBasedOnNode(
path.node.right, path.node.right,
"ref", "ref",
); );
nodes.push( nodes.push(
t.variableDeclaration("var", [ t.variableDeclaration("var", [
t.variableDeclarator(ref, path.node.right), t.variableDeclarator(t.identifier(refName), path.node.right),
]), ]),
); );
@ -287,7 +285,7 @@ export default function(api, opts) {
impureComputedPropertyDeclarators, impureComputedPropertyDeclarators,
argument, argument,
callExpression, callExpression,
] = createObjectSpread(leftPath, file, ref); ] = createObjectSpread(leftPath, file, t.identifier(refName));
if (impureComputedPropertyDeclarators.length > 0) { if (impureComputedPropertyDeclarators.length > 0) {
nodes.push( nodes.push(
@ -296,17 +294,14 @@ export default function(api, opts) {
} }
const nodeWithoutSpread = t.cloneNode(path.node); const nodeWithoutSpread = t.cloneNode(path.node);
nodeWithoutSpread.right = ref; nodeWithoutSpread.right = t.identifier(refName);
nodes.push(t.expressionStatement(nodeWithoutSpread)); nodes.push(t.expressionStatement(nodeWithoutSpread));
nodes.push( nodes.push(
t.toStatement( t.toStatement(
t.assignmentExpression("=", argument, callExpression), t.assignmentExpression("=", argument, callExpression),
), ),
); );
nodes.push(t.expressionStatement(t.identifier(refName)));
if (ref) {
nodes.push(t.expressionStatement(ref));
}
path.replaceWithMultiple(nodes); path.replaceWithMultiple(nodes);
} }

View File

@ -42,7 +42,9 @@ export default function(api, options) {
check = t.assignmentExpression( check = t.assignmentExpression(
"=", "=",
t.cloneNode(ref), t.cloneNode(ref),
t.cloneNode(chain), // Here `chain` MUST NOT be cloned because it could be updated
// when generating the memoised context of a call espression
chain,
); );
node[replaceKey] = ref; node[replaceKey] = ref;
} else { } else {

View File

@ -1,12 +1,12 @@
var _foo, _foo2, _foo$bar, _foo3, _foo3$bar, _foo4, _foo5, _foo6, _foo$bar2, _foo$bar3, _foo$bar3$call, _foo7, _foo7$bar, _foo8, _foo8$bar, _foo8$bar$call; var _foo, _foo2, _foo$bar, _foo3, _foo4, _foo4$bar, _foo5, _foo6, _foo7, _foo$bar2, _foo8, _foo$bar3, _foo9, _foo$bar3$call, _foo10, _foo10$bar, _foo11, _foo11$bar, _foo11$bar$call;
(_foo = foo) === null || _foo === void 0 ? void 0 : _foo(foo); (_foo = foo) === null || _foo === void 0 ? void 0 : _foo(foo);
(_foo2 = foo) === null || _foo2 === void 0 ? void 0 : _foo2.bar(); (_foo2 = foo) === null || _foo2 === void 0 ? void 0 : _foo2.bar();
(_foo$bar = foo.bar) === null || _foo$bar === void 0 ? void 0 : _foo$bar.call(foo, foo.bar, false); (_foo$bar = (_foo3 = foo).bar) === null || _foo$bar === void 0 ? void 0 : _foo$bar.call(_foo3, foo.bar, false);
(_foo3 = foo) === null || _foo3 === void 0 ? void 0 : (_foo3$bar = _foo3.bar) === null || _foo3$bar === void 0 ? void 0 : _foo3$bar.call(_foo3, foo.bar, true); (_foo4 = foo) === null || _foo4 === void 0 ? void 0 : (_foo4$bar = _foo4.bar) === null || _foo4$bar === void 0 ? void 0 : _foo4$bar.call(_foo4, foo.bar, true);
(_foo4 = foo) === null || _foo4 === void 0 ? void 0 : _foo4().bar; (_foo5 = foo) === null || _foo5 === void 0 ? void 0 : _foo5().bar;
(_foo5 = foo) === null || _foo5 === void 0 ? void 0 : (_foo6 = _foo5()) === null || _foo6 === void 0 ? void 0 : _foo6.bar; (_foo6 = foo) === null || _foo6 === void 0 ? void 0 : (_foo7 = _foo6()) === null || _foo7 === void 0 ? void 0 : _foo7.bar;
(_foo$bar2 = foo.bar) === null || _foo$bar2 === void 0 ? void 0 : _foo$bar2.call(foo).baz; (_foo$bar2 = (_foo8 = foo).bar) === null || _foo$bar2 === void 0 ? void 0 : _foo$bar2.call(_foo8).baz;
(_foo$bar3 = foo.bar) === null || _foo$bar3 === void 0 ? void 0 : (_foo$bar3$call = _foo$bar3.call(foo)) === null || _foo$bar3$call === void 0 ? void 0 : _foo$bar3$call.baz; (_foo$bar3 = (_foo9 = foo).bar) === null || _foo$bar3 === void 0 ? void 0 : (_foo$bar3$call = _foo$bar3.call(_foo9)) === null || _foo$bar3$call === void 0 ? void 0 : _foo$bar3$call.baz;
(_foo7 = foo) === null || _foo7 === void 0 ? void 0 : (_foo7$bar = _foo7.bar) === null || _foo7$bar === void 0 ? void 0 : _foo7$bar.call(_foo7).baz; (_foo10 = foo) === null || _foo10 === void 0 ? void 0 : (_foo10$bar = _foo10.bar) === null || _foo10$bar === void 0 ? void 0 : _foo10$bar.call(_foo10).baz;
(_foo8 = foo) === null || _foo8 === void 0 ? void 0 : (_foo8$bar = _foo8.bar) === null || _foo8$bar === void 0 ? void 0 : (_foo8$bar$call = _foo8$bar.call(_foo8)) === null || _foo8$bar$call === void 0 ? void 0 : _foo8$bar$call.baz; (_foo11 = foo) === null || _foo11 === void 0 ? void 0 : (_foo11$bar = _foo11.bar) === null || _foo11$bar === void 0 ? void 0 : (_foo11$bar$call = _foo11$bar.call(_foo11)) === null || _foo11$bar$call === void 0 ? void 0 : _foo11$bar$call.baz;

View File

@ -524,7 +524,7 @@ class BlockScoping {
this.hoistVarDeclarations(); this.hoistVarDeclarations();
// turn outsideLetReferences into an array // turn outsideLetReferences into an array
const args = values(outsideRefs); const args = values(outsideRefs).map(id => t.cloneNode(id));
const params = args.map(id => t.cloneNode(id)); const params = args.map(id => t.cloneNode(id));
const isSwitch = this.blockPath.isSwitchStatement(); const isSwitch = this.blockPath.isSwitchStatement();
@ -569,10 +569,12 @@ class BlockScoping {
let placeholderPath; let placeholderPath;
let index; let index;
if (this.has.hasReturn || this.has.hasBreakContinue) { if (this.has.hasReturn || this.has.hasBreakContinue) {
const ret = this.scope.generateUidIdentifier("ret"); const ret = this.scope.generateUid("ret");
this.body.push( this.body.push(
t.variableDeclaration("var", [t.variableDeclarator(ret, call)]), t.variableDeclaration("var", [
t.variableDeclarator(t.identifier(ret), call),
]),
); );
placeholderPath = "declarations.0.init" + basePath; placeholderPath = "declarations.0.init" + basePath;
index = this.body.length - 1; index = this.body.length - 1;
@ -600,12 +602,14 @@ class BlockScoping {
let fnPath; let fnPath;
if (this.loop) { if (this.loop) {
const ref = this.scope.generateUidIdentifier("loop"); const loopId = this.scope.generateUid("loop");
const p = this.loopPath.insertBefore( const p = this.loopPath.insertBefore(
t.variableDeclaration("var", [t.variableDeclarator(ref, fn)]), t.variableDeclaration("var", [
t.variableDeclarator(t.identifier(loopId), fn),
]),
); );
placeholder.replaceWith(ref); placeholder.replaceWith(t.identifier(loopId));
fnPath = p[0].get("declarations.0.init"); fnPath = p[0].get("declarations.0.init");
} else { } else {
placeholder.replaceWith(fn); placeholder.replaceWith(fn);
@ -637,20 +641,33 @@ class BlockScoping {
const param = fn.params[i]; const param = fn.params[i];
if (!state.reassignments[param.name]) continue; if (!state.reassignments[param.name]) continue;
const newParam = this.scope.generateUidIdentifier(param.name); const paramName = param.name;
fn.params[i] = newParam; const newParamName = this.scope.generateUid(param.name);
fn.params[i] = t.identifier(newParamName);
this.scope.rename(param.name, newParam.name, fn); this.scope.rename(paramName, newParamName, fn);
state.returnStatements.forEach(returnStatement => { state.returnStatements.forEach(returnStatement => {
returnStatement.insertBefore( returnStatement.insertBefore(
t.expressionStatement(t.assignmentExpression("=", param, newParam)), t.expressionStatement(
t.assignmentExpression(
"=",
t.identifier(paramName),
t.identifier(newParamName),
),
),
); );
}); });
// assign outer reference as it's been modified internally and needs to be retained // assign outer reference as it's been modified internally and needs to be retained
fn.body.body.push( fn.body.body.push(
t.expressionStatement(t.assignmentExpression("=", param, newParam)), t.expressionStatement(
t.assignmentExpression(
"=",
t.identifier(paramName),
t.identifier(newParamName),
),
),
); );
} }
} }
@ -793,14 +810,18 @@ class BlockScoping {
const declar = node.declarations[i]; const declar = node.declarations[i];
if (!declar.init) continue; if (!declar.init) continue;
const expr = t.assignmentExpression("=", declar.id, declar.init); const expr = t.assignmentExpression(
"=",
t.cloneNode(declar.id),
t.cloneNode(declar.init),
);
replace.push(t.inherits(expr, declar)); replace.push(t.inherits(expr, declar));
} }
return replace; return replace;
} }
buildHas(ret: { type: "Identifier" }) { buildHas(ret: string) {
const body = this.body; const body = this.body;
let retCheck; let retCheck;
@ -810,7 +831,7 @@ class BlockScoping {
if (has.hasReturn) { if (has.hasReturn) {
// typeof ret === "object" // typeof ret === "object"
retCheck = buildRetCheck({ retCheck = buildRetCheck({
RETURN: ret, RETURN: t.identifier(ret),
}); });
} }
@ -827,7 +848,7 @@ class BlockScoping {
const single = cases[0]; const single = cases[0];
body.push( body.push(
t.ifStatement( t.ifStatement(
t.binaryExpression("===", ret, single.test), t.binaryExpression("===", t.identifier(ret), single.test),
single.consequent[0], single.consequent[0],
), ),
); );
@ -837,13 +858,15 @@ class BlockScoping {
for (let i = 0; i < cases.length; i++) { for (let i = 0; i < cases.length; i++) {
const caseConsequent = cases[i].consequent[0]; const caseConsequent = cases[i].consequent[0];
if (t.isBreakStatement(caseConsequent) && !caseConsequent.label) { if (t.isBreakStatement(caseConsequent) && !caseConsequent.label) {
caseConsequent.label = this.loopLabel = if (!this.loopLabel) {
this.loopLabel || this.scope.generateUidIdentifier("loop"); this.loopLabel = this.scope.generateUidIdentifier("loop");
}
caseConsequent.label = t.cloneNode(this.loopLabel);
} }
} }
} }
body.push(t.switchStatement(ret, cases)); body.push(t.switchStatement(t.identifier(ret), cases));
} }
} else { } else {
if (has.hasReturn) { if (has.hasReturn) {

View File

@ -122,16 +122,18 @@ export default class ClassTransformer {
if (this.isDerived) { if (this.isDerived) {
if (this.extendsNative) { if (this.extendsNative) {
closureArgs.push( closureArgs.push(
t.callExpression(this.file.addHelper("wrapNativeSuper"), [superName]), t.callExpression(this.file.addHelper("wrapNativeSuper"), [
t.cloneNode(superName),
]),
); );
} else { } else {
closureArgs.push(superName); closureArgs.push(t.cloneNode(superName));
} }
superName = this.scope.generateUidIdentifierBasedOnNode(superName); superName = this.scope.generateUidIdentifierBasedOnNode(superName);
closureParams.push(superName); closureParams.push(superName);
this.superName = superName; this.superName = t.cloneNode(superName);
} }
// //
@ -143,13 +145,15 @@ export default class ClassTransformer {
t.expressionStatement( t.expressionStatement(
t.callExpression(file.addHelper("classCallCheck"), [ t.callExpression(file.addHelper("classCallCheck"), [
t.thisExpression(), t.thisExpression(),
this.classRef, t.cloneNode(this.classRef),
]), ]),
), ),
); );
} }
body = body.concat(this.staticPropBody.map(fn => fn(this.classRef))); body = body.concat(
this.staticPropBody.map(fn => fn(t.cloneNode(this.classRef))),
);
if (this.classId) { if (this.classId) {
// named class with only a constructor // named class with only a constructor
@ -157,7 +161,7 @@ export default class ClassTransformer {
} }
// //
body.push(t.returnStatement(this.classRef)); body.push(t.returnStatement(t.cloneNode(this.classRef)));
const container = t.arrowFunctionExpression( const container = t.arrowFunctionExpression(
closureParams, closureParams,
@ -167,7 +171,11 @@ export default class ClassTransformer {
} }
buildConstructor() { buildConstructor() {
const func = t.functionDeclaration(this.classRef, [], this.constructorBody); const func = t.functionDeclaration(
t.cloneNode(this.classRef),
[],
this.constructorBody,
);
t.inherits(func, this.node); t.inherits(func, this.node);
return func; return func;
} }
@ -327,14 +335,12 @@ export default class ClassTransformer {
staticProps = defineMap.toComputedObjectFromClass(staticProps); staticProps = defineMap.toComputedObjectFromClass(staticProps);
} }
const nullNode = t.nullLiteral();
let args = [ let args = [
this.classRef, // Constructor t.cloneNode(this.classRef), // Constructor
nullNode, // instanceDescriptors t.nullLiteral(), // instanceDescriptors
nullNode, // staticDescriptors t.nullLiteral(), // staticDescriptors
nullNode, // instanceInitializers t.nullLiteral(), // instanceInitializers
nullNode, // staticInitializers t.nullLiteral(), // staticInitializers
]; ];
if (instanceProps) args[1] = instanceProps; if (instanceProps) args[1] = instanceProps;
@ -352,7 +358,7 @@ export default class ClassTransformer {
let lastNonNullIndex = 0; let lastNonNullIndex = 0;
for (let i = 0; i < args.length; i++) { for (let i = 0; i < args.length; i++) {
if (args[i] !== nullNode) lastNonNullIndex = i; if (!t.isNullLiteral(args[i])) lastNonNullIndex = i;
} }
args = args.slice(0, lastNonNullIndex + 1); args = args.slice(0, lastNonNullIndex + 1);
@ -400,13 +406,16 @@ export default class ClassTransformer {
bareSuperNode = optimiseCall( bareSuperNode = optimiseCall(
t.logicalExpression( t.logicalExpression(
"||", "||",
t.memberExpression(this.classRef, t.identifier("__proto__")), t.memberExpression(
t.cloneNode(this.classRef),
t.identifier("__proto__"),
),
t.callExpression( t.callExpression(
t.memberExpression( t.memberExpression(
t.identifier("Object"), t.identifier("Object"),
t.identifier("getPrototypeOf"), t.identifier("getPrototypeOf"),
), ),
[this.classRef], [t.cloneNode(this.classRef)],
), ),
), ),
t.thisExpression(), t.thisExpression(),
@ -607,7 +616,7 @@ export default class ClassTransformer {
this.isLoose this.isLoose
? this.file.addHelper("inheritsLoose") ? this.file.addHelper("inheritsLoose")
: this.file.addHelper("inherits"), : this.file.addHelper("inherits"),
[this.classRef, this.superName], [t.cloneNode(this.classRef), t.cloneNode(this.superName)],
), ),
), ),
); );

View File

@ -112,12 +112,10 @@ export default function(api, options) {
// we need to assign the current value of the assignment to avoid evaluating // we need to assign the current value of the assignment to avoid evaluating
// it more than once // it more than once
const tempValueRef = this.scope.generateUidIdentifierBasedOnNode( const tempValueRef = this.scope.generateUidBasedOnNode(valueRef);
valueRef,
);
const declar = t.variableDeclaration("var", [ const declar = t.variableDeclaration("var", [
t.variableDeclarator(tempValueRef, valueRef), t.variableDeclarator(t.identifier(tempValueRef), valueRef),
]); ]);
declar._blockHoist = this.blockHoist; declar._blockHoist = this.blockHoist;
this.nodes.push(declar); this.nodes.push(declar);
@ -127,22 +125,26 @@ export default function(api, options) {
const tempConditional = t.conditionalExpression( const tempConditional = t.conditionalExpression(
t.binaryExpression( t.binaryExpression(
"===", "===",
tempValueRef, t.identifier(tempValueRef),
this.scope.buildUndefinedNode(), this.scope.buildUndefinedNode(),
), ),
pattern.right, pattern.right,
tempValueRef, t.identifier(tempValueRef),
); );
const left = pattern.left; const left = pattern.left;
if (t.isPattern(left)) { if (t.isPattern(left)) {
const tempValueDefault = t.expressionStatement( const tempValueDefault = t.expressionStatement(
t.assignmentExpression("=", tempValueRef, tempConditional), t.assignmentExpression(
"=",
t.identifier(tempValueRef),
tempConditional,
),
); );
tempValueDefault._blockHoist = this.blockHoist; tempValueDefault._blockHoist = this.blockHoist;
this.nodes.push(tempValueDefault); this.nodes.push(tempValueDefault);
this.push(left, tempValueRef); this.push(left, t.identifier(tempValueRef));
} else { } else {
this.nodes.push(this.buildVariableAssignment(left, tempConditional)); this.nodes.push(this.buildVariableAssignment(left, tempConditional));
} }

View File

@ -25,7 +25,11 @@ export default function(api, options) {
array = right; array = right;
} }
const item = t.memberExpression(array, t.cloneNode(i), true); const item = t.memberExpression(
t.cloneNode(array),
t.cloneNode(i),
true,
);
let assignment; let assignment;
if (t.isVariableDeclaration(left)) { if (t.isVariableDeclaration(left)) {
assignment = left; assignment = left;
@ -112,11 +116,13 @@ export default function(api, options) {
let right = node.right; let right = node.right;
if (!t.isIdentifier(right) || !scope.hasBinding(right.name)) { if (!t.isIdentifier(right) || !scope.hasBinding(right.name)) {
const uid = scope.generateUidIdentifier("arr"); const uid = scope.generateUid("arr");
nodes.push( nodes.push(
t.variableDeclaration("var", [t.variableDeclarator(uid, right)]), t.variableDeclaration("var", [
t.variableDeclarator(t.identifier(uid), right),
]),
); );
right = uid; right = t.identifier(uid);
} }
const iterationKey = scope.generateUidIdentifier("i"); const iterationKey = scope.generateUidIdentifier("i");
@ -130,7 +136,11 @@ export default function(api, options) {
t.inherits(loop, node); t.inherits(loop, node);
t.ensureBlock(loop); t.ensureBlock(loop);
const iterationValue = t.memberExpression(right, iterationKey, true); const iterationValue = t.memberExpression(
t.cloneNode(right),
t.cloneNode(iterationKey),
true,
);
const left = node.left; const left = node.left;
if (t.isVariableDeclaration(left)) { if (t.isVariableDeclaration(left)) {
@ -221,9 +231,11 @@ export default function(api, options) {
// for (let i of test) // for (let i of test)
id = scope.generateUidIdentifier("ref"); id = scope.generateUidIdentifier("ref");
declar = t.variableDeclaration(left.kind, [ declar = t.variableDeclaration(left.kind, [
t.variableDeclarator(left.declarations[0].id, id), t.variableDeclarator(left.declarations[0].id, t.identifier(id.name)),
]);
intermediate = t.variableDeclaration("var", [
t.variableDeclarator(t.identifier(id.name)),
]); ]);
intermediate = t.variableDeclaration("var", [t.variableDeclarator(id)]);
} else { } else {
throw file.buildCodeFrameError( throw file.buildCodeFrameError(
left, left,
@ -264,8 +276,11 @@ export default function(api, options) {
const left = node.left; const left = node.left;
let declar; let declar;
const stepKey = scope.generateUidIdentifier("step"); const stepKey = scope.generateUid("step");
const stepValue = t.memberExpression(stepKey, t.identifier("value")); const stepValue = t.memberExpression(
t.identifier(stepKey),
t.identifier("value"),
);
if ( if (
t.isIdentifier(left) || t.isIdentifier(left) ||
@ -288,18 +303,14 @@ export default function(api, options) {
); );
} }
//
const iteratorKey = scope.generateUidIdentifier("iterator");
const template = buildForOf({ const template = buildForOf({
ITERATOR_HAD_ERROR_KEY: scope.generateUidIdentifier("didIteratorError"), ITERATOR_HAD_ERROR_KEY: scope.generateUidIdentifier("didIteratorError"),
ITERATOR_COMPLETION: scope.generateUidIdentifier( ITERATOR_COMPLETION: scope.generateUidIdentifier(
"iteratorNormalCompletion", "iteratorNormalCompletion",
), ),
ITERATOR_ERROR_KEY: scope.generateUidIdentifier("iteratorError"), ITERATOR_ERROR_KEY: scope.generateUidIdentifier("iteratorError"),
ITERATOR_KEY: iteratorKey, ITERATOR_KEY: scope.generateUidIdentifier("iterator"),
STEP_KEY: stepKey, STEP_KEY: t.identifier(stepKey),
OBJECT: node.right, OBJECT: node.right,
}); });

View File

@ -15,7 +15,7 @@ export default function() {
[], [],
t.blockStatement([ t.blockStatement([
t.toStatement(node), t.toStatement(node),
t.returnStatement(node.id), t.returnStatement(t.cloneNode(node.id)),
]), ]),
), ),
[], [],

View File

@ -50,9 +50,17 @@ export default function(api, options) {
let isPostUpdateExpression = path.isUpdateExpression() && !node.prefix; let isPostUpdateExpression = path.isUpdateExpression() && !node.prefix;
if (isPostUpdateExpression) { if (isPostUpdateExpression) {
if (node.operator === "++") { if (node.operator === "++") {
node = t.binaryExpression("+", node.argument, t.numericLiteral(1)); node = t.binaryExpression(
"+",
t.cloneNode(node.argument),
t.numericLiteral(1),
);
} else if (node.operator === "--") { } else if (node.operator === "--") {
node = t.binaryExpression("-", node.argument, t.numericLiteral(1)); node = t.binaryExpression(
"-",
t.cloneNode(node.argument),
t.numericLiteral(1),
);
} else { } else {
isPostUpdateExpression = false; isPostUpdateExpression = false;
} }
@ -74,10 +82,12 @@ export default function(api, options) {
visitor: { visitor: {
CallExpression(path, state) { CallExpression(path, state) {
if (path.node.callee.type === TYPE_IMPORT) { if (path.node.callee.type === TYPE_IMPORT) {
const contextIdent = state.contextIdent;
path.replaceWith( path.replaceWith(
t.callExpression( t.callExpression(
t.memberExpression(contextIdent, t.identifier("import")), t.memberExpression(
t.identifier(state.contextIdent),
t.identifier("import"),
),
path.node.arguments, path.node.arguments,
), ),
); );
@ -90,17 +100,20 @@ export default function(api, options) {
!path.scope.hasBinding("__moduleName") !path.scope.hasBinding("__moduleName")
) { ) {
path.replaceWith( path.replaceWith(
t.memberExpression(state.contextIdent, t.identifier("id")), t.memberExpression(
t.identifier(state.contextIdent),
t.identifier("id"),
),
); );
} }
}, },
Program: { Program: {
enter(path, state) { enter(path, state) {
state.contextIdent = path.scope.generateUidIdentifier("context"); state.contextIdent = path.scope.generateUid("context");
}, },
exit(path, state) { exit(path, state) {
const exportIdent = path.scope.generateUidIdentifier("export"); const exportIdent = path.scope.generateUid("export");
const contextIdent = state.contextIdent; const contextIdent = state.contextIdent;
const exportNames = Object.create(null); const exportNames = Object.create(null);
@ -134,7 +147,10 @@ export default function(api, options) {
function buildExportCall(name, val) { function buildExportCall(name, val) {
return t.expressionStatement( return t.expressionStatement(
t.callExpression(exportIdent, [t.stringLiteral(name), val]), t.callExpression(t.identifier(exportIdent), [
t.stringLiteral(name),
val,
]),
); );
} }
@ -175,7 +191,7 @@ export default function(api, options) {
if (id) { if (id) {
nodes.push(declar.node); nodes.push(declar.node);
nodes.push(buildExportCall("default", id)); nodes.push(buildExportCall("default", t.cloneNode(id)));
addExportName(id.name, "default"); addExportName(id.name, "default");
} else { } else {
nodes.push( nodes.push(
@ -206,7 +222,9 @@ export default function(api, options) {
if (canHoist) { if (canHoist) {
addExportName(name, name); addExportName(name, name);
beforeBody.push(node); beforeBody.push(node);
beforeBody.push(buildExportCall(name, node.id)); beforeBody.push(
buildExportCall(name, t.cloneNode(node.id)),
);
removedPaths.push(path); removedPaths.push(path);
} else { } else {
bindingIdentifiers = { [name]: node.id }; bindingIdentifiers = { [name]: node.id };
@ -250,13 +268,17 @@ export default function(api, options) {
modules.forEach(function(specifiers) { modules.forEach(function(specifiers) {
const setterBody = []; const setterBody = [];
const target = path.scope.generateUidIdentifier(specifiers.key); const target = path.scope.generateUid(specifiers.key);
for (let specifier of specifiers.imports) { for (let specifier of specifiers.imports) {
if (t.isImportNamespaceSpecifier(specifier)) { if (t.isImportNamespaceSpecifier(specifier)) {
setterBody.push( setterBody.push(
t.expressionStatement( t.expressionStatement(
t.assignmentExpression("=", specifier.local, target), t.assignmentExpression(
"=",
specifier.local,
t.identifier(target),
),
), ),
); );
} else if (t.isImportDefaultSpecifier(specifier)) { } else if (t.isImportDefaultSpecifier(specifier)) {
@ -272,7 +294,10 @@ export default function(api, options) {
t.assignmentExpression( t.assignmentExpression(
"=", "=",
specifier.local, specifier.local,
t.memberExpression(target, specifier.imported), t.memberExpression(
t.identifier(target),
specifier.imported,
),
), ),
), ),
); );
@ -280,13 +305,14 @@ export default function(api, options) {
} }
if (specifiers.exports.length) { if (specifiers.exports.length) {
const exportObjRef = path.scope.generateUidIdentifier( const exportObj = path.scope.generateUid("exportObj");
"exportObj",
);
setterBody.push( setterBody.push(
t.variableDeclaration("var", [ t.variableDeclaration("var", [
t.variableDeclarator(exportObjRef, t.objectExpression([])), t.variableDeclarator(
t.identifier(exportObj),
t.objectExpression([]),
),
]), ]),
); );
@ -295,8 +321,8 @@ export default function(api, options) {
setterBody.push( setterBody.push(
buildExportAll({ buildExportAll({
KEY: path.scope.generateUidIdentifier("key"), KEY: path.scope.generateUidIdentifier("key"),
EXPORT_OBJ: exportObjRef, EXPORT_OBJ: t.identifier(exportObj),
TARGET: target, TARGET: t.identifier(target),
}), }),
); );
} else if (t.isExportSpecifier(node)) { } else if (t.isExportSpecifier(node)) {
@ -304,8 +330,11 @@ export default function(api, options) {
t.expressionStatement( t.expressionStatement(
t.assignmentExpression( t.assignmentExpression(
"=", "=",
t.memberExpression(exportObjRef, node.exported), t.memberExpression(
t.memberExpression(target, node.local), t.identifier(exportObj),
node.exported,
),
t.memberExpression(t.identifier(target), node.local),
), ),
), ),
); );
@ -316,7 +345,9 @@ export default function(api, options) {
setterBody.push( setterBody.push(
t.expressionStatement( t.expressionStatement(
t.callExpression(exportIdent, [exportObjRef]), t.callExpression(t.identifier(exportIdent), [
t.identifier(exportObj),
]),
), ),
); );
} }
@ -325,7 +356,7 @@ export default function(api, options) {
setters.push( setters.push(
t.functionExpression( t.functionExpression(
null, null,
[target], [t.identifier(target)],
t.blockStatement(setterBody), t.blockStatement(setterBody),
), ),
); );
@ -368,8 +399,8 @@ export default function(api, options) {
SETTERS: t.arrayExpression(setters), SETTERS: t.arrayExpression(setters),
SOURCES: t.arrayExpression(sources), SOURCES: t.arrayExpression(sources),
BODY: path.node.body, BODY: path.node.body,
EXPORT_IDENTIFIER: exportIdent, EXPORT_IDENTIFIER: t.identifier(exportIdent),
CONTEXT_IDENTIFIER: contextIdent, CONTEXT_IDENTIFIER: t.identifier(contextIdent),
}), }),
]; ];
}, },

View File

@ -68,7 +68,9 @@ export default function(api, options) {
const members = globalName.split("."); const members = globalName.split(".");
globalToAssign = members.slice(1).reduce((accum, curr) => { globalToAssign = members.slice(1).reduce((accum, curr) => {
initAssignments.push( initAssignments.push(
buildPrerequisiteAssignment({ GLOBAL_REFERENCE: accum }), buildPrerequisiteAssignment({
GLOBAL_REFERENCE: t.cloneNode(accum),
}),
); );
return t.memberExpression(accum, t.identifier(curr)); return t.memberExpression(accum, t.identifier(curr));
}, t.memberExpression(t.identifier("global"), t.identifier(members[0]))); }, t.memberExpression(t.identifier("global"), t.identifier(members[0])));

View File

@ -289,8 +289,7 @@ export default function convertFunctionRest(path) {
const key = scope.generateUidIdentifier("key"); const key = scope.generateUidIdentifier("key");
const len = scope.generateUidIdentifier("len"); const len = scope.generateUidIdentifier("len");
let arrKey = key; let arrKey, arrLen;
let arrLen = len;
if (node.params.length) { if (node.params.length) {
// this method has additional params, so we need to subtract // this method has additional params, so we need to subtract
// the index of the current argument position from the // the index of the current argument position from the
@ -308,6 +307,9 @@ export default function convertFunctionRest(path) {
t.binaryExpression("-", t.cloneNode(len), t.cloneNode(start)), t.binaryExpression("-", t.cloneNode(len), t.cloneNode(start)),
t.numericLiteral(0), t.numericLiteral(0),
); );
} else {
arrKey = t.identifier(key.name);
arrLen = t.identifier(len.name);
} }
const loop = buildRest({ const loop = buildRest({

View File

@ -1,4 +1,5 @@
import assert from "assert"; import assert from "assert";
import { template } from "@babel/core";
export default function transpileEnum(path, t) { export default function transpileEnum(path, t) {
const { node } = path; const { node } = path;
@ -50,37 +51,41 @@ function makeVar(id, t, kind): VariableDeclaration {
return t.variableDeclaration(kind, [t.variableDeclarator(id)]); return t.variableDeclaration(kind, [t.variableDeclarator(id)]);
} }
const buildEnumWrapper = template(`
(function (ID) {
ASSIGNMENTS;
})(ID || (ID = {}));
`);
const buildStringAssignment = template(`
ENUM["NAME"] = VALUE;
`);
const buildNumericAssignment = template(`
ENUM[ENUM["NAME"] = VALUE] = "NAME";
`);
const buildEnumMember = (isString, options) =>
(isString ? buildStringAssignment : buildNumericAssignment)(options);
/** /**
* Generates the statement that fills in the variable declared by the enum. * Generates the statement that fills in the variable declared by the enum.
* `(function (E) { ... assignments ... })(E || (E = {}));` * `(function (E) { ... assignments ... })(E || (E = {}));`
*/ */
function enumFill(path, t, id) { function enumFill(path, t, id) {
const x = translateEnumValues(path, t); const x = translateEnumValues(path, t);
const assignments = x.map(([memberName, memberValue]) => { const assignments = x.map(([memberName, memberValue]) =>
const inner = t.assignmentExpression( buildEnumMember(t.isStringLiteral(memberValue), {
"=", ENUM: t.cloneNode(id),
t.memberExpression(id, t.stringLiteral(memberName), /*computed*/ true), NAME: memberName,
memberValue, VALUE: memberValue,
); }),
const outer = t.isStringLiteral(memberValue)
? inner
: t.assignmentExpression(
"=",
t.memberExpression(id, inner, /*computed*/ true),
t.stringLiteral(memberName),
);
return t.expressionStatement(outer);
});
// E || (E = {})
const callArg = t.logicalExpression(
"||",
id,
t.assignmentExpression("=", id, t.objectExpression([])),
); );
const body = t.blockStatement(assignments);
const callee = t.functionExpression(null, [id], body); return buildEnumWrapper({
return t.expressionStatement(t.callExpression(callee, [callArg])); ID: t.cloneNode(id),
ASSIGNMENTS: assignments,
});
} }
/** /**

View File

@ -114,9 +114,11 @@ export default function() {
); );
} }
const id = t.identifier(name); const assign = t.assignmentExpression(
const thisDotName = t.memberExpression(t.thisExpression(), id); "=",
const assign = t.assignmentExpression("=", thisDotName, id); t.memberExpression(t.thisExpression(), t.identifier(name)),
t.identifier(name),
);
return t.expressionStatement(assign); return t.expressionStatement(assign);
}); });

View File

@ -263,14 +263,7 @@ export default class Scope {
return `_${id}`; return `_${id}`;
} }
/** generateUidBasedOnNode(parent: Object, defaultName?: String) {
* Generate a unique identifier based on a node.
*/
generateUidIdentifierBasedOnNode(
parent: Object,
defaultName?: String,
): Object {
let node = parent; let node = parent;
if (t.isAssignmentExpression(parent)) { if (t.isAssignmentExpression(parent)) {
@ -287,7 +280,18 @@ export default class Scope {
let id = parts.join("$"); let id = parts.join("$");
id = id.replace(/^_/, "") || defaultName || "ref"; id = id.replace(/^_/, "") || defaultName || "ref";
return this.generateUidIdentifier(id.slice(0, 20)); return this.generateUid(id.slice(0, 20));
}
/**
* Generate a unique identifier based on a node.
*/
generateUidIdentifierBasedOnNode(
parent: Object,
defaultName?: String,
): Object {
return t.identifier(this.generateUidBasedOnNode(parent, defaultName));
} }
/** /**