}
escaped = !escaped && ch2 == '\\';
}
if (!closed) {
throw new ParseException(
new Message(
MessageType.UNTERMINATED_STRING_TOKEN,
p.filePositionForOffsets(start, end)));
}
type = JsTokenType.STRING;
break;
}
case '/':
{
if (end == limit) {
type = JsTokenType.PUNCTUATION;
} else {
char ch2 = buf[end];
switch (ch2) {
case '/':
while (end < limit && !JsLexer.isJsLineSeparator(buf[end])) {
++end;
}
type = JsTokenType.COMMENT;
break;
case '*':
{
boolean star = false;
boolean closed = false;
while (++end < limit) {
ch2 = buf[end];
if (star && '/' == ch2) {
closed = true;
++end;
break;
} else {
star = (ch2 == '*') && !tokenBreak(end);
}
}
if (!closed) {
throw new ParseException(
new Message(MessageType.UNTERMINATED_STRING_TOKEN,
p.filePositionForOffsets(start, p.getOffset())));
}
type = JsTokenType.COMMENT;
}
break;
default:
{
if (lastNonCommentToken == null
|| JsLexer.isRegexp(lastNonCommentToken.text)) {
boolean closed = false;
boolean escaped = false;
boolean inCharSet = false;
regex_body:
do {
ch2 = buf[end];
if (JsLexer.isJsLineSeparator(ch2)) {
// will register as unterminated token below
break;
} else if (!escaped) {
switch (ch2) {
case '/':
if (!inCharSet) {
closed = true;
++end;
break regex_body;
}
break;
case '[':
inCharSet = true;
break;
case ']':
inCharSet = false;
break;
case '\\':
escaped = true;
break;
}
} else {
escaped = false;
}
++end;
} while (end < limit);
if (!closed) {
throw new ParseException(
new Message(MessageType.UNTERMINATED_STRING_TOKEN,
p.filePositionForOffsets(start, end)));
}
// Pick up any modifiers at the end, e.g. /foo/g
// Firefox fails on "/foo/instanceof RegExp" with an
// invalid identifiers error, so just pick up all letters