Skip to content

Commit

Permalink
splats in function declaration
Browse files Browse the repository at this point in the history
  • Loading branch information
alongubkin committed Nov 14, 2014
1 parent fb1df5b commit c724daa
Show file tree
Hide file tree
Showing 6 changed files with 730 additions and 490 deletions.
202 changes: 201 additions & 1 deletion lib/ast/Parameter.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
var Node = require('./Node').Node;

exports.Parameter = function (id, defaultValue) {
exports.Parameter = function (id, defaultValue, splat) {
Node.call(this);

this.type = 'Parameter';
this.splat = splat;

this.id = id;
this.id.parent = this;
Expand Down Expand Up @@ -60,4 +61,203 @@ exports.Parameter.prototype.codegen = function () {

exports.Parameter.prototype.hasCallExpression = function () {
return false;
};

exports.Parameter.generateFunctionBody = function (fn, params, body) {
var addToBody = [];
var splatPosition = -1;

params.forEach(function (param, i) {
var paramBodyCode = param.codegen();

if (param.splat) {
if (splatPosition !== -1) {
Node.getErrorManager().error({
type: "MultipleSplatsDisallowed",
message: "multiple splats are disallowed in a function declaration",
loc: param.loc
});
}

splatPosition = i;
}

params[i] = param.id;
fn.defineIdentifier(param.id);

if (paramBodyCode != null) {
addToBody.push(paramBodyCode);
}
});

body.body = addToBody.concat(body.body);

if (splatPosition !== -1) {
var declarations = [{
"type": "VariableDeclarator",
"id": {
"type": "Identifier",
"name": "__splat"
},
"init": null
}];

params.forEach(function (param, i) {
var init;
if (i < splatPosition) {
init = {
"type": "MemberExpression",
"computed": true,
"object": {
"type": "Identifier",
"name": "arguments"
},
"property": {
"type": "Literal",
"value": i
}
};
} else if (i === splatPosition) {
init = {
"type": "ConditionalExpression",
"test": {
"type": "BinaryExpression",
"operator": "<=",
"left": {
"type": "Literal",
"value": params.length
},
"right": {
"type": "MemberExpression",
"computed": false,
"object": {
"type": "Identifier",
"name": "arguments"
},
"property": {
"type": "Identifier",
"name": "length"
}
}
},
"consequent": {
"type": "CallExpression",
"callee": {
"type": "MemberExpression",
"computed": false,
"object": {
"type": "MemberExpression",
"computed": false,
"object": {
"type": "ArrayExpression",
"elements": []
},
"property": {
"type": "Identifier",
"name": "slice"
}
},
"property": {
"type": "Identifier",
"name": "call"
}
},
"arguments": [{
"type": "Identifier",
"name": "arguments"
}, {
"type": "Literal",
"value": splatPosition
}]
},
"alternate": {
"type": "ArrayExpression",
"elements": []
}
};

if (splatPosition < params.length - 1) {
init.consequent.arguments.push({
"type": "AssignmentExpression",
"operator": "=",
"left": {
"type": "Identifier",
"name": "__splat"
},
"right": {
"type": "BinaryExpression",
"operator": "-",
"left": {
"type": "MemberExpression",
"computed": false,
"object": {
"type": "Identifier",
"name": "arguments"
},
"property": {
"type": "Identifier",
"name": "length"
}
},
"right": {
"type": "Literal",
"value": params.length - splatPosition - 1
}
}
});

init.alternate = {
"type": "SequenceExpression",
"expressions": [{
"type": "AssignmentExpression",
"operator": "=",
"left": {
"type": "Identifier",
"name": "__splat"
},
"right": {
"type": "Literal",
"value": splatPosition
}
}, {
"type": "ArrayExpression",
"elements": []
}]
};
}
} else {
init = {
"type": "MemberExpression",
"computed": true,
"object": {
"type": "Identifier",
"name": "arguments"
},
"property": {
"type": "UpdateExpression",
"operator": "++",
"argument": {
"type": "Identifier",
"name": "__splat"
},
"prefix": false
}
};
}

declarations.push({
"type": "VariableDeclarator",
"id": param,
"init": init
});
});

body.body = [{
"type": "VariableDeclaration",
"declarations": declarations,
"kind": "var"
}].concat(body.body);

params.length = 0;
}
};
20 changes: 4 additions & 16 deletions lib/ast/expressions/FunctionExpression.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var Node = require('../Node').Node;
var Node = require('../Node').Node,
Parameter = require('../Parameter').Parameter;

exports.FunctionExpression = function (id, params, body, inheritsFrom) {
var self = this;
Expand Down Expand Up @@ -65,26 +66,13 @@ exports.FunctionExpression.prototype.codegen = function () {
self.id = self.id.codegen(false);
}

var addToBody = [];

self.params.forEach(function (param, i) {
var paramBodyCode = param.codegen();

self.params[i] = param.id;
self.defineIdentifier(param.id);

if (paramBodyCode != null) {
addToBody.push(paramBodyCode);
}
});

if (self.autoBlock) {
self.body.body[0].argument = self.body.body[0].argument.codegen();
} else {
self.body = self.body.codegen();
}
self.body.body = addToBody.concat(self.body.body);

Parameter.generateFunctionBody(self, self.params, self.body);

if (self.inheritsFrom) {
var context = self.getContext();
Expand Down
20 changes: 4 additions & 16 deletions lib/ast/statements/FunctionDeclarationStatement.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
var Node = require('../Node').Node;
var Node = require('../Node').Node,
Parameter = require('../Parameter').Parameter;

exports.FunctionDeclarationStatement = function (id, params, body, inheritsFrom) {
var self = this;
Expand Down Expand Up @@ -39,22 +40,9 @@ exports.FunctionDeclarationStatement.prototype.codegen = function () {
}

self.id = self.id.codegen();

var addToBody = [];

self.params.forEach(function (param, i) {
var paramBodyCode = param.codegen();

self.params[i] = param.id;
self.defineIdentifier(param.id);

if (paramBodyCode != null) {
addToBody.push(paramBodyCode);
}
});

self.body = self.body.codegen();
self.body.body = addToBody.concat(self.body.body);

Parameter.generateFunctionBody(self, self.params, self.body);

if (self.inheritsFrom) {
self.inheritsFrom = self.inheritsFrom.codegen();
Expand Down
Loading

0 comments on commit c724daa

Please sign in to comment.