@Nullable
  private PsiBuilder.Marker parseGroup(PsiBuilder builder) {
    final IElementType type = builder.getTokenType();

    final PsiBuilder.Marker marker = builder.mark();

    if (RegExpTT.GROUPS.contains(type)) {
      builder.advanceLexer();
      parseGroupEnd(builder);
      marker.done(RegExpElementTypes.GROUP);
    }
    else if (type == RegExpTT.SET_OPTIONS) {
      builder.advanceLexer();

      if (builder.getTokenType() == RegExpTT.OPTIONS_ON) {
        final PsiBuilder.Marker o = builder.mark();
        builder.advanceLexer();
        o.done(RegExpElementTypes.OPTIONS);
      }
      if (builder.getTokenType() == RegExpTT.OPTIONS_OFF) {
        final PsiBuilder.Marker o = builder.mark();
        builder.advanceLexer();
        o.done(RegExpElementTypes.OPTIONS);
      }

      if (builder.getTokenType() == RegExpTT.COLON) {
        builder.advanceLexer();
        parseGroupEnd(builder);
        marker.done(RegExpElementTypes.GROUP);
      }
      else {
        checkMatches(builder, RegExpTT.GROUP_END, RegExpBundle.message("parse.error.unclosed.options.group"));
        marker.done(RegExpElementTypes.SET_OPTIONS);
      }
    }
    else if (RegExpTT.CHARACTERS.contains(type) || type == RegExpTT.NAMED_CHARACTER) {
      marker.drop();
      parseCharacter(builder);
    }
    else if (type == RegExpTT.NUMBER || type == RegExpTT.COMMA) {
      // don't show these as errors
      builder.remapCurrentToken(RegExpTT.CHARACTER);
      builder.advanceLexer();
      marker.done(RegExpElementTypes.CHAR);
    }
    else if (RegExpTT.BOUNDARIES.contains(type)) {
      builder.advanceLexer();
      marker.done(RegExpElementTypes.BOUNDARY);
    }
    else if (type == RegExpTT.BACKREF) {
      builder.advanceLexer();
      marker.done(RegExpElementTypes.BACKREF);
    }
    else if (type == RegExpTT.PYTHON_NAMED_GROUP || type == RegExpTT.RUBY_NAMED_GROUP || type == RegExpTT.RUBY_QUOTED_NAMED_GROUP) {
      builder.advanceLexer();
      checkMatches(builder, RegExpTT.NAME, RegExpBundle.message("parse.error.group.name.expected"));
      checkMatches(builder, type == RegExpTT.RUBY_QUOTED_NAMED_GROUP ? RegExpTT.QUOTE : RegExpTT.GT,
                   RegExpBundle.message("parse.error.unclosed.group.name"));
      parseGroupEnd(builder);
      marker.done(RegExpElementTypes.GROUP);
    }
    else if (type == RegExpTT.PYTHON_NAMED_GROUP_REF || type == RegExpTT.PCRE_RECURSIVE_NAMED_GROUP_REF) {
      parseNamedGroupRef(builder, marker, RegExpTT.GROUP_END);
    }
    else if (type == RegExpTT.PCRE_NUMBERED_GROUP_REF) {
      builder.advanceLexer();
      marker.done(RegExpElementTypes.BACKREF);
    }
    else if (type == RegExpTT.RUBY_NAMED_GROUP_REF || type == RegExpTT.RUBY_NAMED_GROUP_CALL) {
      parseNamedGroupRef(builder, marker, RegExpTT.GT);
    }
    else if (type == RegExpTT.RUBY_QUOTED_NAMED_GROUP_REF || type == RegExpTT.RUBY_QUOTED_NAMED_GROUP_CALL) {
      parseNamedGroupRef(builder, marker, RegExpTT.QUOTE);
    }
    else if (type == RegExpTT.CONDITIONAL) {
      builder.advanceLexer();
      parseCondition(builder);
      parseBranch(builder);
      if (builder.getTokenType() == RegExpTT.UNION) {
        builder.advanceLexer();
        parseBranch(builder);
      }
      if (!checkMatches(builder, RegExpTT.GROUP_END, RegExpBundle.message("parse.error.unclosed.group"))) {
        parseGroupEnd(builder);
      }
      marker.done(RegExpElementTypes.CONDITIONAL);
    }
    else if (type == RegExpTT.PROPERTY) {
      marker.drop();
      parseProperty(builder);
    }
    else if (type == RegExpTT.DOT || type == RegExpTT.CHAR_CLASS) {
      builder.advanceLexer();
      marker.done(RegExpElementTypes.SIMPLE_CLASS);
    }
    else if (type == RegExpTT.CLASS_BEGIN) {
      marker.drop();
      return parseClass(builder);
    }
    else {
      marker.drop();
      return null;
    }
    return marker;
  }
@Nullable
  private PsiBuilder.Marker parseGroup(PsiBuilder builder)