whole_func_string: function Statement(t, x) {
      var i, label, n, n2, p, c, ss, tt = t.get(true), tt2, x2, x3;
  
      // Cases for statements ending in a right curly return early, avoiding the
      // common semicolon insertion magic after this switch.
      switch (tt) {
        case FUNCTION:
          // DECLARED_FORM extends funDecls of x, STATEMENT_FORM doesn't.
          return FunctionDefinition(t, x, true,
                                    (x.nesting !== NESTING_TOP)
                                    ? STATEMENT_FORM
                                    : DECLARED_FORM);
  
        case LEFT_CURLY:
          n = new Node(t, blockInit());
          Statements(t, x.update({ parentBlock: n }).pushTarget(n).nest(NESTING_SHALLOW), n);
          t.mustMatch(RIGHT_CURLY);
          return n;
  
        case IF:
          n = new Node(t);
          n.condition = HeadExpression(t, x);
          x2 = x.pushTarget(n).nest(NESTING_DEEP);
          n.thenPart = Statement(t, x2);
          n.elsePart = t.match(ELSE) ? Statement(t, x2) : null;
          return n;
  
        case SWITCH:
          // This allows CASEs after a DEFAULT, which is in the standard.
          n = new Node(t, { cases: [], defaultIndex: -1 });
          n.discriminant = HeadExpression(t, x);
          x2 = x.pushTarget(n).nest(NESTING_DEEP);
          t.mustMatch(LEFT_CURLY);
          while ((tt = t.get()) !== RIGHT_CURLY) {
              switch (tt) {
                case DEFAULT:
                  if (n.defaultIndex >= 0)
                      throw t.newSyntaxError("More than one switch default");
                  // FALL THROUGH
                case CASE:
                  n2 = new Node(t);
                  if (tt === DEFAULT)
                      n.defaultIndex = n.cases.length;
                  else
                      n2.caseLabel = Expression(t, x2, COLON);
                  break;
  
                default:
                  throw t.newSyntaxError("Invalid switch case");
              }
              t.mustMatch(COLON);
              n2.statements = new Node(t, blockInit());
              while ((tt=t.peek(true)) !== CASE && tt !== DEFAULT &&
                      tt !== RIGHT_CURLY)
                  n2.statements.push(Statement(t, x2));
              n.cases.push(n2);
          }
          return n;
  
        case FOR:
          n = new Node(t, LOOP_INIT);
          if (t.match(IDENTIFIER)) {
              if (t.token.value === "each")
                  n.isEach = true;
              else
                  t.unget();
          }
          if (!x.parenFreeMode)
              t.mustMatch(LEFT_PAREN);
          x2 = x.pushTarget(n).nest(NESTING_DEEP);
          x3 = x.update({ inForLoopInit: true });
          if ((tt = t.peek()) !== SEMICOLON) {
              if (tt === VAR || tt === CONST) {
                  t.get();
                  n2 = Variables(t, x3);
              } else if (tt === LET) {
                  t.get();
                  if (t.peek() === LEFT_PAREN) {
                      n2 = LetBlock(t, x3, false);
                  } else {
                      // Let in for head, we need to add an implicit block
                      // around the rest of the for.
                      x3.parentBlock = n;
                      n.varDecls = [];
                      n2 = Variables(t, x3);
                  }
              } else {
                  n2 = Expression(t, x3);
              }
          }
          if (n2 && t.match(IN)) {
              n.type = FOR_IN;
              n.object = Expression(t, x3);
              if (n2.type === VAR || n2.type === LET) {
                  c = n2.children;
  
                  // Destructuring turns one decl into multiples, so either
                  // there must be only one destructuring or only one
                  // decl.
                  if (c.length !== 1 && n2.destructurings.length !== 1) {
                      throw new SyntaxError("Invalid for..in left-hand side",
                                            t.filename, n2.lineno);
                  }
                  if (n2.destructurings.length > 0) {
                      n.iterator = n2.destructurings[0];
                  } else {
                      n.iterator = c[0];
                  }
                  n.varDecl = n2;
              } else {
                  if (n2.type === ARRAY_INIT || n2.type === OBJECT_INIT) {
                      n2.destructuredNames = checkDestructuring(t, x3, n2);
                  }
                  n.iterator = n2;
              }
          } else {
              n.setup = n2;
              t.mustMatch(SEMICOLON);
              if (n.isEach)
                  throw t.newSyntaxError("Invalid for each..in loop");
              n.condition = (t.peek() === SEMICOLON)
                            ? null
                            : Expression(t, x3);
              t.mustMatch(SEMICOLON);
              tt2 = t.peek();
              n.update = (x.parenFreeMode
                          ? tt2 === LEFT_CURLY || definitions.isStatementStartCode[tt2]
                          : tt2 === RIGHT_PAREN)
                         ? null
                         : Expression(t, x3);
          }
          if (!x.parenFreeMode)
              t.mustMatch(RIGHT_PAREN);
          n.body = Statement(t, x2);
          return n;
  
        case WHILE:
          n = new Node(t, { isLoop: true });
          n.condition = HeadExpression(t, x);
          n.body = Statement(t, x.pushTarget(n).nest(NESTING_DEEP));
          return n;
  
        case DO:
          n = new Node(t, { isLoop: true });
          n.body = Statement(t, x.pushTarget(n).nest(NESTING_DEEP));
          t.mustMatch(WHILE);
          n.condition = HeadExpression(t, x);
          if (!x.ecmaStrictMode) {
              // <script language="JavaScript"> (without version hints) may need
              // automatic semicolon insertion without a newline after do-while.
              // See http://bugzilla.mozilla.org/show_bug.cgi?id=238945.
              t.match(SEMICOLON);
              return n;
          }
          break;
  
        case BREAK:
        case CONTINUE:
          n = new Node(t);
  
          // handle the |foo: break foo;| corner case
          x2 = x.pushTarget(n);
  
          if (t.peekOnSameLine() === IDENTIFIER) {
              t.get();
              n.label = t.token.value;
          }
  
          n.target = n.label
                   ? x2.labeledTargets.find(function(target) { return target.labels.has(n.label) })
                   : x2.defaultTarget;
  
          if (!n.target)
              throw t.newSyntaxError("Invalid " + ((tt === BREAK) ? "break" : "continue"));
          if (!n.target.isLoop && tt === CONTINUE)
              throw t.newSyntaxError("Invalid continue");
  
          break;
  
        case TRY:
          n = new Node(t, { catchClauses: [] });
          n.tryBlock = Block(t, x);
          while (t.match(CATCH)) {
              n2 = new Node(t);
              p = MaybeLeftParen(t, x);
              switch (t.get()) {
                case LEFT_BRACKET:
                case LEFT_CURLY:
                  // Destructured catch identifiers.
                  t.unget();
                  n2.varName = DestructuringExpression(t, x, true);
                  break;
                case IDENTIFIER:
                  n2.varName = t.token.value;
                  break;
                default:
                  throw t.newSyntaxError("missing identifier in catch");
                  break;
              }
              if (t.match(IF)) {
                  if (x.ecma3OnlyMode)
                      throw t.newSyntaxError("Illegal catch guard");
                  if (n.catchClauses.length && !n.catchClauses.top().guard)
                      throw t.newSyntaxError("Guarded catch after unguarded");
                  n2.guard = Expression(t, x);
              }
              MaybeRightParen(t, p);
              n2.block = Block(t, x);
              n.catchClauses.push(n2);
          }
          if (t.match(FINALLY))
              n.finallyBlock = Block(t, x);
          if (!n.catchClauses.length && !n.finallyBlock)
              throw t.newSyntaxError("Invalid try statement");
          return n;
  
        case CATCH:
        case FINALLY:
          throw t.newSyntaxError(definitions.tokens[tt] + " without preceding try");
  
        case THROW:
          n = new Node(t);
          n.exception = Expression(t, x);
          break;
  
        case RETURN:
          n = ReturnOrYield(t, x);
          break;
  
        case WITH:
          n = new Node(t);
          n.object = HeadExpression(t, x);
          n.body = Statement(t, x.pushTarget(n).nest(NESTING_DEEP));
          return n;
  
        case VAR:
        case CONST:
          n = Variables(t, x);
          break;
  
        case LET:
          if (t.peek() === LEFT_PAREN)
              n = LetBlock(t, x, true);
          else
              n = Variables(t, x);
          break;
  
        case DEBUGGER:
          n = new Node(t);
          break;
  
        case NEWLINE:
        case SEMICOLON:
          n = new Node(t, { type: SEMICOLON });
          n.expression = null;
          return n;
  
        default:
          if (tt === IDENTIFIER) {
              tt = t.peek();
              // Labeled statement.
              if (tt === COLON) {
                  label = t.token.value;
                  if (x.allLabels.has(label))
                      throw t.newSyntaxError("Duplicate label");
                  t.get();
                  n = new Node(t, { type: LABEL, label: label });
                  n.statement = Statement(t, x.pushLabel(label).nest(NESTING_SHALLOW));
                  n.target = (n.statement.type === LABEL) ? n.statement.target : n.statement;
                  return n;
              }
          }
  
          // Expression statement.
          // We unget the current token to parse the expression as a whole.
          n = new Node(t, { type: SEMICOLON });
          t.unget();
          n.expression = Expression(t, x);
          n.end = n.expression.end;
          break;
      }
  
      MagicalSemicolon(t);
      return n;
  }
