Merge pull request #1518 from babel/es7.functionBind
Add experimental support for ES7 function bind.
This commit is contained in:
@@ -214,7 +214,12 @@ pp.parseExprSubscripts = function(refShorthandDefaultPos) {
|
||||
}
|
||||
|
||||
pp.parseSubscripts = function(base, start, noCalls) {
|
||||
if (this.eat(tt.dot)) {
|
||||
if (!noCalls && 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"]
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
41
src/babel/transformation/transformers/es7/function-bind.js
Normal file
41
src/babel/transformation/transformers/es7/function-bind.js
Normal file
@@ -0,0 +1,41 @@
|
||||
// https://github.com/zenparsing/es-function-bind
|
||||
|
||||
import * as t from "../../../types";
|
||||
|
||||
export var metadata = {
|
||||
optional: true,
|
||||
stage: 0
|
||||
};
|
||||
|
||||
function getTempId(scope) {
|
||||
var id = scope.path.getData("functionBind");
|
||||
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 = t.sequenceExpression([
|
||||
t.assignmentExpression("=", tempId, bind.object),
|
||||
bind.callee
|
||||
]);
|
||||
} else {
|
||||
bind.callee.object = t.assignmentExpression("=", tempId, bind.callee.object);
|
||||
}
|
||||
return tempId;
|
||||
}
|
||||
|
||||
export function CallExpression(node, parent, scope, file) {
|
||||
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 context = inferBindContext(node, scope);
|
||||
return t.callExpression(t.memberExpression(node.callee, t.identifier("bind")), [context]);
|
||||
}
|
||||
@@ -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"),
|
||||
|
||||
@@ -20,6 +20,11 @@
|
||||
"right": null
|
||||
},
|
||||
|
||||
"BindExpression": {
|
||||
"object": null,
|
||||
"callee": null
|
||||
},
|
||||
|
||||
"BlockStatement": {
|
||||
"body": null
|
||||
},
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"AssignmentPattern": ["left", "right"],
|
||||
"AwaitExpression": ["argument"],
|
||||
"BinaryExpression": ["left", "right"],
|
||||
"BindExpression": ["object", "callee"],
|
||||
"BlockStatement": ["body"],
|
||||
"BreakStatement": ["label"],
|
||||
"CallExpression": ["callee", "arguments"],
|
||||
|
||||
Reference in New Issue
Block a user