parser_parse_try_statement_end (parser_context_t *context_p) /**< context */
{
  parser_try_statement_t try_statement;
  parser_stack_iterator_t iterator;

  JERRY_ASSERT (context_p->stack_top_uint8 == PARSER_STATEMENT_TRY);

  parser_stack_iterator_init (context_p, &iterator);
  parser_stack_iterator_skip (&iterator, 1);
  parser_stack_iterator_read (&iterator, &try_statement, sizeof (parser_try_statement_t));

#if JERRY_ESNEXT
  context_p->scope_stack_top = try_statement.scope_stack_top;
  context_p->scope_stack_reg_top = try_statement.scope_stack_reg_top;
#endif /* JERRY_ESNEXT */

  lexer_next_token (context_p);

  if (try_statement.type == parser_finally_block)
  {
    parser_flush_cbc (context_p);
    PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, PARSER_FINALLY_CONTEXT_STACK_ALLOCATION);
#ifndef JERRY_NDEBUG
    PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_FINALLY_CONTEXT_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */

    parser_emit_cbc (context_p, CBC_CONTEXT_END);
    parser_set_branch_to_current_position (context_p, &try_statement.branch);
  }
  else
  {
    parser_set_branch_to_current_position (context_p, &try_statement.branch);

    if (try_statement.type == parser_catch_block)
    {
#if !JERRY_ESNEXT
      context_p->scope_stack_top = try_statement.scope_stack_top;
      context_p->scope_stack_reg_top = try_statement.scope_stack_reg_top;
#endif /* !JERRY_ESNEXT */

      if (context_p->token.type != LEXER_KEYW_FINALLY)
      {
        parser_flush_cbc (context_p);
        PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION);
#ifndef JERRY_NDEBUG
        PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */

        parser_emit_cbc (context_p, CBC_CONTEXT_END);
        parser_flush_cbc (context_p);

        try_statement.type = parser_finally_block;
      }
    }
    else
    {
      JERRY_ASSERT (try_statement.type == parser_try_block);

      if (context_p->token.type != LEXER_KEYW_CATCH
          && context_p->token.type != LEXER_KEYW_FINALLY)
      {
        parser_raise_error (context_p, PARSER_ERR_CATCH_FINALLY_EXPECTED);
      }
    }
  }

  if (try_statement.type == parser_finally_block)
  {
    parser_stack_pop (context_p, NULL, (uint32_t) (sizeof (parser_try_statement_t) + 1));
    parser_stack_iterator_init (context_p, &context_p->last_statement);
    return;
  }

  if (context_p->token.type == LEXER_KEYW_CATCH)
  {
    lexer_next_token (context_p);

    try_statement.type = parser_catch_block;
    parser_emit_cbc_ext_forward_branch (context_p,
                                        CBC_EXT_CATCH,
                                        &try_statement.branch);

    try_statement.scope_stack_top = context_p->scope_stack_top;
    try_statement.scope_stack_reg_top = context_p->scope_stack_reg_top;

#ifndef JERRY_NDEBUG
    bool block_found = false;
#endif /* !JERRY_NDEBUG */

    if (context_p->next_scanner_info_p->source_p == context_p->source_p)
    {
      JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK);
#ifndef JERRY_NDEBUG
      block_found = true;
#endif /* !JERRY_NDEBUG */

      if (scanner_is_context_needed (context_p, PARSER_CHECK_BLOCK_CONTEXT))
      {
        parser_emit_cbc_ext (context_p, CBC_EXT_TRY_CREATE_ENV);
      }

      scanner_create_variables (context_p, SCANNER_CREATE_VARS_NO_OPTS);
    }

    if (context_p->token.type == LEXER_LEFT_PAREN)
    {
#if JERRY_ESNEXT
      if (lexer_check_next_characters (context_p, LIT_CHAR_LEFT_SQUARE, LIT_CHAR_LEFT_BRACE))
      {
        parser_pattern_flags_t flags = (PARSER_PATTERN_BINDING
                                        | PARSER_PATTERN_TARGET_ON_STACK
                                        | PARSER_PATTERN_LET);

        parser_parse_initializer_by_next_char (context_p, flags);
      }
      else
      {
#endif /* JERRY_ESNEXT */
        lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL);
        JERRY_ASSERT (context_p->token.type == LEXER_LITERAL
                      && context_p->token.lit_location.type == LEXER_IDENT_LITERAL);

#if JERRY_ESNEXT
        uint16_t literal_index = context_p->lit_object.index;
        parser_emit_cbc_literal (context_p,
                                 (literal_index >= PARSER_REGISTER_START) ? CBC_ASSIGN_SET_IDENT : CBC_ASSIGN_LET_CONST,
                                 literal_index);
#else /* !JERRY_ESNEXT */
        parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, context_p->lit_object.index);
