private Token ReadIdentifier(int firstChar)
{
// Process the first character.
var name = new StringBuilder();
if (firstChar == '\\')
{
// Unicode escape sequence.
if (ReadNextChar() != 'u')
throw new JavaScriptException(this.engine, ErrorType.SyntaxError, "Invalid escape sequence in identifier.", this.lineNumber, this.Source.Path);
firstChar = this.reader.Peek();
if (firstChar == '{')
{
// ECMAScript 6 extended unicode escape sequence.
string extendedCharacter = ReadExtendedUnicodeSequence();
if (extendedCharacter.Length == 1 && IsIdentifierChar(extendedCharacter[0]) == false)
throw new JavaScriptException(this.engine, ErrorType.SyntaxError, "Invalid character in identifier.", this.lineNumber, this.Source.Path);
name.Append(extendedCharacter);
}
else
{
firstChar = ReadHexEscapeSequence(4);
if (IsIdentifierChar(firstChar) == false)
throw new JavaScriptException(this.engine, ErrorType.SyntaxError, "Invalid character in identifier.", this.lineNumber, this.Source.Path);
name.Append((char)firstChar);
}
}
else
name.Append((char)firstChar);
// Read characters until we hit the first non-identifier character.
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 = this.reader.Peek();
if (c == '{')
{
// ECMAScript 6 extended unicode escape sequence.
string extendedCharacter = ReadExtendedUnicodeSequence();
if (extendedCharacter.Length == 1 && IsIdentifierChar(extendedCharacter[0]) == false)
throw new JavaScriptException(this.engine, ErrorType.SyntaxError, "Invalid character in identifier.", this.lineNumber, this.Source.Path);
name.Append(extendedCharacter);
}
else
{
c = ReadHexEscapeSequence(4);
if (IsIdentifierChar(c) == false)
throw new JavaScriptException(this.engine, ErrorType.SyntaxError, "Invalid character in identifier.", this.lineNumber, this.Source.Path);
name.Append((char)c);
}
}
else
{
// Add the character we peeked at to the identifier name.
name.Append((char)c);
// Advance the input stream.
ReadNextChar();
}
}
// Check if the identifier is actually a keyword, boolean literal, or null literal.
return KeywordToken.FromString(name.ToString(), this.engine.CompatibilityMode, this.StrictMode);
}