parser_parse_for_statement_end (parser_context_t *context_p) /**< context */
{
  parser_for_statement_t for_statement;
  parser_loop_statement_t loop;
  lexer_token_t current_token;
  scanner_location_t location;
  cbc_opcode_t opcode;

  JERRY_ASSERT (context_p->stack_top_uint8 == PARSER_STATEMENT_FOR);

  parser_stack_iterator_t iterator;
  parser_stack_iterator_init (context_p, &iterator);

  parser_stack_iterator_skip (&iterator, 1);
  parser_stack_iterator_read (&iterator, &loop, sizeof (parser_loop_statement_t));
  parser_stack_iterator_skip (&iterator, sizeof (parser_loop_statement_t));
  parser_stack_iterator_read (&iterator, &for_statement, sizeof (parser_for_statement_t));

#if JERRY_ESNEXT
  bool has_block_context = false;
  uint8_t next_statement_type;

  parser_stack_iterator_skip (&iterator, sizeof (parser_for_statement_t));
  parser_stack_iterator_read (&iterator, &next_statement_type, 1);

  if (next_statement_type == PARSER_STATEMENT_PRIVATE_CONTEXT)
  {
    has_block_context = true;
  }
#endif

  scanner_get_location (&location, context_p);
  current_token = context_p->token;

  scanner_set_location (context_p, &for_statement.expression_location);
  scanner_seek (context_p);
  lexer_next_token (context_p);

  parser_set_continues_to_current_position (context_p, loop.branch_list_p);

#if JERRY_ESNEXT
  if (has_block_context)
  {
    parser_emit_cbc_ext (context_p, CBC_EXT_CLONE_FULL_CONTEXT);
  }
#endif

  if (context_p->token.type != LEXER_RIGHT_PAREN)
  {
    parser_parse_expression_statement (context_p, PARSE_EXPR);

    if (context_p->token.type != LEXER_RIGHT_PAREN)
    {
      parser_raise_error (context_p, PARSER_ERR_RIGHT_PAREN_EXPECTED);
    }
  }

  parser_set_branch_to_current_position (context_p, &for_statement.branch);

  scanner_set_location (context_p, &for_statement.condition_location);
  scanner_seek (context_p);
  lexer_next_token (context_p);

  if (context_p->token.type != LEXER_SEMICOLON)
  {
    parser_parse_expression (context_p, PARSE_EXPR);

    if (context_p->token.type != LEXER_SEMICOLON)
    {
      parser_raise_error (context_p, PARSER_ERR_SEMICOLON_EXPECTED);
    }

    opcode = CBC_BRANCH_IF_TRUE_BACKWARD;
    if (context_p->last_cbc_opcode == CBC_LOGICAL_NOT)
    {
      context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
      opcode = CBC_BRANCH_IF_FALSE_BACKWARD;
    }
    else if (context_p->last_cbc_opcode == CBC_PUSH_TRUE)
    {
      context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
      opcode = CBC_JUMP_BACKWARD;
    }
  }
  else
  {
    opcode = CBC_JUMP_BACKWARD;
  }

  parser_stack_pop (context_p, NULL, 1 + sizeof (parser_loop_statement_t) + sizeof (parser_for_statement_t));
  parser_stack_iterator_init (context_p, &context_p->last_statement);

  parser_emit_cbc_backward_branch (context_p, (uint16_t) opcode, for_statement.start_offset);
  parser_set_breaks_to_current_position (context_p, loop.branch_list_p);

#if JERRY_ESNEXT
  if (context_p->stack_top_uint8 == PARSER_STATEMENT_PRIVATE_SCOPE
      || context_p->stack_top_uint8 == PARSER_STATEMENT_PRIVATE_CONTEXT)
  {
    parser_pop_block_context (context_p);
  }
#endif

  /* Calling scanner_seek is unnecessary because all
   * info blocks inside the for statement should be processed. */
  scanner_set_location (context_p, &location);
  context_p->token = current_token;
} /* parser_parse_for_statement_end */