IElementType () { if (myStart + 1 >= myEnd) return StringEscapesTokenTypes.INVALID_CHARACTER_ESCAPE_TOKEN; // escape ends too early char nextChar = myBuffer.charAt(myStart + 1); mySeenEscapedSpacesOnly &= nextChar == ' '; if ((nextChar == '\n' || nextChar == ' ' && (mySeenEscapedSpacesOnly || isTrailingSpace(myStart + 2)))) { return StringEscapesTokenTypes.VALID_STRING_ESCAPE_TOKEN; // escaped EOL } if (nextChar == 'u' || nextChar == 'U') { if (isUnicodeMode()) { final int width = nextChar == 'u' ? 4 : 8; // is it uNNNN or Unnnnnnnn for (int i = myStart + 2; i < myStart + width + 2; i++) { if (i >= myEnd || !StringUtil.isHexDigit(myBuffer.charAt(i))) return StringEscapesTokenTypes.INVALID_UNICODE_ESCAPE_TOKEN; } return StringEscapesTokenTypes.VALID_STRING_ESCAPE_TOKEN; } else { return myOriginalLiteralToken; // b"\u1234" is just b"\\u1234", nothing gets escaped } } if (nextChar == 'x') { // \xNN is allowed both in bytes and unicode. for (int i = myStart + 2; i < myStart + 4; i++) { if (i >= myEnd || !StringUtil.isHexDigit(myBuffer.charAt(i))) return StringEscapesTokenTypes.INVALID_UNICODE_ESCAPE_TOKEN; } return StringEscapesTokenTypes.VALID_STRING_ESCAPE_TOKEN; } if (nextChar == 'N' && isUnicodeMode()) { int i = myStart + 2; if (i >= myEnd || myBuffer.charAt(i) != '{') return StringEscapesTokenTypes.INVALID_UNICODE_ESCAPE_TOKEN; i++; while (i < myEnd && myBuffer.charAt(i) != '}') i++; if (i >= myEnd) return StringEscapesTokenTypes.INVALID_UNICODE_ESCAPE_TOKEN; return StringEscapesTokenTypes.VALID_STRING_ESCAPE_TOKEN; } return switch (nextChar) { case 'a', 'b', 'f', 'n', 'r', 't', 'v', '\'', '\"', '\\', '0', '1', '2', '3', '4', '5', '6', '7' -> StringEscapesTokenTypes.VALID_STRING_ESCAPE_TOKEN; default -> // other unrecognized escapes are just part of string, not an error myOriginalLiteralToken; }; }