parser_parse_switch_statement_start (parser_context_t *context_p) /**< context */
{
  parser_switch_statement_t switch_statement;
  parser_loop_statement_t loop;
  parser_stack_iterator_t iterator;
  scanner_location_t start_location;
  bool switch_case_was_found;
  bool default_case_was_found;
  parser_branch_node_t *case_branches_p = NULL;

  JERRY_ASSERT (context_p->token.type == LEXER_KEYW_SWITCH);

  parser_parse_enclosed_expr (context_p);

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

#if JERRY_ESNEXT
  if (context_p->next_scanner_info_p->source_p == context_p->source_p - 1)
  {
    parser_push_block_context (context_p, true);
  }
#endif /* JERRY_ESNEXT */

  JERRY_ASSERT (context_p->next_scanner_info_p->source_p == context_p->source_p
                && context_p->next_scanner_info_p->type == SCANNER_TYPE_SWITCH);

  scanner_case_info_t *case_info_p = ((scanner_switch_info_t *) context_p->next_scanner_info_p)->case_p;
  scanner_set_active (context_p);

  if (case_info_p == NULL)
  {
    lexer_next_token (context_p);

    if (context_p->token.type == LEXER_RIGHT_BRACE)
    {
      scanner_release_active (context_p, sizeof (scanner_switch_info_t));

      parser_emit_cbc (context_p, CBC_POP);
      parser_flush_cbc (context_p);

      parser_stack_push_uint8 (context_p, PARSER_STATEMENT_BLOCK);
      parser_stack_iterator_init (context_p, &context_p->last_statement);
      return;
    }

    parser_raise_error (context_p, PARSER_ERR_INVALID_SWITCH);
  }

  scanner_get_location (&start_location, context_p);

  /* The reason of using an iterator is error management. If an error
   * occures, parser_free_jumps() free all data. However, the branches
   * created by parser_emit_cbc_forward_branch_item() would not be freed.
   * To free these branches, the current switch data is always stored
   * on the stack. If any change happens, this data is updated. Updates
   * are done using the iterator. */

  switch_statement.branch_list_p = NULL;
  loop.branch_list_p = NULL;

  parser_stack_push (context_p, &switch_statement, sizeof (parser_switch_statement_t));
  parser_stack_iterator_init (context_p, &iterator);
  parser_stack_push (context_p, &loop, sizeof (parser_loop_statement_t));
  parser_stack_push_uint8 (context_p, PARSER_STATEMENT_SWITCH);
  parser_stack_iterator_init (context_p, &context_p->last_statement);

  switch_case_was_found = false;
  default_case_was_found = false;

  do
  {
    scanner_set_location (context_p, &case_info_p->location);
    scanner_seek (context_p);
    case_info_p = case_info_p->next_p;

    /* The last letter of case and default is 'e' and 't' respectively.  */
    JERRY_ASSERT (context_p->source_p[-1] == LIT_CHAR_LOWERCASE_E
                  || context_p->source_p[-1] == LIT_CHAR_LOWERCASE_T);

    bool is_default = context_p->source_p[-1] == LIT_CHAR_LOWERCASE_T;
    lexer_next_token (context_p);

    if (is_default)
    {
      if (default_case_was_found)
      {
        parser_raise_error (context_p, PARSER_ERR_MULTIPLE_DEFAULTS_NOT_ALLOWED);
      }

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

      default_case_was_found = true;
      continue;
    }

    switch_case_was_found = true;

#if JERRY_LINE_INFO
    parser_line_info_append (context_p, context_p->token.line, context_p->token.column);
#endif /* JERRY_LINE_INFO */

    parser_parse_expression (context_p, PARSE_EXPR);

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

    uint16_t opcode = CBC_BRANCH_IF_STRICT_EQUAL;

    if (case_info_p == NULL
        || (case_info_p->next_p == NULL && case_info_p->location.source_p[-1] == LIT_CHAR_LOWERCASE_T))
    {
      /* There are no more 'case' statements in the switch. */
      parser_emit_cbc (context_p, CBC_STRICT_EQUAL);
      opcode = CBC_BRANCH_IF_TRUE_FORWARD;
    }

    parser_branch_node_t *new_case_p = parser_emit_cbc_forward_branch_item (context_p, opcode, NULL);

    if (case_branches_p == NULL)
    {
      switch_statement.branch_list_p = new_case_p;
      parser_stack_iterator_write (&iterator, &switch_statement, sizeof (parser_switch_statement_t));
    }
    else
    {
      case_branches_p->next_p = new_case_p;
    }

    case_branches_p = new_case_p;
  }
  while (case_info_p != NULL);

  JERRY_ASSERT (switch_case_was_found || default_case_was_found);

  if (!switch_case_was_found)
  {
    /* There was no case statement, so the expression result
     * of the switch must be popped from the stack */
    parser_emit_cbc (context_p, CBC_POP);
  }

  parser_emit_cbc_forward_branch (context_p, CBC_JUMP_FORWARD, &switch_statement.default_branch);
  parser_stack_iterator_write (&iterator, &switch_statement, sizeof (parser_switch_statement_t));

  if (!default_case_was_found)
  {
    parser_stack_change_last_uint8 (context_p, PARSER_STATEMENT_SWITCH_NO_DEFAULT);
  }

  scanner_release_switch_cases (((scanner_switch_info_t *) context_p->active_scanner_info_p)->case_p);
  scanner_release_active (context_p, sizeof (scanner_switch_info_t));

  scanner_set_location (context_p, &start_location);
  scanner_seek (context_p);
  lexer_next_token (context_p);
} /* parser_parse_switch_statement_start */
parser_parse_switch_statement_start (parser_context_t *context_p)  
{
  parser_switch_statement_t switch_statement;
  parser_loop_statement_t loop;
  parser_stack_iterator_t iterator;
  scanner_location_t start_location;
  bool switch_case_was_found;
  bool default_case_was_found;
  parser_branch_node_t *case_branches_p = NULL;

  JERRY_ASSERT (context_p->token.type == LEXER_KEYW_SWITCH);

  parser_parse_enclosed_expr (context_p);

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

#if JERRY_ESNEXT
  if (context_p->next_scanner_info_p->source_p == context_p->source_p - 1)
  {
    parser_push_block_context (context_p, true);
  }
#endif  

  JERRY_ASSERT (context_p->next_scanner_info_p->source_p == context_p->source_p
                && context_p->next_scanner_info_p->type == SCANNER_TYPE_SWITCH);

  scanner_case_info_t *case_info_p = ((scanner_switch_info_t *) context_p->next_scanner_info_p)->case_p;
  scanner_set_active (context_p);

  if (case_info_p == NULL)
  {
    lexer_next_token (context_p);

    if (context_p->token.type == LEXER_RIGHT_BRACE)
    {
      scanner_release_active (context_p, sizeof (scanner_switch_info_t));

      parser_emit_cbc (context_p, CBC_POP);
      parser_flush_cbc (context_p);

      parser_stack_push_uint8 (context_p, PARSER_STATEMENT_BLOCK);
      parser_stack_iterator_init (context_p, &context_p->last_statement);
      return;
    }

    parser_raise_error (context_p, PARSER_ERR_INVALID_SWITCH);
  }

  scanner_get_location (&start_location, context_p);

   

  switch_statement.branch_list_p = NULL;
  loop.branch_list_p = NULL;

  parser_stack_push (context_p, &switch_statement, sizeof (parser_switch_statement_t));
  parser_stack_iterator_init (context_p, &iterator);
  parser_stack_push (context_p, &loop, sizeof (parser_loop_statement_t));
  parser_stack_push_uint8 (context_p, PARSER_STATEMENT_SWITCH);
  parser_stack_iterator_init (context_p, &context_p->last_statement);

  switch_case_was_found = false;
  default_case_was_found = false;

  do
  {
    scanner_set_location (context_p, &case_info_p->location);
    scanner_seek (context_p);
    case_info_p = case_info_p->next_p;

     
    JERRY_ASSERT (context_p->source_p[-1] == LIT_CHAR_LOWERCASE_E
                  || context_p->source_p[-1] == LIT_CHAR_LOWERCASE_T);

    bool is_default = context_p->source_p[-1] == LIT_CHAR_LOWERCASE_T;
    lexer_next_token (context_p);

    if (is_default)
    {
      if (default_case_was_found)
      {
        parser_raise_error (context_p, PARSER_ERR_MULTIPLE_DEFAULTS_NOT_ALLOWED);
      }

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

      default_case_was_found = true;
      continue;
    }

    switch_case_was_found = true;

#if JERRY_LINE_INFO
    parser_line_info_append (context_p, context_p->token.line, context_p->token.column);
#endif  

    parser_parse_expression (context_p, PARSE_EXPR);

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

    uint16_t opcode = CBC_BRANCH_IF_STRICT_EQUAL;

    if (case_info_p == NULL
        || (case_info_p->next_p == NULL && case_info_p->location.source_p[-1] == LIT_CHAR_LOWERCASE_T))
    {
       
      parser_emit_cbc (context_p, CBC_STRICT_EQUAL);
      opcode = CBC_BRANCH_IF_TRUE_FORWARD;
    }

    parser_branch_node_t *new_case_p = parser_emit_cbc_forward_branch_item (context_p, opcode, NULL);

    if (case_branches_p == NULL)
    {
      switch_statement.branch_list_p = new_case_p;
      parser_stack_iterator_write (&iterator, &switch_statement, sizeof (parser_switch_statement_t));
    }
    else
    {
      case_branches_p->next_p = new_case_p;
    }

    case_branches_p = new_case_p;
  }
  while (case_info_p != NULL);

  JERRY_ASSERT (switch_case_was_found || default_case_was_found);

  if (!switch_case_was_found)
  {
     
    parser_emit_cbc (context_p, CBC_POP);
  }

  parser_emit_cbc_forward_branch (context_p, CBC_JUMP_FORWARD, &switch_statement.default_branch);
  parser_stack_iterator_write (&iterator, &switch_statement, sizeof (parser_switch_statement_t));

  if (!default_case_was_found)
  {
    parser_stack_change_last_uint8 (context_p, PARSER_STATEMENT_SWITCH_NO_DEFAULT);
  }

  scanner_release_switch_cases (((scanner_switch_info_t *) context_p->active_scanner_info_p)->case_p);
  scanner_release_active (context_p, sizeof (scanner_switch_info_t));

  scanner_set_location (context_p, &start_location);
  scanner_seek (context_p);
  lexer_next_token (context_p);
}  