function parseFunction(node, isStatement) {
    if (tokType === _name) {
      node.id = parseIdent();
    } else if (isStatement) {
      unexpected();
    } else {
      node.id = null;
    }
    node.params = [];
    var first = true;
    expect(_parenL);
    while (!eat(_parenR)) {
      if (!first) {
        expect(_comma);
      } else {
        first = false;
      }
      node.params.push(parseIdent());
    }

    // Start a new scope with regard to labels and the `inFunction`
    // flag (restore them to their old value afterwards).
    var oldInFunc = inFunction;
    var oldLabels = labels;
    inFunction = true;
    labels = [];
    node.body = parseBlock(true);
    inFunction = oldInFunc;
    labels = oldLabels;

    // If this is a strict mode function, verify that argument names
    // are not repeated, and it does not try to bind the words `eval`
    // or `arguments`.
    if (strict || node.body.body.length && isUseStrict(node.body.body[0])) {
      for (var i = node.id ? -1 : 0; i < node.params.length; ++i) {
        var id = i < 0 ? node.id : node.params[i];
        if (isStrictReservedWord(id.name) || isStrictBadIdWord(id.name)) {
          raise(id.start, "Defining '" + id.name + "' in strict mode");
        }
        if (i >= 0) {
          for (var j = 0; j < i; ++j) {
            if (id.name === node.params[j].name) {
              raise(id.start, "Argument name clash in strict mode");
            }
          }
        }
      }
    }

    return finishNode(node, isStatement ? "FunctionDeclaration" : "FunctionExpression");
  }
Parse a function declaration or literal (depending on the
`isStatement` parameter).

@param {!node_t} node
@param {boolean} isStatement
@returns {!node_t}