parser_parse_class (parser_context_t *context_p, /**< context */
                    bool is_statement) /**< true - if class is parsed as a statement
                                        *   false - otherwise (as an expression) */
{
  JERRY_ASSERT (context_p->token.type == LEXER_KEYW_CLASS);

  uint16_t class_ident_index = PARSER_INVALID_LITERAL_INDEX;
  uint16_t class_name_index = PARSER_INVALID_LITERAL_INDEX;
  parser_class_literal_opts_t opts = PARSER_CLASS_LITERAL_NO_OPTS;

  if (context_p->next_scanner_info_p->source_p == context_p->source_p)
  {
    JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_CLASS_CONSTRUCTOR);
    scanner_release_next (context_p, sizeof (scanner_info_t));
    opts |= PARSER_CLASS_LITERAL_CTOR_PRESENT;
  }

  if (is_statement)
  {
    /* Class statement must contain an identifier. */
    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 (context_p->next_scanner_info_p->source_p == context_p->source_p)
    {
      JERRY_ASSERT (context_p->next_scanner_info_p->type == SCANNER_TYPE_ERR_REDECLARED);
      parser_raise_error (context_p, PARSER_ERR_VARIABLE_REDECLARED);
    }
    class_ident_index = context_p->lit_object.index;

    lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_NEW_IDENT_LITERAL);
    context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_USED;
    class_name_index = context_p->lit_object.index;

#if JERRY_MODULE_SYSTEM
    parser_module_append_export_name (context_p);
    context_p->status_flags &= (uint32_t) ~PARSER_MODULE_STORE_IDENT;
#endif /* JERRY_MODULE_SYSTEM */

    lexer_next_token (context_p);
  }
  else
  {
    lexer_next_token (context_p);

    /* Class expression may contain an identifier. */
    if (context_p->token.type == LEXER_LITERAL && context_p->token.lit_location.type == LEXER_IDENT_LITERAL)
    {
      lexer_construct_literal_object (context_p, &context_p->token.lit_location, LEXER_NEW_IDENT_LITERAL);
      context_p->lit_object.literal_p->status_flags |= LEXER_FLAG_USED;
      class_name_index = context_p->lit_object.index;
      lexer_next_token (context_p);
    }
  }

  if (class_name_index != PARSER_INVALID_LITERAL_INDEX)
  {
    if (JERRY_UNLIKELY (context_p->scope_stack_top >= context_p->scope_stack_size))
    {
      JERRY_ASSERT (context_p->scope_stack_size == PARSER_MAXIMUM_DEPTH_OF_SCOPE_STACK);
      parser_raise_error (context_p, PARSER_ERR_SCOPE_STACK_LIMIT_REACHED);
    }

    parser_scope_stack_t *scope_stack_p = context_p->scope_stack_p + context_p->scope_stack_top;

    PARSER_PLUS_EQUAL_U16 (context_p->scope_stack_top, 1);
    scope_stack_p->map_from = class_name_index;
    scope_stack_p->map_to = 0;

    parser_emit_cbc_ext_literal (context_p, CBC_EXT_PUSH_NAMED_CLASS_ENV, class_name_index);
  }
  else
  {
    parser_emit_cbc (context_p, CBC_PUSH_UNDEFINED);
  }

  bool is_strict = (context_p->status_flags & PARSER_IS_STRICT) != 0;

  /* 14.5. A ClassBody is always strict code. */
  context_p->status_flags |= PARSER_IS_STRICT;

  if (context_p->token.type == LEXER_KEYW_EXTENDS)
  {
    lexer_next_token (context_p);
    parser_parse_expression (context_p, PARSE_EXPR | PARSE_EXPR_LEFT_HAND_SIDE);
    opts |= PARSER_CLASS_LITERAL_HERTIAGE_PRESENT;
  }
  else
  {
    /* Elisions represents that the classHeritage is not present */
    parser_emit_cbc (context_p, CBC_PUSH_ELISION);
  }

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

  /* ClassDeclaration is parsed. Continue with class body. */
  bool has_static_field = parser_parse_class_body (context_p, opts);

  if (class_name_index != PARSER_INVALID_LITERAL_INDEX)
  {
    parser_emit_cbc_ext_literal (context_p, CBC_EXT_FINALIZE_NAMED_CLASS, class_name_index);
    parser_emit_cbc_ext_literal (context_p, CBC_EXT_SET_CLASS_NAME, class_name_index);
    PARSER_MINUS_EQUAL_U16 (context_p->scope_stack_top, 1);
  }
  else
  {
    parser_emit_cbc_ext (context_p, CBC_EXT_FINALIZE_ANONYMOUS_CLASS);
  }

  if (has_static_field)
  {
    parser_emit_cbc_ext (context_p, CBC_EXT_RUN_STATIC_FIELD_INIT);
  }

  if (is_statement)
  {
    cbc_opcode_t opcode = CBC_MOV_IDENT;

    if (class_ident_index < PARSER_REGISTER_START)
    {
      opcode = (scanner_literal_is_created (context_p, class_ident_index) ? CBC_ASSIGN_LET_CONST
                                                                          : CBC_INIT_LET);
    }

    parser_emit_cbc_literal (context_p, (uint16_t) opcode, class_ident_index);
    parser_flush_cbc (context_p);
  }

  if (!is_strict)
  {
    /* Restore flag */
    context_p->status_flags &= (uint32_t) ~PARSER_IS_STRICT;
  }
  context_p->status_flags &= (uint32_t) ~PARSER_ALLOW_SUPER;

  lexer_next_token (context_p);
} /* parser_parse_class */