aboutsummaryrefslogtreecommitdiff
path: root/node_modules/meriyah/src/lexer/identifier.ts
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/meriyah/src/lexer/identifier.ts')
-rw-r--r--node_modules/meriyah/src/lexer/identifier.ts177
1 files changed, 177 insertions, 0 deletions
diff --git a/node_modules/meriyah/src/lexer/identifier.ts b/node_modules/meriyah/src/lexer/identifier.ts
new file mode 100644
index 0000000..ec8a7e4
--- /dev/null
+++ b/node_modules/meriyah/src/lexer/identifier.ts
@@ -0,0 +1,177 @@
+import { ParserState, Context } from '../common';
+import { Token, descKeywordTable } from '../token';
+import { Chars } from '../chars';
+import { advanceChar, consumeMultiUnitCodePoint, fromCodePoint, toHex } from './common';
+import { CharTypes, CharFlags, isIdentifierPart, isIdentifierStart, isIdPart } from './charClassifier';
+import { report, reportScannerError, Errors } from '../errors';
+
+/**
+ * Scans identifier
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function scanIdentifier(parser: ParserState, context: Context, isValidAsKeyword: 0 | 1): Token {
+ while (isIdPart[advanceChar(parser)]) {}
+ parser.tokenValue = parser.source.slice(parser.tokenPos, parser.index);
+
+ return parser.currentChar !== Chars.Backslash && parser.currentChar < 0x7e
+ ? descKeywordTable[parser.tokenValue] || Token.Identifier
+ : scanIdentifierSlowCase(parser, context, 0, isValidAsKeyword);
+}
+
+/**
+ * Scans unicode identifier
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ */
+export function scanUnicodeIdentifier(parser: ParserState, context: Context): Token {
+ const cookedChar = scanIdentifierUnicodeEscape(parser);
+ if (!isIdentifierPart(cookedChar)) report(parser, Errors.InvalidUnicodeEscapeSequence);
+ parser.tokenValue = fromCodePoint(cookedChar);
+ return scanIdentifierSlowCase(parser, context, /* hasEscape */ 1, CharTypes[cookedChar] & CharFlags.KeywordCandidate);
+}
+
+/**
+ * Scans identifier slow case
+ *
+ * @param parser Parser object
+ * @param context Context masks
+ * @param hasEscape True if contains a unicode sequence
+ * @param isValidAsKeyword
+ */
+export function scanIdentifierSlowCase(
+ parser: ParserState,
+ context: Context,
+ hasEscape: 0 | 1,
+ isValidAsKeyword: number
+): Token {
+ let start = parser.index;
+
+ while (parser.index < parser.end) {
+ if (parser.currentChar === Chars.Backslash) {
+ parser.tokenValue += parser.source.slice(start, parser.index);
+ hasEscape = 1;
+ const code = scanIdentifierUnicodeEscape(parser);
+ if (!isIdentifierPart(code)) report(parser, Errors.InvalidUnicodeEscapeSequence);
+ isValidAsKeyword = isValidAsKeyword && CharTypes[code] & CharFlags.KeywordCandidate;
+ parser.tokenValue += fromCodePoint(code);
+ start = parser.index;
+ } else if (isIdentifierPart(parser.currentChar) || consumeMultiUnitCodePoint(parser, parser.currentChar)) {
+ advanceChar(parser);
+ } else {
+ break;
+ }
+ }
+
+ if (parser.index <= parser.end) {
+ parser.tokenValue += parser.source.slice(start, parser.index);
+ }
+
+ const length = parser.tokenValue.length;
+
+ if (isValidAsKeyword && length >= 2 && length <= 11) {
+ const token: Token | undefined = descKeywordTable[parser.tokenValue];
+ if (token === void 0) return Token.Identifier;
+ if (!hasEscape) return token;
+
+ if (context & Context.Strict) {
+ return token === Token.AwaitKeyword && (context & (Context.Module | Context.InAwaitContext)) === 0
+ ? token
+ : token === Token.StaticKeyword
+ ? Token.EscapedFutureReserved
+ : (token & Token.FutureReserved) === Token.FutureReserved
+ ? Token.EscapedFutureReserved
+ : Token.EscapedReserved;
+ }
+ if (
+ context & Context.AllowEscapedKeyword &&
+ (context & Context.InGlobal) === 0 &&
+ (token & Token.Reserved) === Token.Reserved
+ )
+ return token;
+ if (token === Token.YieldKeyword) {
+ return context & Context.AllowEscapedKeyword
+ ? Token.AnyIdentifier
+ : context & Context.InYieldContext
+ ? Token.EscapedReserved
+ : token;
+ }
+
+ return token === Token.AsyncKeyword && context & Context.AllowEscapedKeyword
+ ? Token.AnyIdentifier
+ : (token & Token.FutureReserved) === Token.FutureReserved
+ ? token
+ : token === Token.AwaitKeyword && (context & Context.InAwaitContext) === 0
+ ? token
+ : Token.EscapedReserved;
+ }
+ return Token.Identifier;
+}
+
+/**
+ * Scans private name
+ *
+ * @param parser Parser object
+ */
+export function scanPrivateIdentifier(parser: ParserState): Token {
+ if (!isIdentifierStart(advanceChar(parser))) report(parser, Errors.MissingPrivateIdentifier);
+ return Token.PrivateField;
+}
+
+/**
+ * Scans unicode identifier
+ *
+ * @param parser Parser object
+ */
+export function scanIdentifierUnicodeEscape(parser: ParserState): number {
+ // Check for Unicode escape of the form '\uXXXX'
+ // and return code point value if valid Unicode escape is found.
+ if (parser.source.charCodeAt(parser.index + 1) !== Chars.LowerU) {
+ report(parser, Errors.InvalidUnicodeEscapeSequence);
+ }
+ parser.currentChar = parser.source.charCodeAt((parser.index += 2));
+ return scanUnicodeEscape(parser);
+}
+
+/**
+ * Scans unicode escape value
+ *
+ * @param parser Parser object
+ */
+export function scanUnicodeEscape(parser: ParserState): number {
+ // Accept both \uxxxx and \u{xxxxxx}
+ let codePoint = 0;
+ const char = parser.currentChar;
+ // First handle a delimited Unicode escape, e.g. \u{1F4A9}
+ if (char === Chars.LeftBrace) {
+ const begin = parser.index - 2;
+ while (CharTypes[advanceChar(parser)] & CharFlags.Hex) {
+ codePoint = (codePoint << 4) | toHex(parser.currentChar);
+ if (codePoint > Chars.NonBMPMax) reportScannerError(begin, parser.line, parser.index + 1, Errors.UnicodeOverflow);
+ }
+
+ // At least 4 characters have to be read
+ if ((parser.currentChar as number) !== Chars.RightBrace) {
+ reportScannerError(begin, parser.line, parser.index - 1, Errors.InvalidHexEscapeSequence);
+ }
+ advanceChar(parser); // consumes '}'
+ return codePoint;
+ }
+
+ if ((CharTypes[char] & CharFlags.Hex) === 0) report(parser, Errors.InvalidHexEscapeSequence); // first one is mandatory
+
+ const char2 = parser.source.charCodeAt(parser.index + 1);
+ if ((CharTypes[char2] & CharFlags.Hex) === 0) report(parser, Errors.InvalidHexEscapeSequence);
+ const char3 = parser.source.charCodeAt(parser.index + 2);
+ if ((CharTypes[char3] & CharFlags.Hex) === 0) report(parser, Errors.InvalidHexEscapeSequence);
+ const char4 = parser.source.charCodeAt(parser.index + 3);
+ if ((CharTypes[char4] & CharFlags.Hex) === 0) report(parser, Errors.InvalidHexEscapeSequence);
+
+ codePoint = (toHex(char) << 12) | (toHex(char2) << 8) | (toHex(char3) << 4) | toHex(char4);
+
+ parser.currentChar = parser.source.charCodeAt((parser.index += 4));
+
+ return codePoint;
+}