int initialPos = pos;
if (current == '*') {
//universal selector
sb.append(current);
hasSimpleSelector = true;
TypeSelector ts = new TypeSelector("*", new Context(content, "*", initialPos, pos));
parserListener.typeSelector(ts);
simpleSelectorList.add(ts);
next();
} else if (Character.isLetter(current)) {
//type selector
String type = identifier();
sb.append(type);
hasSimpleSelector = true;
TypeSelector ts = new TypeSelector(type, new Context(content, type, initialPos, pos));
parserListener.typeSelector(ts);
simpleSelectorList.add(ts);
}
int selectorCount = 0;
boolean hasPseudoElement = false;
while (!end()) {
int initialLoopPos = pos;
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);
}
sb.append(className);
ClassSelector cs = new ClassSelector(className, new Context(content, "." + className, initialLoopPos, pos));
simpleSelectorList.add(cs);
parserListener.classSelector(cs);
} 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, initialLoopPos, pos));
simpleSelectorList.add(hs);
parserListener.idSelector(hs);
sb.append(id);
} else if (current == '[') {
//attribute selectors
sb.append(current);
next();
AttributeSelector as = attribute();
simpleSelectorList.add(as);
parserListener.attributeSelector(as);
sb.append(as);
sb.append(']');
} else if (current == ':') {
//pseudo-element, pseudo-class or negation
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);
}
boolean special = isPseudoSpecialCase(ident);
if (special || doubleColon) {
//pseudo-element (double colon or special cases)
//allow just one
if (hasPseudoElement) {
throw new ParserException("Only one pseudo-element is allowed for each simple selector and a second one was found at position " + pos);
}
PseudoSelector ps = pseudo(ident, PseudoType.PseudoElement, doubleColon);
simpleSelectorList.add(ps);
parserListener.pseudoSelector(ps);
sb.append(ps);
hasPseudoElement = true;
} else if ("not".equalsIgnoreCase(ident)) {
//negation
NegationSelector n = negation(selectorCount);
simpleSelectorList.add(n);
sb.append(ident);
sb.append(n);
} else {
//pseudo-class
PseudoSelector ps = pseudo(ident, PseudoType.PseudoClass, false);
simpleSelectorList.add(ps);
parserListener.pseudoSelector(ps);
sb.append(ps);
}
} else {
break;
}
selectorCount++;
}
if (!hasSimpleSelector && selectorCount == 0) {
throw new ParserException("No real selector found at position " + pos);
}
return new SimpleSelectorSequence(simpleSelectorList, new Context(content, sb.toString(), initialPos, pos));
}