parser_parse_function_expression (parser_context_t *context_p, /**< context */
                                  uint32_t status_flags) /**< function status flags */
{
  int literals = 0;
  uint16_t literal1 = 0;
  uint16_t literal2 = 0;
  uint16_t function_literal_index;
  int32_t function_name_index = -1;

#if !JERRY_ESNEXT
  JERRY_ASSERT (status_flags & PARSER_IS_FUNC_EXPRESSION);
#endif /* !JERRY_ESNEXT */

#if JERRY_ESNEXT
  if (status_flags & PARSER_IS_FUNC_EXPRESSION)
  {
#endif /* !JERRY_ESNEXT */

#if JERRY_DEBUGGER
    parser_line_counter_t debugger_line = context_p->token.line;
    parser_line_counter_t debugger_column = context_p->token.column;
#endif /* JERRY_DEBUGGER */

#if JERRY_ESNEXT
    uint32_t parent_status_flags = context_p->status_flags;

    context_p->status_flags &= (uint32_t) ~(PARSER_IS_ASYNC_FUNCTION
                                            | PARSER_IS_GENERATOR_FUNCTION
                                            | PARSER_DISALLOW_AWAIT_YIELD);

    if (status_flags & PARSER_IS_ASYNC_FUNCTION)
    {
      /* The name of the function cannot be await. */
      context_p->status_flags |= PARSER_IS_ASYNC_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD;
    }

    if (lexer_consume_generator (context_p))
    {
      /* The name of the function cannot be yield. */
      context_p->status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD;
      status_flags |= PARSER_IS_GENERATOR_FUNCTION | PARSER_DISALLOW_AWAIT_YIELD;
    }
#endif /* JERRY_ESNEXT */

    if (!lexer_check_next_character (context_p, LIT_CHAR_LEFT_PAREN))
    {
      lexer_next_token (context_p);

      if (context_p->token.type != LEXER_LITERAL
          || context_p->token.lit_location.type != LEXER_IDENT_LITERAL)
      {
        parser_raise_error (context_p, PARSER_ERR_IDENTIFIER_EXPECTED);
      }

      parser_flush_cbc (context_p);

      lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_STRING_LITERAL);

#if JERRY_DEBUGGER
      if (JERRY_CONTEXT (debugger_flags) & JERRY_DEBUGGER_CONNECTED)
      {
        jerry_debugger_send_string (JERRY_DEBUGGER_FUNCTION_NAME,
                                    JERRY_DEBUGGER_NO_SUBTYPE,
                                    context_p->lit_object.literal_p->u.char_p,
                                    context_p->lit_object.literal_p->prop.length);

        /* Reset token position for the function. */
        context_p->token.line = debugger_line;
        context_p->token.column = debugger_column;
      }
#endif /* JERRY_DEBUGGER */

      if (context_p->token.keyword_type >= LEXER_FIRST_NON_STRICT_ARGUMENTS)
      {
        status_flags |= PARSER_HAS_NON_STRICT_ARG;
      }

      function_name_index = context_p->lit_object.index;
    }

#if JERRY_ESNEXT
    context_p->status_flags = parent_status_flags;
  }
#endif /* JERRY_ESNEXT */

  if (context_p->last_cbc_opcode == CBC_PUSH_LITERAL)
  {
    literals = 1;
    literal1 = context_p->last_cbc.literal_index;
    context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
  }
  else if (context_p->last_cbc_opcode == CBC_PUSH_TWO_LITERALS)
  {
    literals = 2;
    literal1 = context_p->last_cbc.literal_index;
    literal2 = context_p->last_cbc.value;
    context_p->last_cbc_opcode = PARSER_CBC_UNAVAILABLE;
  }

  function_literal_index = lexer_construct_function_object (context_p, status_flags);

  JERRY_ASSERT (context_p->last_cbc_opcode == PARSER_CBC_UNAVAILABLE);

#if JERRY_ESNEXT
  if (function_name_index != -1)
  {
    parser_set_function_name (context_p, function_literal_index, (uint16_t) function_name_index, 0);
  }
#endif /* JERRY_ESNEXT */

  if (literals == 1)
  {
    context_p->last_cbc_opcode = CBC_PUSH_TWO_LITERALS;
    context_p->last_cbc.literal_index = literal1;
    context_p->last_cbc.value = function_literal_index;
  }
  else if (literals == 2)
  {
    context_p->last_cbc_opcode = CBC_PUSH_THREE_LITERALS;
    context_p->last_cbc.literal_index = literal1;
    context_p->last_cbc.value = literal2;
    context_p->last_cbc.third_literal_index = function_literal_index;
  }
  else
  {
    parser_emit_cbc_literal (context_p,
                             CBC_PUSH_LITERAL,
                             function_literal_index);

    if (function_name_index != -1)
    {
      context_p->last_cbc_opcode = PARSER_TO_EXT_OPCODE (CBC_EXT_PUSH_NAMED_FUNC_EXPRESSION);
      context_p->last_cbc.value = (uint16_t) function_name_index;
    }
  }

  context_p->last_cbc.literal_type = LEXER_FUNCTION_LITERAL;
  context_p->last_cbc.literal_keyword_type = LEXER_EOS;
} /* parser_parse_function_expression */