in src/main/java/net/starlark/java/syntax/Lexer.java [252:398]
private void escapedStringLiteral(char quot, boolean isRaw) {
int literalStartPos = isRaw ? pos - 2 : pos - 1;
boolean inTriplequote = skipTripleQuote(quot);
// more expensive second choice that expands escaped into a buffer
StringBuilder literal = new StringBuilder();
while (pos < buffer.length) {
char c = buffer[pos];
pos++;
switch (c) {
case '\n':
if (inTriplequote) {
literal.append(c);
break;
} else {
error("unclosed string literal", literalStartPos);
setToken(TokenKind.STRING, literalStartPos, pos);
setValue(literal.toString());
return;
}
case '\\':
if (pos == buffer.length) {
error("unclosed string literal", literalStartPos);
setToken(TokenKind.STRING, literalStartPos, pos);
setValue(literal.toString());
return;
}
if (isRaw) {
// Insert \ and the following character.
// As in Python, it means that a raw string can never end with a single \.
literal.append('\\');
if (peek(0) == '\r' && peek(1) == '\n') {
literal.append("\n");
pos += 2;
} else if (buffer[pos] == '\r' || buffer[pos] == '\n') {
literal.append("\n");
pos += 1;
} else {
literal.append(buffer[pos]);
pos += 1;
}
break;
}
c = buffer[pos];
pos++;
switch (c) {
case '\r':
if (peek(0) == '\n') {
pos += 1;
break;
} else {
break;
}
case '\n':
// ignore end of line character
break;
case 'a':
literal.append('\u0007');
break;
case 'b':
literal.append('\b');
break;
case 'f':
literal.append('\f');
break;
case 'n':
literal.append('\n');
break;
case 'r':
literal.append('\r');
break;
case 't':
literal.append('\t');
break;
case 'v':
literal.append('\u000b');
break;
case '\\':
literal.append('\\');
break;
case '\'':
literal.append('\'');
break;
case '"':
literal.append('"');
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
{ // octal escape
int octal = c - '0';
if (pos < buffer.length) {
c = buffer[pos];
if (c >= '0' && c <= '7') {
pos++;
octal = (octal << 3) | (c - '0');
if (pos < buffer.length) {
c = buffer[pos];
if (c >= '0' && c <= '7') {
pos++;
octal = (octal << 3) | (c - '0');
}
}
}
}
if (octal > 0xff) {
error("octal escape sequence out of range (maximum is \\377)", pos - 1);
}
literal.append((char) (octal & 0xff));
break;
}
case 'N':
case 'u':
case 'U':
default:
// unknown char escape => "\literal"
error("invalid escape sequence: \\" + c + ". Use '\\\\' to insert '\\'.", pos - 1);
literal.append('\\');
literal.append(c);
break;
}
break;
case '\'':
case '"':
if (c != quot || (inTriplequote && !skipTripleQuote(quot))) {
// Non-matching quote, treat it like a regular char.
literal.append(c);
} else {
// Matching close-delimiter, all done.
setToken(TokenKind.STRING, literalStartPos, pos);
setValue(literal.toString());
return;
}
break;
default:
literal.append(c);
break;
}
}
error("unclosed string literal", literalStartPos);
setToken(TokenKind.STRING, literalStartPos, pos);
setValue(literal.toString());
}