protected NegationSelector negation(int number) throws ParserException {

        StringBuilder sb = new StringBuilder();
        ignoreWhitespaces();
        if (end() || current != '(') {
            throw new ParserException("Expected '(' at position " + pos);
        }
        //sb.append(current);
        int parenthesisPos = pos;
        next();
        ignoreWhitespaces();
        if (end()) {
            throw new ParserException("Selector expected at position " + pos);
        }
        int initialPos = pos;
        SimpleSelector simpleSelector = null;
        if (current == '*') {
            //universal selector
            sb.append(current);
            TypeSelector ts = new TypeSelector("*", new Context(content, "*", initialPos, pos + 1));
            parserListener.negationTypeSelector(ts);
            simpleSelector = ts;
            next();
        } else if (Character.isLetter(current)) {
            //type selector
            String type = identifier();
            sb.append(type);
            TypeSelector ts = new TypeSelector(type, new Context(content, type, initialPos, pos));
            parserListener.negationTypeSelector(ts);
            simpleSelector = ts;
        } else if (current == '.') {
            //class selector
            sb.append(current);
            next();
            String className = !end() ? identifier() : null;
            if (className == null || className.isEmpty()) {
                throw new ParserException("Expected className at position " + pos);
            }
            ClassSelector cs = new ClassSelector(className, new Context(content, "." + className, initialPos, pos));
            simpleSelector = cs;
            parserListener.negationClassSelector(cs);
            sb.append(className);
        } else if (current == '#') {
            //hash selector
            sb.append(current);
            next();
            String id = !end() ? identifier() : null;
            if (id == null || id.isEmpty()) {
                throw new ParserException("Expected id at position " + pos);
            }
            HashSelector hs = new HashSelector(id, new Context(content, "#" + id, initialPos, pos));
            simpleSelector = hs;
            parserListener.negationIdSelector(hs);
            sb.append(id);
        } else if (current == '[') {
            //attribute selectors
            sb.append(current);
            next();
            AttributeSelector as = attribute();
            simpleSelector = as;
            parserListener.negationAttributeSelector(as);
            sb.append(as.getContext());
            sb.append(']');
        } else if (current == ':') {
            //pseudo-class only
            sb.append(current);
            next();
            if (end()) {
                throw new ParserException("Expected pseudo-element or pseudo-class at " + pos);
            }
            boolean doubleColon = false;
            if (current == ':') {
                doubleColon = true;
                sb.append(current);
                next();
            }
            String ident = !end() ? identifier() : null;
            if (ident == null || ident.isEmpty()) {
                throw new ParserException("Expected identifier at position " + pos);
            }
            if ("not".equalsIgnoreCase(ident) || isPseudoSpecialCase(ident) || doubleColon) {
                throw new ParserException("Expected pseudo-class (starting with ':', except ':not', ':first-line', ':first-letter', ':before' and ':after') at position " + pos);
            }
            PseudoSelector ps = pseudo(ident, PseudoType.PSEUDO_CLASS, doubleColon);
            simpleSelector = ps;
            parserListener.negationPseudoSelector(ps);
            sb.append(ps.getContext());
        } else {
            throw new ParserException("Selector expected at position " + pos);
        }

        ignoreWhitespaces();
        if (end() || current != ')') {
            throw new ParserException("Expected ')' at position " + pos);
        }
        //sb.append(current);
        next();

        return new NegationSelector(simpleSelector, new Context(content, sb.toString(), parenthesisPos, pos));

    }
protected NegationSelector negation(int number) throws ParserException {

        StringBuilder sb = new StringBuilder();
        ignoreWhitespaces();
        if (end() || current != '(') {
            throw new ParserException("Expected '(' at position " + pos);
        }
        
        int parenthesisPos = pos;
        next();
        ignoreWhitespaces();
        if (end()) {
            throw new ParserException("Selector expected at position " + pos);
        }
        int initialPos = pos;
        SimpleSelector simpleSelector = null;
        if (current == '*') {
            
            sb.append(current);
            TypeSelector ts = new TypeSelector("*", new Context(content, "*", initialPos, pos + 1));
            parserListener.negationTypeSelector(ts);
            simpleSelector = ts;
            next();
        } else if (Character.isLetter(current)) {
            
            String type = identifier();
            sb.append(type);
            TypeSelector ts = new TypeSelector(type, new Context(content, type, initialPos, pos));
            parserListener.negationTypeSelector(ts);
            simpleSelector = ts;
        } else if (current == '.') {
            
            sb.append(current);
            next();
            String className = !end() ? identifier() : null;
            if (className == null || className.isEmpty()) {
                throw new ParserException("Expected className at position " + pos);
            }
            ClassSelector cs = new ClassSelector(className, new Context(content, "." + className, initialPos, pos));
            simpleSelector = cs;
            parserListener.negationClassSelector(cs);
            sb.append(className);
        } else if (current == '#') {
            
            sb.append(current);
            next();
            String id = !end() ? identifier() : null;
            if (id == null || id.isEmpty()) {
                throw new ParserException("Expected id at position " + pos);
            }
            HashSelector hs = new HashSelector(id, new Context(content, "#" + id, initialPos, pos));
            simpleSelector = hs;
            parserListener.negationIdSelector(hs);
            sb.append(id);
        } else if (current == '[') {
            
            sb.append(current);
            next();
            AttributeSelector as = attribute();
            simpleSelector = as;
            parserListener.negationAttributeSelector(as);
            sb.append(as.getContext());
            sb.append(']');
        } else if (current == ':') {
            
            sb.append(current);
            next();
            if (end()) {
                throw new ParserException("Expected pseudo-element or pseudo-class at " + pos);
            }
            boolean doubleColon = false;
            if (current == ':') {
                doubleColon = true;
                sb.append(current);
                next();
            }
            String ident = !end() ? identifier() : null;
            if (ident == null || ident.isEmpty()) {
                throw new ParserException("Expected identifier at position " + pos);
            }
            if ("not".equalsIgnoreCase(ident) || isPseudoSpecialCase(ident) || doubleColon) {
                throw new ParserException("Expected pseudo-class (starting with ':', except ':not', ':first-line', ':first-letter', ':before' and ':after') at position " + pos);
            }
            PseudoSelector ps = pseudo(ident, PseudoType.PSEUDO_CLASS, doubleColon);
            simpleSelector = ps;
            parserListener.negationPseudoSelector(ps);
            sb.append(ps.getContext());
        } else {
            throw new ParserException("Selector expected at position " + pos);
        }

        ignoreWhitespaces();
        if (end() || current != ')') {
            throw new ParserException("Expected ')' at position " + pos);
        }
        
        next();

        return new NegationSelector(simpleSelector, new Context(content, sb.toString(), parenthesisPos, pos));

    }
