From 37f662d790a3e8d872fc2f8e319a14651bfe5ae3 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Wed, 13 May 2015 17:58:21 +0300 Subject: [PATCH 1/5] Add experimental support for ES7 function bind. (issue #1287) --- src/acorn/src/expression.js | 26 +++++++++++-- src/acorn/src/tokenize.js | 8 +++- src/acorn/src/tokentype.js | 1 + .../generation/generators/expressions.js | 6 +++ src/babel/patch.js | 6 +++ .../transformers/es7/function-bind.js | 37 +++++++++++++++++++ .../transformation/transformers/index.js | 1 + src/babel/types/builder-keys.json | 5 +++ src/babel/types/visitor-keys.json | 1 + .../es7.function-bind/bind/actual.js | 2 + .../es7.function-bind/bind/expected.js | 6 +++ .../es7.function-bind/call/actual.js | 4 ++ .../es7.function-bind/call/expected.js | 8 ++++ .../es7.function-bind/complex-call/actual.js | 6 +++ .../complex-call/expected.js | 11 ++++++ .../es7.function-bind/options.json | 3 ++ 16 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 src/babel/transformation/transformers/es7/function-bind.js create mode 100644 test/core/fixtures/transformation/es7.function-bind/bind/actual.js create mode 100644 test/core/fixtures/transformation/es7.function-bind/bind/expected.js create mode 100644 test/core/fixtures/transformation/es7.function-bind/call/actual.js create mode 100644 test/core/fixtures/transformation/es7.function-bind/call/expected.js create mode 100644 test/core/fixtures/transformation/es7.function-bind/complex-call/actual.js create mode 100644 test/core/fixtures/transformation/es7.function-bind/complex-call/expected.js create mode 100644 test/core/fixtures/transformation/es7.function-bind/options.json diff --git a/src/acorn/src/expression.js b/src/acorn/src/expression.js index b820a6bf64..086a01c58a 100755 --- a/src/acorn/src/expression.js +++ b/src/acorn/src/expression.js @@ -214,7 +214,12 @@ pp.parseExprSubscripts = function(refShorthandDefaultPos) { } pp.parseSubscripts = function(base, start, noCalls) { - if (this.eat(tt.dot)) { + if (this.eat(tt.doubleColon)) { + let node = this.startNodeAt(start) + node.object = base + node.callee = this.parseNoCallExpr() + return this.parseSubscripts(this.finishNode(node, "BindExpression"), start, noCalls) + } else if (this.eat(tt.dot)) { let node = this.startNodeAt(start) node.object = base node.property = this.parseIdent(true) @@ -240,6 +245,13 @@ pp.parseSubscripts = function(base, start, noCalls) { } return base } +// Parse a no-call expression (like argument of `new` or `::` operators). + +pp.parseNoCallExpr = function() { + let start = this.markPosition() + return this.parseSubscripts(this.parseExprAtom(), start, true) +} + // Parse an atomic expression — either a single token that is an // expression, an expression started by a keyword like `function` or // `new`, or an expression wrapped in punctuation like `()`, `[]`, @@ -363,6 +375,15 @@ pp.parseExprAtom = function(refShorthandDefaultPos) { case tt.backQuote: return this.parseTemplate() + case tt.doubleColon: + node = this.startNode() + this.next() + node.object = null + let callee = node.callee = this.parseNoCallExpr() + if (callee.type !== "MemberExpression") + this.raise(callee.start, "Binding should be performed on object property.") + return this.finishNode(node, "BindExpression") + default: this.unexpected() } @@ -472,8 +493,7 @@ pp.parseNew = function() { this.raise(node.property.start, "The only valid meta property for new is new.target") return this.finishNode(node, "MetaProperty") } - let start = this.markPosition() - node.callee = this.parseSubscripts(this.parseExprAtom(), start, true) + node.callee = this.parseNoCallExpr() if (this.eat(tt.parenL)) node.arguments = this.parseExprList( tt.parenR, this.options.features["es7.trailingFunctionCommas"] diff --git a/src/acorn/src/tokenize.js b/src/acorn/src/tokenize.js index e99fc74080..fc9d706bb8 100755 --- a/src/acorn/src/tokenize.js +++ b/src/acorn/src/tokenize.js @@ -320,7 +320,13 @@ pp.getTokenFromCode = function(code) { case 93: ++this.pos; return this.finishToken(tt.bracketR) case 123: ++this.pos; return this.finishToken(tt.braceL) case 125: ++this.pos; return this.finishToken(tt.braceR) - case 58: ++this.pos; return this.finishToken(tt.colon) + + case 58: + if (this.options.features["es7.functionBind"] && this.input.charCodeAt(this.pos + 1) === 58) + return this.finishOp(tt.doubleColon, 2) + ++this.pos + return this.finishToken(tt.colon) + case 63: ++this.pos; return this.finishToken(tt.question) case 64: ++this.pos; return this.finishToken(tt.at) diff --git a/src/acorn/src/tokentype.js b/src/acorn/src/tokentype.js index 609e508583..05d1d53186 100755 --- a/src/acorn/src/tokentype.js +++ b/src/acorn/src/tokentype.js @@ -54,6 +54,7 @@ export const types = { comma: new TokenType(",", beforeExpr), semi: new TokenType(";", beforeExpr), colon: new TokenType(":", beforeExpr), + doubleColon: new TokenType("::", beforeExpr), dot: new TokenType("."), question: new TokenType("?", beforeExpr), arrow: new TokenType("=>", beforeExpr), diff --git a/src/babel/generation/generators/expressions.js b/src/babel/generation/generators/expressions.js index afa481d11d..e08aeb168e 100644 --- a/src/babel/generation/generators/expressions.js +++ b/src/babel/generation/generators/expressions.js @@ -133,6 +133,12 @@ export function AssignmentExpression(node, print) { print(node.right); } +export function BindExpression(node, print) { + print(node.object); + this.push("::"); + print(node.callee); +} + export { AssignmentExpression as BinaryExpression, AssignmentExpression as LogicalExpression, diff --git a/src/babel/patch.js b/src/babel/patch.js index f8f5dcf95e..4d329a6b3c 100644 --- a/src/babel/patch.js +++ b/src/babel/patch.js @@ -72,4 +72,10 @@ def("ExportAllDeclaration") .field("exported", def("Identifier")) .field("source", def("Literal")); +def("BindExpression") + .bases("Expression") + .build("object", "callee") + .field("object", or(def("Expression"), null)) + .field("callee", def("Expression")); + types.finalize(); diff --git a/src/babel/transformation/transformers/es7/function-bind.js b/src/babel/transformation/transformers/es7/function-bind.js new file mode 100644 index 0000000000..dc3af46ecd --- /dev/null +++ b/src/babel/transformation/transformers/es7/function-bind.js @@ -0,0 +1,37 @@ +// https://github.com/zenparsing/es-function-bind + +import * as t from "../../../types"; + +export var metadata = { + optional: true, + stage: 0 +}; + +var CALL = t.identifier("call"); +var BIND = t.identifier("bind"); + +function inferBindContext(bindExpr, scope) { + // nothing to infer + if (bindExpr.object) return bindExpr.object; + + var id = scope.path.getData("functionBind"); + if (!id) { + id = scope.generateTemp("context"); + scope.path.setData("functionBind", id); + } + bindExpr.callee.object = t.assignmentExpression("=", id, bindExpr.callee.object); + return id; +} + +export function CallExpression(node, parent, scope, file) { + var bindExpr = node.callee; + if (!t.isBindExpression(bindExpr)) return; + var bindCtx = inferBindContext(bindExpr, scope); + node.callee = t.memberExpression(bindExpr.callee, CALL, false); + node.arguments.unshift(bindCtx); +} + +export function BindExpression(node, parent, scope, file) { + var bindCtx = inferBindContext(node, scope); + return t.callExpression(t.memberExpression(node.callee, BIND, false), [bindCtx]); +} diff --git a/src/babel/transformation/transformers/index.js b/src/babel/transformation/transformers/index.js index e6231da863..b44ba74e3a 100644 --- a/src/babel/transformation/transformers/index.js +++ b/src/babel/transformation/transformers/index.js @@ -51,6 +51,7 @@ export default { "spec.protoToAssign": require("./spec/proto-to-assign"), "es7.doExpressions": require("./es7/do-expressions"), "es6.spec.symbols": require("./es6/spec.symbols"), + "es7.functionBind": require("./es7/function-bind"), "spec.undefinedToVoid": require("./spec/undefined-to-void"), jscript: require("./other/jscript"), flow: require("./other/flow"), diff --git a/src/babel/types/builder-keys.json b/src/babel/types/builder-keys.json index bae45903a7..8213e78235 100644 --- a/src/babel/types/builder-keys.json +++ b/src/babel/types/builder-keys.json @@ -20,6 +20,11 @@ "right": null }, + "BindExpression": { + "object": null, + "callee": null + }, + "BlockStatement": { "body": null }, diff --git a/src/babel/types/visitor-keys.json b/src/babel/types/visitor-keys.json index c0d52cab62..0dc2d97b6e 100644 --- a/src/babel/types/visitor-keys.json +++ b/src/babel/types/visitor-keys.json @@ -6,6 +6,7 @@ "AssignmentPattern": ["left", "right"], "AwaitExpression": ["argument"], "BinaryExpression": ["left", "right"], + "BindExpression": ["object", "callee"], "BlockStatement": ["body"], "BreakStatement": ["label"], "CallExpression": ["callee", "arguments"], diff --git a/test/core/fixtures/transformation/es7.function-bind/bind/actual.js b/test/core/fixtures/transformation/es7.function-bind/bind/actual.js new file mode 100644 index 0000000000..95e7aa13cd --- /dev/null +++ b/test/core/fixtures/transformation/es7.function-bind/bind/actual.js @@ -0,0 +1,2 @@ +var f = ctx::ns.obj.func; +var g = ::ns.obj.func; diff --git a/test/core/fixtures/transformation/es7.function-bind/bind/expected.js b/test/core/fixtures/transformation/es7.function-bind/bind/expected.js new file mode 100644 index 0000000000..41321e2ecb --- /dev/null +++ b/test/core/fixtures/transformation/es7.function-bind/bind/expected.js @@ -0,0 +1,6 @@ +"use strict"; + +var _context; + +var f = ns.obj.func.bind(ctx); +var g = (_context = ns.obj).func.bind(_context); \ No newline at end of file diff --git a/test/core/fixtures/transformation/es7.function-bind/call/actual.js b/test/core/fixtures/transformation/es7.function-bind/call/actual.js new file mode 100644 index 0000000000..c2c18d6370 --- /dev/null +++ b/test/core/fixtures/transformation/es7.function-bind/call/actual.js @@ -0,0 +1,4 @@ +ctx::ns.obj.func(); +::ns.obj.func(); + +ns.obj2::ns.obj1.func(); diff --git a/test/core/fixtures/transformation/es7.function-bind/call/expected.js b/test/core/fixtures/transformation/es7.function-bind/call/expected.js new file mode 100644 index 0000000000..75cc530bff --- /dev/null +++ b/test/core/fixtures/transformation/es7.function-bind/call/expected.js @@ -0,0 +1,8 @@ +"use strict"; + +var _context; + +ns.obj.func.call(ctx); +(_context = ns.obj).func.call(_context); + +ns.obj1.func.call(ns.obj2); \ No newline at end of file diff --git a/test/core/fixtures/transformation/es7.function-bind/complex-call/actual.js b/test/core/fixtures/transformation/es7.function-bind/complex-call/actual.js new file mode 100644 index 0000000000..b681cb546b --- /dev/null +++ b/test/core/fixtures/transformation/es7.function-bind/complex-call/actual.js @@ -0,0 +1,6 @@ +import { map, takeWhile, forEach } from "iterlib"; + +getPlayers() +::map(x => x.character()) +::takeWhile(x => x.strength > 100) +::forEach(x => console.log(x)); diff --git a/test/core/fixtures/transformation/es7.function-bind/complex-call/expected.js b/test/core/fixtures/transformation/es7.function-bind/complex-call/expected.js new file mode 100644 index 0000000000..e1482fbd94 --- /dev/null +++ b/test/core/fixtures/transformation/es7.function-bind/complex-call/expected.js @@ -0,0 +1,11 @@ +"use strict"; + +var _iterlib = require("iterlib"); + +_iterlib.forEach.call(_iterlib.takeWhile.call(_iterlib.map.call(getPlayers(), function (x) { + return x.character(); +}), function (x) { + return x.strength > 100; +}), function (x) { + return console.log(x); +}); \ No newline at end of file diff --git a/test/core/fixtures/transformation/es7.function-bind/options.json b/test/core/fixtures/transformation/es7.function-bind/options.json new file mode 100644 index 0000000000..bdc665fe51 --- /dev/null +++ b/test/core/fixtures/transformation/es7.function-bind/options.json @@ -0,0 +1,3 @@ +{ + "optional": "es7.functionBind" +} From 1a299b2bccaa5e4ff96c7fc22af8898bc17b9a06 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Wed, 13 May 2015 18:20:33 +0300 Subject: [PATCH 2/5] Small fixes to es7.functionBind and generation tests added. --- src/babel/transformation/transformers/es7/function-bind.js | 7 ++----- .../fixtures/generation/types/BindExpression/actual.js | 5 +++++ .../fixtures/generation/types/BindExpression/expected.js | 5 +++++ test/core/generation.js | 3 ++- 4 files changed, 14 insertions(+), 6 deletions(-) create mode 100644 test/core/fixtures/generation/types/BindExpression/actual.js create mode 100644 test/core/fixtures/generation/types/BindExpression/expected.js diff --git a/src/babel/transformation/transformers/es7/function-bind.js b/src/babel/transformation/transformers/es7/function-bind.js index dc3af46ecd..2846999aa7 100644 --- a/src/babel/transformation/transformers/es7/function-bind.js +++ b/src/babel/transformation/transformers/es7/function-bind.js @@ -7,9 +7,6 @@ export var metadata = { stage: 0 }; -var CALL = t.identifier("call"); -var BIND = t.identifier("bind"); - function inferBindContext(bindExpr, scope) { // nothing to infer if (bindExpr.object) return bindExpr.object; @@ -27,11 +24,11 @@ export function CallExpression(node, parent, scope, file) { var bindExpr = node.callee; if (!t.isBindExpression(bindExpr)) return; var bindCtx = inferBindContext(bindExpr, scope); - node.callee = t.memberExpression(bindExpr.callee, CALL, false); + node.callee = t.memberExpression(bindExpr.callee, t.identifier("call")); node.arguments.unshift(bindCtx); } export function BindExpression(node, parent, scope, file) { var bindCtx = inferBindContext(node, scope); - return t.callExpression(t.memberExpression(node.callee, BIND, false), [bindCtx]); + return t.callExpression(t.memberExpression(node.callee, t.identifier("bind")), [bindCtx]); } diff --git a/test/core/fixtures/generation/types/BindExpression/actual.js b/test/core/fixtures/generation/types/BindExpression/actual.js new file mode 100644 index 0000000000..c78d72da44 --- /dev/null +++ b/test/core/fixtures/generation/types/BindExpression/actual.js @@ -0,0 +1,5 @@ +::foo.bar.foo; +::foo.bar["foo"]; + +ctx::foo.bar.foo; +ctx::foo.bar["foo"]; diff --git a/test/core/fixtures/generation/types/BindExpression/expected.js b/test/core/fixtures/generation/types/BindExpression/expected.js new file mode 100644 index 0000000000..c78d72da44 --- /dev/null +++ b/test/core/fixtures/generation/types/BindExpression/expected.js @@ -0,0 +1,5 @@ +::foo.bar.foo; +::foo.bar["foo"]; + +ctx::foo.bar.foo; +ctx::foo.bar["foo"]; diff --git a/test/core/generation.js b/test/core/generation.js index fa4dd81017..b1f08a2908 100644 --- a/test/core/generation.js +++ b/test/core/generation.js @@ -34,7 +34,8 @@ _.each(helper.get("generation"), function (testSuite) { features: { "es7.comprehensions": true, "es7.asyncFunctions": true, - "es7.exportExtensions": true + "es7.exportExtensions": true, + "es7.functionBind": true } }); var actualCode = generate(actualAst, task.options, actual.code).code; From fd8e94a90f59312dcbe19a9d13dfe0f5a5813783 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Thu, 14 May 2015 12:39:05 +0300 Subject: [PATCH 3/5] Preserve original execution order in :: operator. --- .../transformers/es7/function-bind.js | 39 +++++++++++-------- .../es7.function-bind/bind/expected.js | 4 +- .../es7.function-bind/call/expected.js | 4 +- .../es7.function-bind/complex-call/exec.js | 27 +++++++++++++ .../complex-call/expected.js | 10 +++-- 5 files changed, 60 insertions(+), 24 deletions(-) create mode 100644 test/core/fixtures/transformation/es7.function-bind/complex-call/exec.js diff --git a/src/babel/transformation/transformers/es7/function-bind.js b/src/babel/transformation/transformers/es7/function-bind.js index 2846999aa7..d8cbd0c6ed 100644 --- a/src/babel/transformation/transformers/es7/function-bind.js +++ b/src/babel/transformation/transformers/es7/function-bind.js @@ -7,28 +7,35 @@ export var metadata = { stage: 0 }; -function inferBindContext(bindExpr, scope) { - // nothing to infer - if (bindExpr.object) return bindExpr.object; - +function getTempId(scope) { var id = scope.path.getData("functionBind"); - if (!id) { - id = scope.generateTemp("context"); - scope.path.setData("functionBind", id); + if (id) return id; + id = scope.generateTemp("context"); + return scope.path.setData("functionBind", id); +} + +function inferBindContext(bind, scope) { + var tempId = getTempId(scope); + if (!bind.object) { + bind.callee.object = t.assignmentExpression("=", tempId, bind.callee.object); + } else { + bind.callee = t.sequenceExpression([ + t.assignmentExpression("=", tempId, bind.object), + bind.callee + ]); } - bindExpr.callee.object = t.assignmentExpression("=", id, bindExpr.callee.object); - return id; + return tempId; } export function CallExpression(node, parent, scope, file) { - var bindExpr = node.callee; - if (!t.isBindExpression(bindExpr)) return; - var bindCtx = inferBindContext(bindExpr, scope); - node.callee = t.memberExpression(bindExpr.callee, t.identifier("call")); - node.arguments.unshift(bindCtx); + var bind = node.callee; + if (!t.isBindExpression(bind)) return; + var context = inferBindContext(bind, scope); + node.callee = t.memberExpression(bind.callee, t.identifier("call")); + node.arguments.unshift(context); } export function BindExpression(node, parent, scope, file) { - var bindCtx = inferBindContext(node, scope); - return t.callExpression(t.memberExpression(node.callee, t.identifier("bind")), [bindCtx]); + var context = inferBindContext(node, scope); + return t.callExpression(t.memberExpression(node.callee, t.identifier("bind")), [context]); } diff --git a/test/core/fixtures/transformation/es7.function-bind/bind/expected.js b/test/core/fixtures/transformation/es7.function-bind/bind/expected.js index 41321e2ecb..7c47a86b25 100644 --- a/test/core/fixtures/transformation/es7.function-bind/bind/expected.js +++ b/test/core/fixtures/transformation/es7.function-bind/bind/expected.js @@ -2,5 +2,5 @@ var _context; -var f = ns.obj.func.bind(ctx); -var g = (_context = ns.obj).func.bind(_context); \ No newline at end of file +var f = (_context = ctx, ns.obj.func).bind(_context); +var g = (_context = ns.obj).func.bind(_context); diff --git a/test/core/fixtures/transformation/es7.function-bind/call/expected.js b/test/core/fixtures/transformation/es7.function-bind/call/expected.js index 75cc530bff..b48a0bdb3e 100644 --- a/test/core/fixtures/transformation/es7.function-bind/call/expected.js +++ b/test/core/fixtures/transformation/es7.function-bind/call/expected.js @@ -2,7 +2,7 @@ var _context; -ns.obj.func.call(ctx); +(_context = ctx, ns.obj.func).call(_context); (_context = ns.obj).func.call(_context); -ns.obj1.func.call(ns.obj2); \ No newline at end of file +(_context = ns.obj2, ns.obj1.func).call(_context); diff --git a/test/core/fixtures/transformation/es7.function-bind/complex-call/exec.js b/test/core/fixtures/transformation/es7.function-bind/complex-call/exec.js new file mode 100644 index 0000000000..5ee5f3f7d7 --- /dev/null +++ b/test/core/fixtures/transformation/es7.function-bind/complex-call/exec.js @@ -0,0 +1,27 @@ +var operations = []; + +var lib = {}; + +for (let key of ['f', 'g', 'h']) { + let func = () => operations.push(`lib.${key}()`); + Object.defineProperty(lib, key, { + get() { + operations.push(`get lib.${key}`); + return func; + } + }); +} + +({prop:'value'}) +::lib.f() +::lib.g() +::lib.h(); + +assert.deepEqual(operations, [ + 'get lib.f', + 'lib.f()', + 'get lib.g', + 'lib.g()', + 'get lib.h', + 'lib.h()' +]); diff --git a/test/core/fixtures/transformation/es7.function-bind/complex-call/expected.js b/test/core/fixtures/transformation/es7.function-bind/complex-call/expected.js index e1482fbd94..b15ae7d381 100644 --- a/test/core/fixtures/transformation/es7.function-bind/complex-call/expected.js +++ b/test/core/fixtures/transformation/es7.function-bind/complex-call/expected.js @@ -1,11 +1,13 @@ "use strict"; +var _context; + var _iterlib = require("iterlib"); -_iterlib.forEach.call(_iterlib.takeWhile.call(_iterlib.map.call(getPlayers(), function (x) { +(_context = (_context = (_context = getPlayers(), _iterlib.map).call(_context, function (x) { return x.character(); -}), function (x) { +}), _iterlib.takeWhile).call(_context, function (x) { return x.strength > 100; -}), function (x) { +}), _iterlib.forEach).call(_context, function (x) { return console.log(x); -}); \ No newline at end of file +}); From e05d7cf49a43b314fe0f13c166624c88e4c0eecf Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Thu, 14 May 2015 12:47:51 +0300 Subject: [PATCH 4/5] Fix some parsing edge cases for :: operator. --- src/acorn/src/expression.js | 2 +- .../fixtures/transformation/es7.function-bind/bind/actual.js | 1 + .../fixtures/transformation/es7.function-bind/bind/expected.js | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/acorn/src/expression.js b/src/acorn/src/expression.js index 086a01c58a..08c4b26084 100755 --- a/src/acorn/src/expression.js +++ b/src/acorn/src/expression.js @@ -214,7 +214,7 @@ pp.parseExprSubscripts = function(refShorthandDefaultPos) { } pp.parseSubscripts = function(base, start, noCalls) { - if (this.eat(tt.doubleColon)) { + if (!noCalls && this.eat(tt.doubleColon)) { let node = this.startNodeAt(start) node.object = base node.callee = this.parseNoCallExpr() diff --git a/test/core/fixtures/transformation/es7.function-bind/bind/actual.js b/test/core/fixtures/transformation/es7.function-bind/bind/actual.js index 95e7aa13cd..822d9a79e9 100644 --- a/test/core/fixtures/transformation/es7.function-bind/bind/actual.js +++ b/test/core/fixtures/transformation/es7.function-bind/bind/actual.js @@ -1,2 +1,3 @@ var f = ctx::ns.obj.func; var g = ::ns.obj.func; +var h = new X::y; diff --git a/test/core/fixtures/transformation/es7.function-bind/bind/expected.js b/test/core/fixtures/transformation/es7.function-bind/bind/expected.js index 7c47a86b25..22ae9099a5 100644 --- a/test/core/fixtures/transformation/es7.function-bind/bind/expected.js +++ b/test/core/fixtures/transformation/es7.function-bind/bind/expected.js @@ -4,3 +4,4 @@ var _context; var f = (_context = ctx, ns.obj.func).bind(_context); var g = (_context = ns.obj).func.bind(_context); +var h = (_context = new X(), y).bind(_context); From da765cc4c13cf188c97ab31610a43d764da36e04 Mon Sep 17 00:00:00 2001 From: Ingvar Stepanyan Date: Thu, 14 May 2015 18:05:55 +0300 Subject: [PATCH 5/5] Flip the negation in if-else. --- src/babel/transformation/transformers/es7/function-bind.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/babel/transformation/transformers/es7/function-bind.js b/src/babel/transformation/transformers/es7/function-bind.js index d8cbd0c6ed..08e53b6d5a 100644 --- a/src/babel/transformation/transformers/es7/function-bind.js +++ b/src/babel/transformation/transformers/es7/function-bind.js @@ -16,13 +16,13 @@ function getTempId(scope) { function inferBindContext(bind, scope) { var tempId = getTempId(scope); - if (!bind.object) { - bind.callee.object = t.assignmentExpression("=", tempId, bind.callee.object); - } else { + if (bind.object) { bind.callee = t.sequenceExpression([ t.assignmentExpression("=", tempId, bind.object), bind.callee ]); + } else { + bind.callee.object = t.assignmentExpression("=", tempId, bind.callee.object); } return tempId; }