function doFunction(context, options) {
    var f, token, name, statement, classExprBinding, isGenerator, isArrow,
      isMethod, ignoreLoopFunc;
    var oldOption = state.option;
    var oldIgnored = state.ignored;
    var isAsync = context & prodParams.preAsync;

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

    context &= ~prodParams.noin;
    context &= ~prodParams.tryClause;

    if (isAsync) {
      context |= prodParams.async;
    } else {
      context &= ~prodParams.async;
    }

    if (isGenerator) {
      context |= prodParams.yield;
    } else if (!isArrow) {
      context &= ~prodParams.yield;
    }
    context &= ~prodParams.preAsync;

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

    state.funct = functor(name || state.nameStack.infer(), state.tokens.next, {
      "(statement)": statement,
      "(context)":   state.funct,
      "(arrow)":     isArrow,
      "(method)":    isMethod,
      "(async)":     isAsync
    });

    f = state.funct;
    token = state.tokens.curr;

    functions.push(state.funct);

    // So that the function is available to itself and referencing itself is not
    // seen as a closure, add the function name to a new scope, but do not
    // test for unused (unused: false)
    // it is a new block scope so that params can override it, it can be block scoped
    // but declarations inside the function don't cause already declared error
    state.funct["(scope)"].stack("functionouter");
    var internallyAccessibleName = !isMethod && (name || classExprBinding);
    if (internallyAccessibleName) {
      state.funct["(scope)"].block.add(internallyAccessibleName,
        classExprBinding ? "class" : "function", state.tokens.curr, false);
    }

    if (!isArrow) {
      state.funct["(scope)"].funct.add("arguments", "var", token, false);
    }

    // create the param scope (params added in functionparams)
    state.funct["(scope)"].stack("functionparams");

    var paramsInfo = functionparams(context, options);

    if (paramsInfo) {
      state.funct["(params)"] = paramsInfo.params;
      state.funct["(hasSimpleParams)"] = paramsInfo.isSimple;
      state.funct["(metrics)"].arity = paramsInfo.arity;
      state.funct["(metrics)"].verifyMaxParametersPerFunction();
    } else {
      state.funct["(params)"] = [];
      state.funct["(metrics)"].arity = 0;
      state.funct["(hasSimpleParams)"] = true;
    }

    if (isArrow) {
      context &= ~prodParams.yield;

      if (!state.inES6(true)) {
        warning("W119", state.tokens.curr, "arrow function syntax (=>)", "6");
      }

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

    block(context, false, true, true, isArrow);

    if (!state.option.noyield && isGenerator && !state.funct["(yielded)"]) {
      warning("W124", state.tokens.curr);
    }

    state.funct["(metrics)"].verifyMaxStatementsPerFunction();
    state.funct["(metrics)"].verifyMaxComplexityPerFunction();
    state.funct["(unusedOption)"] = state.option.unused;
    state.option = oldOption;
    state.ignored = oldIgnored;
    state.funct["(last)"] = state.tokens.curr.line;
    state.funct["(lastcharacter)"] = state.tokens.curr.character;

    // unstack the params scope
    state.funct["(scope)"].unstack(); // also does usage and label checks

    // unstack the function outer stack
    state.funct["(scope)"].unstack();

    state.funct = state.funct["(context)"];

    if (!ignoreLoopFunc && !state.option.loopfunc && state.funct["(loopage)"]) {
      // If the function we just parsed accesses any non-local variables
      // trigger a warning. Otherwise, the function is safe even within
      // a loop.
      if (f["(outerMutables)"]) {
        warning("W083", token, f["(outerMutables)"].join(", "));
      }
    }

    return f;
  }
Parse a function literal.

@param {Number} context The parsing context
@param {Object} [options]
@param {string} [options.name] The identifier belonging to the function (if
                               any)
@param {token} [options.statement] The statement that triggered creation
                                   of the current function.
@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
@param {string} [options.classExprBinding] Define a function with this
                                           identifier in the new function's
                                           scope, mimicking the bahavior of
                                           class expression names within
                                           the body of member functions.