protected NegationSelector negation ( int number ) throws ParserException { StringBuilder sb = new StringBuilder ( ) ; ignoreWhitespaces ( ) ; if ( end ( ) || current != ' ' ) { throw new ParserException ( "Expected '(' at position " + pos ) ; } //sb.append(current);
 int parenthesisPos = pos ; next ( ) ; ignoreWhitespaces ( ) ; if ( end ( ) ) { throw new ParserException ( "Selector expected at position " + pos ) ; } int initialPos = pos ; SimpleSelector simpleSelector = null ; if ( current == ' ' ) { //universal selector
 sb . append ( current ) ; TypeSelector ts = new TypeSelector ( "*" , new Context ( content , "*" , initialPos , pos + 1 ) ) ; parserListener . negationTypeSelector ( ts ) ; simpleSelector = ts ; next ( ) ; } else if ( Character . isLetter ( current ) ) { //type selector
 String type = identifier ( ) ; sb . append ( type ) ; TypeSelector ts = new TypeSelector ( type , new Context ( content , type , initialPos , pos ) ) ; parserListener . negationTypeSelector ( ts ) ; simpleSelector = ts ; } else if ( current == ' ' ) { //class selector
 sb . append ( current ) ; next ( ) ; String className = ! end ( ) ? identifier ( ) : null ; if ( className == null || className . isEmpty ( ) ) { throw new ParserException ( "Expected className at position " + pos ) ; } ClassSelector cs = new ClassSelector ( className , new Context ( content , "." + className , initialPos , pos ) ) ; simpleSelector = cs ; parserListener . negationClassSelector ( cs ) ; sb . append ( className ) ; } else if ( current == ' ' ) { //hash selector
 sb . append ( current ) ; next ( ) ; String id = ! end ( ) ? identifier ( ) : null ; if ( id == null || id . isEmpty ( ) ) { throw new ParserException ( "Expected id at position " + pos ) ; } HashSelector hs = new HashSelector ( id , new Context ( content , "#" + id , initialPos , pos ) ) ; simpleSelector = hs ; parserListener . negationIdSelector ( hs ) ; sb . append ( id ) ; } else if ( current == ' ' ) { //attribute selectors
 sb . append ( current ) ; next ( ) ; AttributeSelector as = attribute ( ) ; simpleSelector = as ; parserListener . negationAttributeSelector ( as ) ; sb . append ( as . getContext ( ) ) ; sb . append ( ' ' ) ; } else if ( current == ' ' ) { //pseudo-class only
 sb . append ( current ) ; next ( ) ; if ( end ( ) ) { throw new ParserException ( "Expected pseudo-element or pseudo-class at " + pos ) ; } boolean doubleColon = false ; if ( current == ' ' ) { doubleColon = true ; sb . append ( current ) ; next ( ) ; } String ident = ! end ( ) ? identifier ( ) : null ; if ( ident == null || ident . isEmpty ( ) ) { throw new ParserException ( "Expected identifier at position " + pos ) ; } if ( "not" . equalsIgnoreCase ( ident ) || isPseudoSpecialCase ( ident ) || doubleColon ) { throw new ParserException ( "Expected pseudo-class (starting with ':', except ':not', ':first-line', ':first-letter', ':before' and ':after') at position " + pos ) ; } PseudoSelector ps = pseudo ( ident , PseudoType . PSEUDO_CLASS , doubleColon ) ; simpleSelector = ps ; parserListener . negationPseudoSelector ( ps ) ; sb . append ( ps . getContext ( ) ) ; } else { throw new ParserException ( "Selector expected at position " + pos ) ; } ignoreWhitespaces ( ) ; if ( end ( ) || current != ' ' ) { throw new ParserException ( "Expected ')' at position " + pos ) ; } //sb.append(current);
 next ( ) ; return new NegationSelector ( simpleSelector , new Context ( content , sb . toString ( ) , parenthesisPos , pos ) ) ; }
negation
: NOT S* negation_arg S* ')'

negation_arg
: type_selector | universal | HASH | class | attrib | pseudo

TODO include "not" or not? It would be necessary to use parameters
negation : NOT S * negation_arg S * )