function block(context, ordinary, stmt, isfunc, isfatarrow, iscase) {
    var a,
      b = inblock,
      old_indent = indent,
      m,
      t,
      d;

    inblock = ordinary;

    t = state.tokens.next;

    var metrics = state.funct["(metrics)"];
    metrics.nestedBlockDepth += 1;
    metrics.verifyMaxNestedBlockDepthPerFunction();

    if (state.tokens.next.id === "{") {
      advance("{");

      // create a new block scope
      state.funct["(scope)"].stack();

      if (state.tokens.next.id !== "}") {
        indent += state.option.indent;
        while (!ordinary && state.tokens.next.from > indent) {
          indent += state.option.indent;
        }

        if (isfunc) {
          m = {};
          for (d in state.directive) {
            m[d] = state.directive[d];
          }
          directives();

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

          if (state.option.strict && state.funct["(context)"]["(global)"]) {
            if (!m["use strict"] && !state.isStrict()) {
              warning("E007");
            }
          }
        }

        a = statements(context);

        metrics.statementCount += a.length;

        indent -= state.option.indent;
      } else if (isfunc) {
        // Ensure property is set for functions with empty bodies.
        state.funct["(isStrict)"] = state.isStrict();
      }

      advance("}", t);

      if (isfunc) {
        state.funct["(scope)"].validateParams(isfatarrow);
        if (m) {
          state.directive = m;
        }
      }

      state.funct["(scope)"].unstack();

      indent = old_indent;
    } else if (!ordinary) {
      if (isfunc) {
        state.funct["(scope)"].stack();

        if (stmt && !isfatarrow && !state.inMoz()) {
          error("W118", state.tokens.curr, "function closure expressions");
        }

        if (isfatarrow) {
          state.funct["(scope)"].validateParams(true);
        }

        var expr = expression(context, 10);

        if (state.option.noreturnawait && context & prodParams.async &&
            expr.identifier && expr.value === "await") {
          warning("W146", expr);
        }

        if (state.option.strict && state.funct["(context)"]["(global)"]) {
          if (!state.isStrict()) {
            warning("E007");
          }
        }

        state.funct["(scope)"].unstack();
      } else {
        error("E021", state.tokens.next, "{", state.tokens.next.value);
      }
    } else {

      state.funct["(scope)"].stack();

      if (!stmt || state.option.curly) {
        warning("W116", state.tokens.next, "{", state.tokens.next.value);
      }

      // JSHint observes Annex B of the ECMAScript specification by default,
      // where function declarations are permitted in the statement positions
      // of IfStatements.
      var supportsFnDecl = state.funct["(verb)"] === "if" ||
        state.tokens.curr.id === "else";

      state.tokens.next.inBracelessBlock = true;
      indent += state.option.indent;
      // test indentation only if statement is in new line
      a = [statement(context)];
      indent -= state.option.indent;

      if (a[0] && a[0].declaration &&
        !(supportsFnDecl && a[0].id === "function")) {
        error("E048", a[0], a[0].id[0].toUpperCase() + a[0].id.slice(1));
      }

      state.funct["(scope)"].unstack();
    }

    // Don't clear and let it propagate out if it is "break", "return" or
    // similar in switch case
    switch (state.funct["(verb)"]) {
    case "break":
    case "continue":
    case "return":
    case "throw":
      if (iscase) {
        break;
      }

      /* falls through */
    default:
      state.funct["(verb)"] = null;
    }

    inblock = b;
    if (ordinary && state.option.noempty && (!a || a.length === 0)) {
      warning("W035", state.tokens.prev);
    }
    metrics.nestedBlockDepth -= 1;
    return a;
  }
Parses a single block. A block is a sequence of statements wrapped in
braces.

@param {number} context - parsing context
@param {boolean} ordinary - `true` for everything but function bodies and
                            try blocks
@param {boolean} [stmt] - `true` if block can be a single statement (e.g.
                          in if/for/while)
@param {boolean} [isfunc] - `true` if block is a function body
@param {boolean} [isfatarrow] - `true` if its a body of a fat arrow
                                function
@param {boolean} [iscase] - `true` if block is a switch case block

@returns {token} - the token describing the block