mirror of
https://github.com/apple/pkl.git
synced 2026-05-25 08:09:17 +02:00
SPICE-0028: Add support for multi-line string line continuations (#1507)
SPICE: https://github.com/apple/pkl-evolution/pull/31
This commit is contained in:
@@ -978,6 +978,8 @@ class GenericParserImpl {
|
||||
STRING_ESCAPE_RETURN,
|
||||
STRING_ESCAPE_UNICODE ->
|
||||
children.add(make(NodeType.STRING_ESCAPE, next().span));
|
||||
case STRING_ESCAPE_CONTINUATION ->
|
||||
throw parserError("invalidLineContinuationEscapeSequence");
|
||||
case INTERPOLATION_START -> {
|
||||
children.add(makeTerminal(next()));
|
||||
ff(children);
|
||||
@@ -1011,6 +1013,8 @@ class GenericParserImpl {
|
||||
}
|
||||
}
|
||||
case STRING_NEWLINE -> children.add(make(NodeType.STRING_NEWLINE, next().span));
|
||||
case STRING_ESCAPE_CONTINUATION ->
|
||||
children.add(make(NodeType.STRING_CONTINUATION, next().span));
|
||||
case STRING_ESCAPE_NEWLINE,
|
||||
STRING_ESCAPE_TAB,
|
||||
STRING_ESCAPE_QUOTE,
|
||||
@@ -1060,7 +1064,8 @@ class GenericParserImpl {
|
||||
throw parserError(ErrorMessages.create("stringIndentationMustMatchLastLine"), child.span);
|
||||
}
|
||||
}
|
||||
previousNewline = child.type == NodeType.STRING_NEWLINE;
|
||||
previousNewline =
|
||||
child.type == NodeType.STRING_NEWLINE || child.type == NodeType.STRING_CONTINUATION;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -460,6 +460,22 @@ public final class Lexer {
|
||||
yield Token.INTERPOLATION_START;
|
||||
}
|
||||
case 'u' -> lexUnicodeEscape();
|
||||
case '\n' -> Token.STRING_ESCAPE_CONTINUATION;
|
||||
case ' ', '\t' -> {
|
||||
var c = cursor;
|
||||
var next = nextChar();
|
||||
while (next == ' ' || next == '\t') next = nextChar();
|
||||
if (next == '\n')
|
||||
throw lexError(
|
||||
ErrorMessages.create("invalidLineContinuationEscapeSequenceWhitespace"),
|
||||
c - 2,
|
||||
cursor - c + 2);
|
||||
|
||||
throw lexError(
|
||||
ErrorMessages.create("invalidCharacterEscapeSequence", "\\" + (char) ch, "\\"),
|
||||
c - 2,
|
||||
2);
|
||||
}
|
||||
default ->
|
||||
throw lexError(
|
||||
ErrorMessages.create("invalidCharacterEscapeSequence", "\\" + (char) ch, "\\"),
|
||||
|
||||
@@ -1131,6 +1131,8 @@ final class ParserImpl {
|
||||
end = tk.span;
|
||||
builder.append(parseUnicodeEscape(tk));
|
||||
}
|
||||
case STRING_ESCAPE_CONTINUATION ->
|
||||
throw parserError("invalidLineContinuationEscapeSequence");
|
||||
case INTERPOLATION_START -> {
|
||||
var istart = next().span;
|
||||
if (!builder.isEmpty()) {
|
||||
@@ -1167,7 +1169,8 @@ final class ParserImpl {
|
||||
STRING_ESCAPE_QUOTE,
|
||||
STRING_ESCAPE_BACKSLASH,
|
||||
STRING_ESCAPE_RETURN,
|
||||
STRING_ESCAPE_UNICODE ->
|
||||
STRING_ESCAPE_UNICODE,
|
||||
STRING_ESCAPE_CONTINUATION ->
|
||||
stringTokens.add(new TempNode(next(), null));
|
||||
case INTERPOLATION_START -> {
|
||||
var istart = next();
|
||||
@@ -1236,6 +1239,7 @@ final class ParserImpl {
|
||||
builder.append('\n');
|
||||
isNewLine = true;
|
||||
}
|
||||
case STRING_ESCAPE_CONTINUATION -> isNewLine = true;
|
||||
case STRING_PART -> {
|
||||
var text = token.text(lexer);
|
||||
if (isNewLine) {
|
||||
@@ -1642,6 +1646,7 @@ final class ParserImpl {
|
||||
case STRING_ESCAPE_BACKSLASH -> "\\";
|
||||
case STRING_ESCAPE_TAB -> "\t";
|
||||
case STRING_ESCAPE_RETURN -> "\r";
|
||||
case STRING_ESCAPE_CONTINUATION -> "";
|
||||
case STRING_ESCAPE_UNICODE -> parseUnicodeEscape(tk);
|
||||
default -> throw new RuntimeException("Unreacheable code");
|
||||
};
|
||||
|
||||
@@ -129,6 +129,7 @@ public enum Token {
|
||||
STRING_ESCAPE_QUOTE,
|
||||
STRING_ESCAPE_BACKSLASH,
|
||||
STRING_ESCAPE_UNICODE,
|
||||
STRING_ESCAPE_CONTINUATION,
|
||||
STRING_END,
|
||||
STRING_PART;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* Copyright © 2025-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -70,6 +70,7 @@ public enum NodeType {
|
||||
STRING_CHARS,
|
||||
OPERATOR,
|
||||
STRING_NEWLINE,
|
||||
STRING_CONTINUATION,
|
||||
STRING_ESCAPE,
|
||||
|
||||
// members
|
||||
|
||||
@@ -44,13 +44,23 @@ The separator character (`_`) cannot follow `0x`, `0b`, `.`, `e`, or 'E' in a nu
|
||||
invalidCharacterEscapeSequence=\
|
||||
Invalid character escape sequence `{0}`.\n\
|
||||
\n\
|
||||
Valid character escape sequences are: {1}n {1}r {1}t {1}" {1}\\
|
||||
Valid character escape sequences are: {1}n {1}r {1}t {1}" {1}\\ {1}<newline>
|
||||
|
||||
invalidUnicodeEscapeSequence=\
|
||||
Invalid Unicode escape sequence `{0}`.\n\
|
||||
\n\
|
||||
Valid Unicode escape sequences are {1}'{'0'}' to {1}'{'10FFFF'}' (1-6 hexadecimal characters).
|
||||
|
||||
invalidLineContinuationEscapeSequence=\
|
||||
Invalid line continuation escape sequence.\n\
|
||||
\n\
|
||||
Line continuations are only allowed in multi-line strings.
|
||||
|
||||
invalidLineContinuationEscapeSequenceWhitespace=\
|
||||
Invalid line continuation escape sequence.\n\
|
||||
\n\
|
||||
Whitespace between the continuation escape and following newline is not allowed.
|
||||
|
||||
missingDelimiter=\
|
||||
Missing `{0}` delimiter.
|
||||
|
||||
|
||||
@@ -197,6 +197,7 @@ class GenericSexpRenderer(code: String) {
|
||||
NodeType.TERMINAL,
|
||||
NodeType.OPERATOR,
|
||||
NodeType.STRING_NEWLINE,
|
||||
NodeType.STRING_CONTINUATION,
|
||||
)
|
||||
|
||||
private val UNPACK_CHILDREN =
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright © 2024-2025 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
* Copyright © 2024-2026 Apple Inc. and the Pkl project authors. All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -97,6 +97,7 @@ class ParserComparisonTest {
|
||||
"errors/parser18.pkl",
|
||||
"errors/nested1.pkl",
|
||||
"errors/invalidCharacterEscape.pkl",
|
||||
"errors/invalidCharacterEscape2.pkl",
|
||||
"errors/invalidUnicodeEscape.pkl",
|
||||
"errors/unterminatedUnicodeEscape.pkl",
|
||||
"errors/keywordNotAllowedHere1.pkl",
|
||||
|
||||
Reference in New Issue
Block a user