Skip to content

Commit

Permalink
[[FIX]] Refactor doFunction
Browse files Browse the repository at this point in the history
The behavior of the `doFunction` routine is highly dynamic and dependent
on a number of optional arguments. None of these arguments is required,
and invocations of the function have become inconsistent in how these
are specified.

Re-factor `doFunction` to accept a single `options` argument. This
avoids the need to specify null values for irrelevant positional
arguments and makes the call site more legible to human readers.
Additionally, provide documentation for each of the options.
  • Loading branch information
jugglinmike committed Feb 22, 2015
1 parent 4e59553 commit 06b5d40
Showing 1 changed file with 48 additions and 29 deletions.
77 changes: 48 additions & 29 deletions src/jshint.js
Original file line number Diff line number Diff line change
Expand Up @@ -1172,7 +1172,7 @@ var JSHINT = (function() {
nobreaknonadjacent(state.tokens.prev, state.tokens.curr);

this.left = left;
this.right = doFunction(undefined, undefined, false, { loneArg: left });
this.right = doFunction({ type: "arrow", loneArg: left });
return this;
};
return x;
Expand Down Expand Up @@ -2467,7 +2467,7 @@ var JSHINT = (function() {
// current token marks the beginning of a "fat arrow" function and parsing
// should proceed accordingly.
if (pn.value === "=>") {
return doFunction(null, null, null, { parsedParen: true });
return doFunction({ type: "arrow", parsedOpening: true });
}

var exprs = [];
Expand Down Expand Up @@ -2730,14 +2730,22 @@ var JSHINT = (function() {
return id;
}

function functionparams(fatarrow) {
/**
* @param {Object} [options]
* @param {token} [options.loneArg] The argument to the function in cases
* where it was defined using the
* single-argument shorthand.
* @param {bool} [options.parsedOpening] Whether the opening parenthesis has
* already been parsed.
*/
function functionparams(options) {
var next;
var params = [];
var ident;
var tokens = [];
var t;
var pastDefault = false;
var loneArg = fatarrow && fatarrow.loneArg;
var loneArg = options && options.loneArg;

if (loneArg && loneArg.identifier === true) {
addlabel(loneArg.value, { type: "unused", token: loneArg });
Expand All @@ -2746,7 +2754,7 @@ var JSHINT = (function() {

next = state.tokens.next;

if (!fatarrow || !fatarrow.parsedParen) {
if (!options || !options.parsedOpening) {
advance("(");
}

Expand Down Expand Up @@ -2879,30 +2887,38 @@ var JSHINT = (function() {
}

/**
* @param {Object} [fatarrow] In the case that the function being parsed
* takes the "fat arrow" form, this object will
* contain details about the in-progress parsing
* operation.
* @param {Token} [fatarrow.loneArg] The argument to the function in cases
* where it was defined using the single-
* argument shorthand.
* @param {bool} [fatarrow.parsedParen] Whether the opening parenthesis has
* already been parsed.
* @param {Object} [options]
* @param {token} [options.name] The identifier belonging to the function (if
* any)
* @param {token} [options.statement] The statement to which the function
* belongs
* @param {string} [options.type] If specified, either "generator" or "arrow"
* @param {token} [options.loneArg] The argument to the function in cases
* where it was defined using the
* single-argument shorthand
* @param {bool} [options.parsedOpening] Whether the opening parenthesis has
* already been parsed
*/
function doFunction(name, statement, generator, fatarrow) {
var f;
function doFunction(options) {
var f, name, isGenerator, isArrow;
var oldOption = state.option;
var oldIgnored = state.ignored;
var oldScope = scope;

if (options) {
name = options.name;
isGenerator = options.type === "generator";
isArrow = options.type === "arrow";
}

state.option = Object.create(state.option);
state.ignored = Object.create(state.ignored);
scope = Object.create(scope);

funct = functor(name || state.nameStack.infer(), state.tokens.next, scope, {
"(statement)": statement,
"(statement)": options && options.statement,
"(context)": funct,
"(generator)": generator ? true : null
"(generator)": isGenerator
});

f = funct;
Expand All @@ -2914,22 +2930,22 @@ var JSHINT = (function() {
addlabel(name, { type: "function" });
}

funct["(params)"] = functionparams(fatarrow);
funct["(params)"] = functionparams(options);
funct["(metrics)"].verifyMaxParametersPerFunction(funct["(params)"]);

if (fatarrow) {
if (isArrow) {
if (!state.option.esnext) {
warning("W119", state.tokens.curr, "arrow function syntax (=>)");
}

if (!fatarrow.loneArg) {
if (!options.loneArg) {
advance("=>");
}
}

block(false, true, true, !!fatarrow);
block(false, true, true, isArrow);

if (!state.option.noyield && generator &&
if (!state.option.noyield && isGenerator &&
funct["(generator)"] !== "yielded") {
warning("W124", state.tokens.curr);
}
Expand Down Expand Up @@ -3093,7 +3109,6 @@ var JSHINT = (function() {
warning("W077", t, i);
}
} else {
g = false;
if (state.tokens.next.value === "*" && state.tokens.next.type === "(punctuator)") {
if (!state.option.inESNext()) {
warning("W104", state.tokens.next, "generator functions");
Expand Down Expand Up @@ -3128,7 +3143,7 @@ var JSHINT = (function() {
if (!state.option.inESNext()) {
warning("W104", state.tokens.curr, "concise methods");
}
doFunction(null, undefined, g);
doFunction({ type: g ? "generator" : null });
} else {
advance(":");
expression(10);
Expand Down Expand Up @@ -3555,7 +3570,7 @@ var JSHINT = (function() {
advance();
}
if (state.tokens.next.value !== "(") {
doFunction(undefined, c, false, null);
doFunction({ statement: c });
}
}

Expand Down Expand Up @@ -3583,7 +3598,7 @@ var JSHINT = (function() {

propertyName(name);

doFunction(null, c, isGenerator, null);
doFunction({ statement: c, type: isGenerator ? "generator" : null });
}

checkProperties(props);
Expand Down Expand Up @@ -3614,7 +3629,11 @@ var JSHINT = (function() {
}
addlabel(i, { type: "unction", token: state.tokens.curr });

doFunction(i, { statement: true }, generator);
doFunction({
name: i,
statement: { statement: true },
type: generator ? "generator" : null
});
if (state.tokens.next.id === "(" && state.tokens.next.line === state.tokens.curr.line) {
error("E039");
}
Expand All @@ -3633,7 +3652,7 @@ var JSHINT = (function() {
}

var i = optionalidentifier();
var fn = doFunction(i, undefined, generator);
var fn = doFunction({ name: i, type: generator ? "generator" : null });

function isVariable(name) { return name[0] !== "("; }
function isLocal(name) { return fn[name] === "var"; }
Expand Down

0 comments on commit 06b5d40

Please sign in to comment.