#endif /* JERRY_ESNEXT */

        lexer_next_token (context_p);

#ifndef JERRY_NDEBUG
        JERRY_ASSERT (block_found);
#endif /* !JERRY_NDEBUG */
#if JERRY_ESNEXT
      }
#endif /* JERRY_ESNEXT */

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

      lexer_next_token (context_p);

      if (context_p->token.type != LEXER_LEFT_BRACE)
      {
        parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED);
      }
    }
#if JERRY_ESNEXT
    else if (context_p->token.type == LEXER_LEFT_BRACE)
    {
      parser_emit_cbc (context_p, CBC_POP);
    }
#endif /* JERRY_ESNEXT */
    else
    {
      parser_raise_error (context_p, PARSER_ERR_LEFT_PAREN_EXPECTED);
    }

    parser_flush_cbc (context_p);
  }
  else
  {
    JERRY_ASSERT (context_p->token.type == LEXER_KEYW_FINALLY);

    lexer_next_token (context_p);

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

#ifndef JERRY_NDEBUG
    PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_FINALLY_CONTEXT_EXTRA_STACK_ALLOCATION);
#endif /* !JERRY_NDEBUG */

    try_statement.type = parser_finally_block;
    parser_emit_cbc_ext_forward_branch (context_p,
                                        CBC_EXT_FINALLY,
                                        &try_statement.branch);

#if JERRY_ESNEXT
    if (context_p->next_scanner_info_p->source_p == context_p->source_p)
    {
      JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK);

      if (scanner_is_context_needed (context_p, PARSER_CHECK_BLOCK_CONTEXT))
      {
        parser_emit_cbc_ext (context_p, CBC_EXT_TRY_CREATE_ENV);
      }

      scanner_create_variables (context_p, SCANNER_CREATE_VARS_NO_OPTS);
    }
#endif /* JERRY_ESNEXT */
  }

  lexer_next_token (context_p);
  parser_stack_iterator_write (&iterator, &try_statement, sizeof (parser_try_statement_t));
} /* parser_parse_try_statement_end */
parser_parse_try_statement_end (parser_context_t *context_p)  
{
  parser_try_statement_t try_statement;
  parser_stack_iterator_t iterator;

  JERRY_ASSERT (context_p->stack_top_uint8 == PARSER_STATEMENT_TRY);

  parser_stack_iterator_init (context_p, &iterator);
  parser_stack_iterator_skip (&iterator, 1);
  parser_stack_iterator_read (&iterator, &try_statement, sizeof (parser_try_statement_t));

#if JERRY_ESNEXT
  context_p->scope_stack_top = try_statement.scope_stack_top;
  context_p->scope_stack_reg_top = try_statement.scope_stack_reg_top;
#endif  

  lexer_next_token (context_p);

  if (try_statement.type == parser_finally_block)
  {
    parser_flush_cbc (context_p);
    PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, PARSER_FINALLY_CONTEXT_STACK_ALLOCATION);
#ifndef JERRY_NDEBUG
    PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_FINALLY_CONTEXT_STACK_ALLOCATION);
