break;
}
++end;
} while (state != 3);
if (state != 3) {
throw new ParseException(new Message(
MessageType.UNTERMINATED_COMMENT_TOKEN,
cp.filePositionForOffsets(start, end)));
}
type = CssTokenType.COMMENT;
} else if (end < limit && buf[end] == '/') {
do {
if (++end == limit) { break; }
ch = buf[end];
// Line comment does not contain the newline character that ends it
// since we don't want to break \r\n sequences across two tokens,
// and for consistency with JavaScript conventions which exclude the
// newline from the line comment token.
if (ch == '\r' || ch == '\n') { break; }
} while (true);
type = CssTokenType.COMMENT;
FilePosition commentPos = cp.filePositionForOffsets(start, end);
mq.addMessage(MessageType.INVALID_CSS_COMMENT, commentPos);
} else {
// *yytext
type = CssTokenType.PUNCTUATION;
}
} else if (end < limit && '=' == buf[end] &&
('~' == ch || '|' == ch || '^' == ch || '$' == ch || '*' == ch)) {
// "~=" INCLUDES
// "|=" DASHMATCH
// "^=" HEADMATCH
// "$=" TAILMATCH
// "*=" SUBSTRINGMATCH
++end;
type = CssTokenType.PUNCTUATION;
} else if (ch == '\'' || ch == '"') {
end = parseString(cp, start);
type = CssTokenType.STRING;
} else if (ch == '@') {
identEnd = parseIdent(cp, end);
if (identEnd != -1) {
// "@import" IMPORT_SYM
// "@page" PAGE_SYM
// "@media" MEDIA_SYM
// "@font-face" FONT_FACE_SYM
// "@charset " CHARSET_SYM
// "@"{ident} ATKEYWORD
type = CssTokenType.SYMBOL;
end = identEnd;
// In http://www.w3.org/TR/CSS21/grammar.html, the CHARSET_SYM is
// allowed to match only "@charset "
if ((end - start) == 8 && parseMatch(cp, start, "@charset ") > 0) {
++end;
}
} else {
// . *yytext
type = CssTokenType.PUNCTUATION;
}
} else if (ch == '!') {
// "!{w}important" IMPORTANT_SYM
// handled by token joining at a later pass
// . *yytext
type = CssTokenType.PUNCTUATION;
} else if (ch == '#') {
int nameEnd = parseName(cp, end);
if (nameEnd >= 0) {
// "#"{name} HASH
type = CssTokenType.HASH;
end = nameEnd;
} else {
// . *yytext
type = CssTokenType.PUNCTUATION;
}
} else if (ch == '<' || ch == '-') {
// "<!--" CDO
// "-->" CDC
int tailEnd = parseMatch(cp, end, ch == '<' ? "!--" : "->");
if (tailEnd >= 0) { end = tailEnd; }
type = CssTokenType.PUNCTUATION;
} else if ((ch >= '0' && ch <= '9') || '.' == ch) {
// {num}em EMS
// {num}ex EXS
// {num}px LENGTH
// {num}cm LENGTH
// {num}mm LENGTH
// {num}in LENGTH
// {num}pt LENGTH
// {num}pc LENGTH
// {num}deg ANGLE
// {num}rad ANGLE
// {num}grad ANGLE
// {num}ms TIME
// {num}s TIME
// {num}Hz FREQ
// {num}kHz FREQ
// {num}{ident} DIMEN
// {num}% PERCENTAGE
// {num} NUMBER
boolean isNum;
if ('.' == ch) {
int numEnd = parseInt(cp, end);
isNum = numEnd >= 0;
if (isNum) { end = numEnd; }
} else {
isNum = true;
end = parseNum(cp, start);
}
if (isNum) {
identEnd = parseIdent(cp, end);
if (identEnd >= 0) {
end = identEnd;
} else if (end < limit && '%' == buf[end]) {
++end;
}
type = CssTokenType.QUANTITY;
} else {
// lone .
// . *yytext
type = CssTokenType.PUNCTUATION;
}
} else if ((identEnd = parseIdent(cp, start)) >= 0) {
end = identEnd;
if (end - start == 1 && 'U' == ch && end < limit && '+' == buf[end]) {
// U\+{range} UNICODERANGE
// U\+{h}{1,6}-{h}{1,6} UNICODERANGE
// range \?{1,6}|{h}(\?{0,5}|{h}(\?{0,4}|{h}\
// (\?{0,3}|{h}(\?{0,2}|{h}(\??|{h})))))
type = CssTokenType.UNICODE_RANGE;
++end;
end = parseRange(cp, end);
} else if (end < limit && '(' == buf[end]) {
++end;
if (end - start == 4 && parseMatch(cp, start, "url(") >= 0) {
// "url("{w}{string}{w}")" URI
// "url("{w}{url}{w}")" URI
end = parseWhitespace(buf, end, limit);
int stringEnd = parseString(cp, end);
int uriEnd = stringEnd < 0 ? parseUri(cp, end) : -1;
if (stringEnd < 0 && uriEnd < 0) {
throw new ParseException(new Message(
MessageType.EXPECTED_TOKEN,
cp.filePositionForOffsets(end, end),
MessagePart.Factory.valueOf("{url}"), toMessagePart(cp, end)));
}
end = stringEnd >= 0 ? stringEnd : uriEnd;
end = parseWhitespace(buf, end, limit);
if (end == limit || ')' != buf[end]) {
throw new ParseException(new Message(
MessageType.EXPECTED_TOKEN,
cp.filePositionForOffsets(end, end),
MessagePart.Factory.valueOf(")"), toMessagePart(cp, end)));
}
++end;
type = CssTokenType.URI;
} else {
// {ident}"(" FUNCTION
type = CssTokenType.FUNCTION;
}
} else {
// {ident} IDENT
type = CssTokenType.IDENT;
}
} else if (ch == '$' && allowSubstitutions) {
// ${<javascript tokens>}
if (end < limit && buf[end] != '{') {
type = CssTokenType.PUNCTUATION;
} else {
// 0 - non string
// 1 - quoted string
// 2 - saw \ in string
// 3 - saw close paren
int state = 0;
// number of parenthetical blocks entered and not exited
int nOpen = 0;
char delim = 0;
do {
if (end == limit) { break; }
ch = buf[end];
switch (state) {
case 0:
if (ch == '"' || ch == '\'') {
delim = ch;
state = 1;
} else if (ch == '{') {
++nOpen;
} else if (ch == '}') {
if (--nOpen == 0) {
state = 3;
}
}
break;
case 1:
if (ch == delim) {
state = 0;
} else if (ch == '\\') {
state = 2;
}
break;
case 2:
state = 1;
break;
}
++end;
} while (state != 3);
if (state != 3) {
throw new ParseException(new Message(
MessageType.UNTERMINATED_STRING_TOKEN,
cp.filePositionForOffsets(start, end)));
}
identEnd = parseIdent(cp, end);