private Token ReadRegularExpression()
{
// The first slash has already been read.
// Read the regular expression body.
var body = new StringBuilder();
bool insideCharacterClass = false;
while (true)
{
// Read the next character.
int c = ReadNextChar();
// Check for special cases.
if (c == '/' && insideCharacterClass == false)
break;
else if (c == '\\')
{
// Escape sequence. Escaped characters are never special.
body.Append((char)c);
c = ReadNextChar();
}
else if (c == '[')
insideCharacterClass = true;
else if (c == ']')
insideCharacterClass = false;
// Note: a line terminator or EOF is not allowed in a regular expression, even if
// it is escaped with a backslash. Therefore, these checks have to come after the
// checks above.
if (IsLineTerminator(c))
throw new JavaScriptException(this.engine, ErrorType.SyntaxError, "Unexpected line terminator in regular expression literal.", this.lineNumber, this.Source.Path);
else if (c == -1)
throw new JavaScriptException(this.engine, ErrorType.SyntaxError, "Unexpected end of input in regular expression literal.", this.lineNumber, this.Source.Path);
// Append the character to the regular expression.
body.Append((char)c);
}
// Read the flags.
var flags = new StringBuilder(3);
while (true)
{
int c = this.reader.Peek();
if (IsIdentifierChar(c) == false || c == -1)
break;
if (c == '\\')
{
// Unicode escape sequence.
ReadNextChar();
if (ReadNextChar() != 'u')
throw new JavaScriptException(this.engine, ErrorType.SyntaxError, "Invalid escape sequence in identifier.", this.lineNumber, this.Source.Path);
c = ReadHexEscapeSequence(4);
if (IsIdentifierChar(c) == false)
throw new JavaScriptException(this.engine, ErrorType.SyntaxError, "Invalid character in identifier.", this.lineNumber, this.Source.Path);
flags.Append((char)c);
}
else
{
// Add the character we peeked at to the flags.
flags.Append((char)c);
// Advance the input stream.
ReadNextChar();
}
}
// Create a new literal token.
return new LiteralToken(new RegularExpressionLiteral(body.ToString(), flags.ToString()));
}