#endif  

    parser_emit_cbc (context_p, CBC_CONTEXT_END);
    parser_set_branch_to_current_position (context_p, &try_statement.branch);
  }
  else
  {
    parser_set_branch_to_current_position (context_p, &try_statement.branch);

    if (try_statement.type == parser_catch_block)
    {
#if !JERRY_ESNEXT
      context_p->scope_stack_top = try_statement.scope_stack_top;
      context_p->scope_stack_reg_top = try_statement.scope_stack_reg_top;
#endif  

      if (context_p->token.type != LEXER_KEYW_FINALLY)
      {
        parser_flush_cbc (context_p);
        PARSER_MINUS_EQUAL_U16 (context_p->stack_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION);
#ifndef JERRY_NDEBUG
        PARSER_MINUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_TRY_CONTEXT_STACK_ALLOCATION);
#endif  

        parser_emit_cbc (context_p, CBC_CONTEXT_END);
        parser_flush_cbc (context_p);

        try_statement.type = parser_finally_block;
      }
    }
    else
    {
      JERRY_ASSERT (try_statement.type == parser_try_block);

      if (context_p->token.type != LEXER_KEYW_CATCH
          && context_p->token.type != LEXER_KEYW_FINALLY)
      {
        parser_raise_error (context_p, PARSER_ERR_CATCH_FINALLY_EXPECTED);
      }
    }
  }

  if (try_statement.type == parser_finally_block)
  {
    parser_stack_pop (context_p, NULL, (uint32_t) (sizeof (parser_try_statement_t) + 1));
    parser_stack_iterator_init (context_p, &context_p->last_statement);
    return;
  }

  if (context_p->token.type == LEXER_KEYW_CATCH)
  {
    lexer_next_token (context_p);

    try_statement.type = parser_catch_block;
    parser_emit_cbc_ext_forward_branch (context_p,
                                        CBC_EXT_CATCH,
                                        &try_statement.branch);

    try_statement.scope_stack_top = context_p->scope_stack_top;
    try_statement.scope_stack_reg_top = context_p->scope_stack_reg_top;

#ifndef JERRY_NDEBUG
    bool block_found = false;
#endif  

    if (context_p->next_scanner_info_p->source_p == context_p->source_p)
    {
      JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK);
#ifndef JERRY_NDEBUG
      block_found = true;
#endif  

      if (scanner_is_context_needed (context_p, PARSER_CHECK_BLOCK_CONTEXT))
      {
        parser_emit_cbc_ext (context_p, CBC_EXT_TRY_CREATE_ENV);
      }

      scanner_create_variables (context_p, SCANNER_CREATE_VARS_NO_OPTS);
    }

    if (context_p->token.type == LEXER_LEFT_PAREN)
    {
#if JERRY_ESNEXT
      if (lexer_check_next_characters (context_p, LIT_CHAR_LEFT_SQUARE, LIT_CHAR_LEFT_BRACE))
      {
        parser_pattern_flags_t flags = (PARSER_PATTERN_BINDING
                                        | PARSER_PATTERN_TARGET_ON_STACK
                                        | PARSER_PATTERN_LET);

        parser_parse_initializer_by_next_char (context_p, flags);
      }
      else
      {
#endif  
        lexer_expect_identifier (context_p, LEXER_IDENT_LITERAL);
        JERRY_ASSERT (context_p->token.type == LEXER_LITERAL
                      && context_p->token.lit_location.type == LEXER_IDENT_LITERAL);

#if JERRY_ESNEXT
        uint16_t literal_index = context_p->lit_object.index;
        parser_emit_cbc_literal (context_p,
                                 (literal_index >= PARSER_REGISTER_START) ? CBC_ASSIGN_SET_IDENT : CBC_ASSIGN_LET_CONST,
                                 literal_index);
#else  
        parser_emit_cbc_literal (context_p, CBC_ASSIGN_SET_IDENT, context_p->lit_object.index);
#endif  

        lexer_next_token (context_p);

#ifndef JERRY_NDEBUG
        JERRY_ASSERT (block_found);
#endif  
#if JERRY_ESNEXT
      }
#endif  

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

      lexer_next_token (context_p);

      if (context_p->token.type != LEXER_LEFT_BRACE)
      {
        parser_raise_error (context_p, PARSER_ERR_LEFT_BRACE_EXPECTED);
      }
    }
#if JERRY_ESNEXT
    else if (context_p->token.type == LEXER_LEFT_BRACE)
    {
      parser_emit_cbc (context_p, CBC_POP);
    }
#endif  
    else
    {
      parser_raise_error (context_p, PARSER_ERR_LEFT_PAREN_EXPECTED);
    }

    parser_flush_cbc (context_p);
  }
  else
  {
    JERRY_ASSERT (context_p->token.type == LEXER_KEYW_FINALLY);

    lexer_next_token (context_p);

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

#ifndef JERRY_NDEBUG
    PARSER_PLUS_EQUAL_U16 (context_p->context_stack_depth, PARSER_FINALLY_CONTEXT_EXTRA_STACK_ALLOCATION);
#endif  

    try_statement.type = parser_finally_block;
    parser_emit_cbc_ext_forward_branch (context_p,
                                        CBC_EXT_FINALLY,
                                        &try_statement.branch);

#if JERRY_ESNEXT
    if (context_p->next_scanner_info_p->source_p == context_p->source_p)
    {
      JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_BLOCK);

      if (scanner_is_context_needed (context_p, PARSER_CHECK_BLOCK_CONTEXT))
      {
        parser_emit_cbc_ext (context_p, CBC_EXT_TRY_CREATE_ENV);
      }

      scanner_create_variables (context_p, SCANNER_CREATE_VARS_NO_OPTS);
    }
#endif  
  }

  lexer_next_token (context_p);
  parser_stack_iterator_write (&iterator, &try_statement, sizeof (parser_try_statement_t));
}  