func_code_string: function Statement(t, x) {
      var i, label, n, n2, p, c, ss, tt = t.get(true), tt2, x2, x3;
  
      // Cases for statements ending in a right curly return early, avoiding the
      // common semicolon insertion magic after this switch.
      switch (tt) {
        case FUNCTION:
          // DECLARED_FORM extends funDecls of x, STATEMENT_FORM doesn't.
          return FunctionDefinition(t, x, true,
                                    (x.nesting !== NESTING_TOP)
                                    ? STATEMENT_FORM
                                    : DECLARED_FORM);
  
        case LEFT_CURLY:
          n = new Node(t, blockInit());
          Statements(t, x.update({ parentBlock: n }).pushTarget(n).nest(NESTING_SHALLOW), n);
          t.mustMatch(RIGHT_CURLY);
          return n;
  
        case IF:
          n = new Node(t);
          n.condition = HeadExpression(t, x);
          x2 = x.pushTarget(n).nest(NESTING_DEEP);
          n.thenPart = Statement(t, x2);
          n.elsePart = t.match(ELSE) ? Statement(t, x2) : null;
          return n;
  
        case SWITCH:
          // This allows CASEs after a DEFAULT, which is in the standard.
          n = new Node(t, { cases: [], defaultIndex: -1 });
          n.discriminant = HeadExpression(t, x);
          x2 = x.pushTarget(n).nest(NESTING_DEEP);
          t.mustMatch(LEFT_CURLY);
          while ((tt = t.get()) !== RIGHT_CURLY) {
              switch (tt) {
                case DEFAULT:
                  if (n.defaultIndex >= 0)
                      throw t.newSyntaxError("More than one switch default");
                  // FALL THROUGH
                case CASE:
                  n2 = new Node(t);
                  if (tt === DEFAULT)
                      n.defaultIndex = n.cases.length;
                  else
                      n2.caseLabel = Expression(t, x2, COLON);
                  break;
  
                default:
                  throw t.newSyntaxError("Invalid switch case");
              }
              t.mustMatch(COLON);
              n2.statements = new Node(t, blockInit());
              while ((tt=t.peek(true)) !== CASE && tt !== DEFAULT &&
                      tt !== RIGHT_CURLY)
                  n2.statements.push(Statement(t, x2));
              n.cases.push(n2);
          }
          return n;
  
        case FOR:
          n = new Node(t, LOOP_INIT);
          if (t.match(IDENTIFIER)) {
              if (t.token.value === "each")
                  n.isEach = true;
              else
                  t.unget();
          }
          if (!x.parenFreeMode)
              t.mustMatch(LEFT_PAREN);
          x2 = x.pushTarget(n).nest(NESTING_DEEP);
          x3 = x.update({ inForLoopInit: true });
          if ((tt = t.peek()) !== SEMICOLON) {
              if (tt === VAR || tt === CONST) {
                  t.get();
                  n2 = Variables(t, x3);
              } else if (tt === LET) {
                  t.get();
                  if (t.peek() === LEFT_PAREN) {
                      n2 = LetBlock(t, x3, false);
                  } else {
                      // Let in for head, we need to add an implicit block
                      // around the rest of the for.
                      x3.parentBlock = n;
                      n.varDecls = [];
                      n2 = Variables(t, x3);
                  }
              } else {
                  n2 = Expression(t, x3);
              }
          }
          if (n2 && t.match(IN)) {
              n.type = FOR_IN;
              n.object = Expression(t, x3);
              if (n2.type === VAR || n2.type === LET) {
                  c = n2.children;
  
                  // Destructuring turns one decl into multiples, so either
                  // there must be only one destructuring or only one
                  // decl.
                  if (c.length !== 1 && n2.destructurings.length !== 1) {
                      throw new SyntaxError("Invalid for..in left-hand side",
                                            t.filename, n2.lineno);
                  }
                  if (n2.destructurings.length > 0) {
                      n.iterator = n2.destructurings[0];
                  } else {
                      n.iterator = c[0];
                  }
                  n.varDecl = n2;
              } else {
                  if (n2.type === ARRAY_INIT || n2.type === OBJECT_INIT) {
                      n2.destructuredNames = checkDestructuring(t, x3, n2);
                  }
                  n.iterator = n2;
              }
          } else {
              n.setup = n2;
              t.mustMatch(SEMICOLON);
              if (n.isEach)
                  throw t.newSyntaxError("Invalid for each..in loop");
              n.condition = (t.peek() === SEMICOLON)
                            ? null
                            : Expression(t, x3);
              t.mustMatch(SEMICOLON);
              tt2 = t.peek();
              n.update = (x.parenFreeMode
                          ? tt2 === LEFT_CURLY || definitions.isStatementStartCode[tt2]
                          : tt2 === RIGHT_PAREN)
                         ? null
                         : Expression(t, x3);
          }
          if (!x.parenFreeMode)
              t.mustMatch(RIGHT_PAREN);
          n.body = Statement(t, x2);
          return n;
  
        case WHILE:
          n = new Node(t, { isLoop: true });
          n.condition = HeadExpression(t, x);
          n.body = Statement(t, x.pushTarget(n).nest(NESTING_DEEP));
          return n;
  
        case DO:
          n = new Node(t, { isLoop: true });
          n.body = Statement(t, x.pushTarget(n).nest(NESTING_DEEP));
          t.mustMatch(WHILE);
          n.condition = HeadExpression(t, x);
          if (!x.ecmaStrictMode) {
              // <script language="JavaScript"> (without version hints) may need
              // automatic semicolon insertion without a newline after do-while.
              // See http://bugzilla.mozilla.org/show_bug.cgi?id=238945.
              t.match(SEMICOLON);
              return n;
          }
          break;
  
        case BREAK:
        case CONTINUE:
          n = new Node(t);
  
          // handle the |foo: break foo;| corner case
          x2 = x.pushTarget(n);
  
          if (t.peekOnSameLine() === IDENTIFIER) {
              t.get();
              n.label = t.token.value;
          }
  
          n.target = n.label
                   ? x2.labeledTargets.find(function(target) { return target.labels.has(n.label) })
                   : x2.defaultTarget;
  
          if (!n.target)
              throw t.newSyntaxError("Invalid " + ((tt === BREAK) ? "break" : "continue"));
          if (!n.target.isLoop && tt === CONTINUE)
              throw t.newSyntaxError("Invalid continue");
  
          break;
  
        case TRY:
          n = new Node(t, { catchClauses: [] });
          n.tryBlock = Block(t, x);
          while (t.match(CATCH)) {
              n2 = new Node(t);
              p = MaybeLeftParen(t, x);
              switch (t.get()) {
                case LEFT_BRACKET:
                case LEFT_CURLY:
                  // Destructured catch identifiers.
                  t.unget();
                  n2.varName = DestructuringExpression(t, x, true);
                  break;
                case IDENTIFIER:
                  n2.varName = t.token.value;
                  break;
                default:
                  throw t.newSyntaxError("missing identifier in catch");
                  break;
              }
              if (t.match(IF)) {
                  if (x.ecma3OnlyMode)
                      throw t.newSyntaxError("Illegal catch guard");
                  if (n.catchClauses.length && !n.catchClauses.top().guard)
                      throw t.newSyntaxError("Guarded catch after unguarded");
                  n2.guard = Expression(t, x);
              }
              MaybeRightParen(t, p);
              n2.block = Block(t, x);
              n.catchClauses.push(n2);
          }
          if (t.match(FINALLY))
              n.finallyBlock = Block(t, x);
          if (!n.catchClauses.length && !n.finallyBlock)
              throw t.newSyntaxError("Invalid try statement");
          return n;
  
        case CATCH:
        case FINALLY:
          throw t.newSyntaxError(definitions.tokens[tt] + " without preceding try");
  
        case THROW:
          n = new Node(t);
          n.exception = Expression(t, x);
          break;
  
        case RETURN:
          n = ReturnOrYield(t, x);
          break;
  
        case WITH:
          n = new Node(t);
          n.object = HeadExpression(t, x);
          n.body = Statement(t, x.pushTarget(n).nest(NESTING_DEEP));
          return n;
  
        case VAR:
        case CONST:
          n = Variables(t, x);
          break;
  
        case LET:
          if (t.peek() === LEFT_PAREN)
              n = LetBlock(t, x, true);
          else
              n = Variables(t, x);
          break;
  
        case DEBUGGER:
          n = new Node(t);
          break;
  
        case NEWLINE:
        case SEMICOLON:
          n = new Node(t, { type: SEMICOLON });
          n.expression = null;
          return n;
  
        default:
          if (tt === IDENTIFIER) {
              tt = t.peek();
              // Labeled statement.
              if (tt === COLON) {
                  label = t.token.value;
                  if (x.allLabels.has(label))
                      throw t.newSyntaxError("Duplicate label");
                  t.get();
                  n = new Node(t, { type: LABEL, label: label });
                  n.statement = Statement(t, x.pushLabel(label).nest(NESTING_SHALLOW));
                  n.target = (n.statement.type === LABEL) ? n.statement.target : n.statement;
                  return n;
              }
          }
  
          // Expression statement.
          // We unget the current token to parse the expression as a whole.
          n = new Node(t, { type: SEMICOLON });
          t.unget();
          n.expression = Expression(t, x);
          n.end = n.expression.end;
          break;
      }
  
      MagicalSemicolon(t);
      return n;
  }
func_documentation_string: /*
  Statement :: (tokenizer, compiler context) -> node
  
  Parses a Statement.