mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
PY-59594 PEP 701: Allow quote-reuse and line breaks inside f-strings. Keep reporting these problems for Python <3.12.
PEP 498 required f-strings to be recognizable by existing tooling, such as syntax highlighters,
by prohibiting re-using quotes of the same kind and having line breaks inside expression fragments.
We used to detect these problems already at the lexer level, correctly replacing violating quotes
with FSTRING_END token, and appending STATEMENT_BREAK tokens to illegal line breaks inside expressions,
depending on the lexer's state. Now, thanks to a general f-string grammar in PEP 701, most of this
bookkeeping could be moved from the lexer to the CompatibilityVisitor (to still be reported
for previous versions of the language and by the compatibility inspection).
Previously forbidden backslashes and line comments are now also detected by the CompatibilityVisitor
instead of the version-agnostic FStringAnnotator.
One side effect of the new grammar is that parser recovery in pre-3.12 version of Python became
slightly worse. For instance, something like `f'{foo'` used to be recognized as an f-string
with an incomplete fragment lacking its closing brace. Now, it's parsed as an incomplete
f-string, lacking its own closing quote, containing an incomplete string literal inside
an incomplete fragment. What's more, parsing of this fragment's expression doesn't terminate
until the end of a file, because STATEMENT_BREAK is never produced by PythonIndentingProcessor
while it's inside an f-string fragment, and every quote is considered a new string literal.
Examples of parsing tests affected by this are:
PythonParsingTest.testFStringFragmentIncompleteTypeConversionBeforeClosingQuote
PythonParsingTest.testFStringIncompleteFragmentWithTypeConversion
PythonParsingTest.testFStringIncompleteFragment
I also had to simplify some scenarios from PythonHighlightingTest, removing snippets
with incomplete fragments or moving such examples to the very end of a file.
It's not clear how to handle these situations not overcomplicating the lexer.
(cherry picked from commit 03ba6d7fba1b45a84aa92221e6a452645a765205)
IJ-MR-115763
GitOrigin-RevId: cd36470d9cae353fe3caeb2d3b628d8743b46cbb
This commit is contained in:
committed by
intellij-monorepo-bot
parent
4671fe0c7c
commit
37d25ee815
@@ -142,12 +142,9 @@ ANN.variable.annotation.cannot.be.combined.with.tuple.unpacking=A variable annot
|
||||
ANN.variable.annotation.cannot.be.used.in.assignment.with.multiple.targets=A variable annotation cannot be used in assignment with multiple targets
|
||||
ANN.generator.expression.must.be.parenthesized.if.not.sole.argument=Generator expression must be parenthesized if not sole argument
|
||||
|
||||
ANN.fstrings.expression.fragment.inside.fstring.nested.too.deeply=Expression fragment inside an f-string is nested too deeply
|
||||
ANN.fstrings.missing.conversion.character=A conversion character is expected: should be one of 's', 'r', 'a'
|
||||
ANN.fstrings.illegal.conversion.character=An illegal conversion character ''{0}'': should be one of ''s'', ''r'', ''a''
|
||||
ANN.fstrings.expression.fragments.cannot.include.backslashes=Expression fragments inside f-strings cannot include backslashes
|
||||
ANN.fstrings.single.right.brace.not.allowed.inside.fstrings=A single '}' is not allowed inside f-strings
|
||||
ANN.fstrings.expression.fragments.cannot.include.line.comments=Expression fragments inside f-strings cannot include line comments
|
||||
|
||||
ANN.patterns.single.star.pattern.cannot.be.used.outside.sequence.patterns=Single star pattern cannot be used outside sequence patterns
|
||||
ANN.patterns.double.star.pattern.cannot.be.used.outside.mapping.patterns=Double star pattern cannot be used outside mapping patterns
|
||||
@@ -813,6 +810,11 @@ INSP.compatibility.feature.support.raise.with.no.arguments.outside.except.block=
|
||||
INSP.compatibility.feature.support.backquotes=support backquotes, use repr() instead
|
||||
INSP.compatibility.feature.support.print.statement=support this syntax. The print statement has been replaced with a print() function
|
||||
INSP.compatibility.feature.support.super.without.arguments=support this syntax. super() should have arguments in Python 2
|
||||
INSP.compatibility.feature.allow.quote.reuse.in.f-strings=allow nesting of string literals with the same quote type inside f-strings
|
||||
INSP.compatibility.feature.allow.new.lines.in.f-strings=allow new lines in expression parts of non-triple-quoted f-strings
|
||||
INSP.compatibility.feature.allow.deep.expression.nesting.in.f-strings=allow nesting expressions in format specifiers this deep
|
||||
INSP.compatibility.feature.allow.backslashes.in.f-strings=allow backslashes inside expression parts of f-strings
|
||||
INSP.compatibility.feature.line.comments.in.f-strings=allow comments inside expression parts of f-strings
|
||||
INSP.compatibility.py35.does.not.support.yield.inside.async.functions=Python version 3.5 does not support 'yield' inside async functions
|
||||
INSP.compatibility.feature.support.yield.from=support this syntax. Delegating to a subgenerator is available since Python 3.3; use explicit iteration over subgenerator instead.
|
||||
INSP.compatibility.pre35.versions.do.not.allow.return.with.argument.inside.generator=Python versions < 3.3 do not allow 'return' with argument inside generator.
|
||||
|
||||
@@ -14,11 +14,7 @@ class PyLexerFStringHelper(private val myLexer: FlexLexerEx) {
|
||||
|
||||
fun handleFStringStartInFragment(): IElementType {
|
||||
val prefixAndQuotes = myLexer.yytext().toString()
|
||||
val (_, offset) = findFStringTerminator(prefixAndQuotes)
|
||||
if (offset == prefixAndQuotes.length) {
|
||||
return pushFString(prefixAndQuotes)
|
||||
}
|
||||
return PyTokenTypes.IDENTIFIER
|
||||
return pushFString(prefixAndQuotes)
|
||||
}
|
||||
|
||||
fun handleFStringStart(): IElementType {
|
||||
@@ -90,9 +86,6 @@ class PyLexerFStringHelper(private val myLexer: FlexLexerEx) {
|
||||
}
|
||||
|
||||
fun handleLineBreakInFragment(): IElementType {
|
||||
val text = myLexer.yytext().toString()
|
||||
// We will return a line break anyway, but we need to transit from FSTRING state of the lexer
|
||||
findFStringTerminator(text)
|
||||
return PyTokenTypes.LINE_BREAK
|
||||
}
|
||||
|
||||
@@ -106,15 +99,7 @@ class PyLexerFStringHelper(private val myLexer: FlexLexerEx) {
|
||||
}
|
||||
|
||||
fun handleStringLiteral(stringLiteralType: IElementType): IElementType {
|
||||
val stringText = myLexer.yytext().toString()
|
||||
val prefixLength = PyStringLiteralUtil.getPrefixLength(stringText)
|
||||
|
||||
val (type, offset) = findFStringTerminator(stringText)
|
||||
return when (offset) {
|
||||
0 -> type!!
|
||||
prefixLength -> PyTokenTypes.IDENTIFIER
|
||||
else -> stringLiteralType
|
||||
}
|
||||
return stringLiteralType
|
||||
}
|
||||
|
||||
private fun findFStringTerminator(text: String): Pair<IElementType?, Int> {
|
||||
@@ -126,8 +111,8 @@ class PyLexerFStringHelper(private val myLexer: FlexLexerEx) {
|
||||
continue
|
||||
}
|
||||
if (c == '\n') {
|
||||
val insideSingleQuoted = myFStringStates.any { it.openingQuotes.length == 1 }
|
||||
if (insideSingleQuoted) {
|
||||
val topmostFStringIsSingleQuoted = myFStringStates.peek().openingQuotes.length == 1
|
||||
if (topmostFStringIsSingleQuoted) {
|
||||
if (i == 0) {
|
||||
// Terminate all f-strings and insert STATEMENT_BREAK at this point
|
||||
dropFStringStateWithAllNested(0)
|
||||
@@ -138,13 +123,13 @@ class PyLexerFStringHelper(private val myLexer: FlexLexerEx) {
|
||||
}
|
||||
else {
|
||||
val nextThree = text.substring(i, min(text.length, i + 3))
|
||||
val lastWithMatchingQuotesIndex = myFStringStates.indexOfLast { nextThree.startsWith(it.openingQuotes) }
|
||||
if (lastWithMatchingQuotesIndex >= 0) {
|
||||
val state = myFStringStates[lastWithMatchingQuotesIndex]
|
||||
val topmostFStringState = myFStringStates.peek()
|
||||
val closesTopmostFStringQuotes = nextThree.startsWith(topmostFStringState.openingQuotes)
|
||||
if (closesTopmostFStringQuotes) {
|
||||
if (i == 0) {
|
||||
dropFStringStateWithAllNested(lastWithMatchingQuotesIndex)
|
||||
dropFStringStateWithAllNested(myFStringStates.size - 1)
|
||||
}
|
||||
pushBackToOrConsumeMatch(i, state.openingQuotes.length)
|
||||
pushBackToOrConsumeMatch(i, topmostFStringState.openingQuotes.length)
|
||||
return Pair(PyTokenTypes.FSTRING_END, i)
|
||||
}
|
||||
}
|
||||
|
||||
+40
-12
@@ -20,7 +20,6 @@ import com.intellij.lexer.FlexLexer;
|
||||
import com.intellij.lexer.MergingLexerAdapter;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.containers.Stack;
|
||||
import com.jetbrains.python.PyTokenTypes;
|
||||
import com.jetbrains.python.PythonDialectsTokenSetProvider;
|
||||
@@ -44,7 +43,7 @@ public class PythonIndentingProcessor extends MergingLexerAdapter {
|
||||
private int myLineBreakBeforeFirstCommentIndex = -1;
|
||||
protected boolean myProcessSpecialTokensPending = false;
|
||||
|
||||
private final Stack<String> myFStringStack = new Stack<>();
|
||||
private final Stack<FString> myFStringStack = new Stack<>();
|
||||
|
||||
private static final boolean DUMP_TOKENS = false;
|
||||
private final TokenSet RECOVERY_TOKENS = PythonDialectsTokenSetProvider.getInstance().getUnbalancedBracesRecoveryTokens();
|
||||
@@ -200,16 +199,33 @@ public class PythonIndentingProcessor extends MergingLexerAdapter {
|
||||
final int prefixLength = PyStringLiteralUtil.getPrefixLength(tokenText);
|
||||
final String openingQuotes = tokenText.substring(prefixLength);
|
||||
assert !openingQuotes.isEmpty();
|
||||
myFStringStack.push(openingQuotes);
|
||||
myFStringStack.push(new FString(openingQuotes, new Stack<>()));
|
||||
}
|
||||
else if (isBaseAt(PyTokenTypes.FSTRING_END)) {
|
||||
while (!myFStringStack.isEmpty()) {
|
||||
final String lastOpeningQuotes = myFStringStack.pop();
|
||||
if (lastOpeningQuotes.equals(tokenText)) {
|
||||
final FString lastFString = myFStringStack.pop();
|
||||
if (lastFString.quotes.equals(tokenText)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (isBaseAt(PyTokenTypes.FSTRING_FRAGMENT_START)) {
|
||||
assert !myFStringStack.isEmpty();
|
||||
myFStringStack.peek().fragments.push(FStringFragmentPart.EXPRESSION);
|
||||
}
|
||||
else if (isBaseAt(PyTokenTypes.FSTRING_FRAGMENT_END)) {
|
||||
assert !myFStringStack.isEmpty();
|
||||
FString topmostFString = myFStringStack.peek();
|
||||
assert !topmostFString.fragments.isEmpty();
|
||||
topmostFString.fragments.pop();
|
||||
}
|
||||
else if (isBaseAt(PyTokenTypes.FSTRING_FRAGMENT_FORMAT_START) || isBaseAt(PyTokenTypes.FSTRING_FRAGMENT_TYPE_CONVERSION)) {
|
||||
assert !myFStringStack.isEmpty();
|
||||
FString topmostFString = myFStringStack.peek();
|
||||
assert !topmostFString.fragments.isEmpty();
|
||||
topmostFString.fragments.pop();
|
||||
topmostFString.fragments.push(FStringFragmentPart.TYPE_CONVERSION_OR_FORMAT);
|
||||
}
|
||||
}
|
||||
|
||||
protected void pushToken(IElementType type, int start, int end) {
|
||||
@@ -343,14 +359,9 @@ public class PythonIndentingProcessor extends MergingLexerAdapter {
|
||||
}
|
||||
|
||||
protected void processLineBreak(int startPos) {
|
||||
// See https://www.python.org/dev/peps/pep-0498/#expression-evaluation
|
||||
final boolean allFStringsAreTripleQuoted = ContainerUtil.and(myFStringStack, quotes -> quotes.length() == 3);
|
||||
final boolean insideImplicitFragmentParentheses = !myFStringStack.isEmpty() && allFStringsAreTripleQuoted;
|
||||
final boolean shouldTerminateFStrings = !myFStringStack.isEmpty() && !allFStringsAreTripleQuoted;
|
||||
if ((myBraceLevel == 0 && !insideImplicitFragmentParentheses) || shouldTerminateFStrings) {
|
||||
if (myLineHasSignificantTokens || shouldTerminateFStrings) {
|
||||
if (myBraceLevel == 0 && isOutsideFStringOrInsideItsLineBreakSensitiveTextPart()) {
|
||||
if (myLineHasSignificantTokens) {
|
||||
pushToken(PyTokenTypes.STATEMENT_BREAK, startPos, startPos);
|
||||
myFStringStack.clear();
|
||||
}
|
||||
myLineHasSignificantTokens = false;
|
||||
advanceBase();
|
||||
@@ -361,6 +372,14 @@ public class PythonIndentingProcessor extends MergingLexerAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isOutsideFStringOrInsideItsLineBreakSensitiveTextPart() {
|
||||
if (myFStringStack.isEmpty()) return true;
|
||||
FString topmostFString = myFStringStack.peek();
|
||||
// In triple-quoted f-strings one can put line breaks in any plain-text part
|
||||
if (topmostFString.quotes.length() != 1) return false;
|
||||
return topmostFString.fragments.isEmpty() || topmostFString.fragments.peek() == FStringFragmentPart.TYPE_CONVERSION_OR_FORMAT;
|
||||
}
|
||||
|
||||
protected void processInsignificantLineBreak(int startPos,
|
||||
boolean breakStatementOnLineBreak) {
|
||||
// merge whitespace following the line break character into the
|
||||
@@ -485,4 +504,13 @@ public class PythonIndentingProcessor extends MergingLexerAdapter {
|
||||
protected IElementType getCommentTokenType() {
|
||||
return PyTokenTypes.END_OF_LINE_COMMENT;
|
||||
}
|
||||
|
||||
private record FString(@NotNull String quotes, @NotNull Stack<FStringFragmentPart> fragments) {
|
||||
}
|
||||
|
||||
private enum FStringFragmentPart {
|
||||
EXPRESSION,
|
||||
TYPE_CONVERSION_OR_FORMAT,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+82
-5
@@ -12,10 +12,7 @@ import com.intellij.openapi.util.NlsSafe;
|
||||
import com.intellij.openapi.util.Ref;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiErrorElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiWhiteSpace;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import com.intellij.psi.tree.TokenSet;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
@@ -709,7 +706,87 @@ public abstract class CompatibilityVisitor extends PyAnnotator {
|
||||
final ASTNode equalitySignInFStringFragment = node.getNode().findChildByType(PyTokenTypes.EQ);
|
||||
if (equalitySignInFStringFragment != null) {
|
||||
registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON38) && registerForLanguageLevel(level),
|
||||
PyPsiBundle.message("INSP.compatibility.support.equality.signs.in.fstrings"), equalitySignInFStringFragment.getPsi());
|
||||
PyPsiBundle.message("INSP.compatibility.support.equality.signs.in.fstrings"),
|
||||
equalitySignInFStringFragment.getPsi());
|
||||
}
|
||||
|
||||
List<PyFStringFragment> containingFragmentsOfSameFString =
|
||||
PsiTreeUtil.collectParents(node, PyFStringFragment.class, false, o -> o instanceof PyStringLiteralExpression);
|
||||
|
||||
if (containingFragmentsOfSameFString.size() > 1) {
|
||||
// At the moment, there is a limit of 2 for CPython 3.12, but it's implementation-dependent.
|
||||
// See https://peps.python.org/pep-0701/#specification
|
||||
registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON312) && registerForLanguageLevel(level),
|
||||
PyPsiBundle.message("INSP.compatibility.feature.allow.deep.expression.nesting.in.f-strings"), node);
|
||||
}
|
||||
|
||||
boolean isTopmostFragment = PsiTreeUtil.getParentOfType(node, PyFStringFragment.class, true) == null;
|
||||
if (isTopmostFragment) {
|
||||
List<PyFStringFragment> fragments = new ArrayList<>();
|
||||
fragments.add(node);
|
||||
PyFStringFragmentFormatPart formatPart = node.getFormatPart();
|
||||
if (formatPart != null) {
|
||||
fragments.addAll(formatPart.getFragments());
|
||||
}
|
||||
for (PyFStringFragment fragment : fragments) {
|
||||
String wholeNodeText = fragment.getText();
|
||||
TextRange range = fragment.getExpressionContentRange();
|
||||
for (int i = range.getStartOffset(); i < range.getEndOffset(); i++) {
|
||||
if (wholeNodeText.charAt(i) == '\\') {
|
||||
TextRange backslashRange = TextRange.from(i, 1).shiftRight(fragment.getTextRange().getStartOffset());
|
||||
registerForAllMatchingVersions(
|
||||
level -> level.isOlderThan(LanguageLevel.PYTHON312) && registerForLanguageLevel(level),
|
||||
PyPsiBundle.message("INSP.compatibility.feature.allow.backslashes.in.f-strings"),
|
||||
node, backslashRange, true
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
List<PyFormattedStringElement> containingFStrings =
|
||||
PsiTreeUtil.collectParents(node, PyFormattedStringElement.class, false, e -> e instanceof PyStatement);
|
||||
assert !containingFStrings.isEmpty();
|
||||
PyFormattedStringElement parentFString = containingFStrings.get(0);
|
||||
List<PyFormattedStringElement> remainingEnclosingFStrings = ContainerUtil.subList(containingFStrings, 1);
|
||||
// Report only on fragments of the topmost single-quoted f-string to avoid duplicates
|
||||
// in cases like: f'{f'{1<BR>
|
||||
// + 1}'}'
|
||||
boolean isFragmentOfTopmostSingleQuotedFString = !parentFString.isTripleQuoted() &&
|
||||
ContainerUtil.all(remainingEnclosingFStrings, PyStringElement::isTripleQuoted);
|
||||
if (isFragmentOfTopmostSingleQuotedFString && node.textContains('\n')) {
|
||||
int lineBreakOffset = node.getText().indexOf('\n');
|
||||
if (node.getExpressionContentRange().contains(lineBreakOffset)) {
|
||||
PsiElement multiLineLeaf = node.findElementAt(lineBreakOffset);
|
||||
assert multiLineLeaf != null;
|
||||
registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON312) && registerForLanguageLevel(level),
|
||||
PyPsiBundle.message("INSP.compatibility.feature.allow.new.lines.in.f-strings"), multiLineLeaf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String parentFStringQuote = parentFString.getQuote();
|
||||
// Report only on fragments of the topmost f-string with this quote type to avoid duplicates in cases like: f'{f'{f"'"}'}'
|
||||
boolean isFragmentOfTopmostFStringWithSuchQuotes = ContainerUtil.all(remainingEnclosingFStrings,
|
||||
fString -> !fString.getQuote().equals(parentFStringQuote));
|
||||
if (isFragmentOfTopmostFStringWithSuchQuotes) {
|
||||
int illegalQuoteOffset = node.getText().indexOf(parentFStringQuote);
|
||||
if (node.getExpressionContentRange().contains(illegalQuoteOffset)) {
|
||||
TextRange illegalQuoteRange = TextRange.from(illegalQuoteOffset, parentFStringQuote.length());
|
||||
registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON312) && registerForLanguageLevel(level),
|
||||
PyPsiBundle.message("INSP.compatibility.feature.allow.quote.reuse.in.f-strings"),
|
||||
node, illegalQuoteRange.shiftRight(node.getTextRange().getStartOffset()), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitComment(@NotNull PsiComment node) {
|
||||
boolean insideFStringFragment = PsiTreeUtil.getParentOfType(node, PyFStringFragment.class) != null;
|
||||
if (insideFStringFragment) {
|
||||
registerForAllMatchingVersions(level -> level.isOlderThan(LanguageLevel.PYTHON312) && registerForLanguageLevel(level),
|
||||
PyPsiBundle.message("INSP.compatibility.feature.line.comments.in.f-strings"), node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -39,11 +39,6 @@ public class FStringsAnnotator extends PyAnnotator {
|
||||
|
||||
@Override
|
||||
public void visitPyFStringFragment(@NotNull PyFStringFragment node) {
|
||||
final List<PyFStringFragment> enclosingFragments = PsiTreeUtil.collectParents(node, PyFStringFragment.class, false,
|
||||
PyStringLiteralExpression.class::isInstance);
|
||||
if (enclosingFragments.size() > 1) {
|
||||
report(node, PyPsiBundle.message("ANN.fstrings.expression.fragment.inside.fstring.nested.too.deeply"));
|
||||
}
|
||||
final PsiElement typeConversion = node.getTypeConversion();
|
||||
if (typeConversion != null) {
|
||||
final String conversionChar = typeConversion.getText().substring(1);
|
||||
@@ -54,24 +49,6 @@ public class FStringsAnnotator extends PyAnnotator {
|
||||
report(typeConversion, PyPsiBundle.message("ANN.fstrings.illegal.conversion.character", conversionChar));
|
||||
}
|
||||
}
|
||||
|
||||
final boolean topLevel = PsiTreeUtil.getParentOfType(node, PyFStringFragment.class, true) == null;
|
||||
if (topLevel) {
|
||||
final List<PyFStringFragment> fragments = Lists.newArrayList(node);
|
||||
final PyFStringFragmentFormatPart formatPart = node.getFormatPart();
|
||||
if (formatPart != null) {
|
||||
fragments.addAll(formatPart.getFragments());
|
||||
}
|
||||
for (PyFStringFragment fragment : fragments) {
|
||||
final String wholeNodeText = fragment.getText();
|
||||
final TextRange range = fragment.getExpressionContentRange();
|
||||
for (int i = range.getStartOffset(); i < range.getEndOffset(); i++) {
|
||||
if (wholeNodeText.charAt(i) == '\\') {
|
||||
reportCharacter(fragment, i, PyPsiBundle.message("ANN.fstrings.expression.fragments.cannot.include.backslashes"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -106,14 +83,6 @@ public class FStringsAnnotator extends PyAnnotator {
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitComment(@NotNull PsiComment comment) {
|
||||
final boolean insideFragment = PsiTreeUtil.getParentOfType(comment, PyFStringFragment.class) != null;
|
||||
if (insideFragment) {
|
||||
report(comment, PyPsiBundle.message("ANN.fstrings.expression.fragments.cannot.include.line.comments"));
|
||||
}
|
||||
}
|
||||
|
||||
public void reportCharacter(@NotNull PsiElement element, int offset, @NotNull @InspectionMessage String message) {
|
||||
final int nodeStartOffset = element.getTextRange().getStartOffset();
|
||||
getHolder().newAnnotation(HighlightSeverity.ERROR, message).range(TextRange.from(offset, 1).shiftRight(nodeStartOffset)).create();
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
f'{<error descr="Expression expected"><error descr="Expression fragments inside f-strings cannot include backslashes">\</error>t</error>}'
|
||||
f'{<error descr="Expression expected"><error descr="Expression fragments inside f-strings cannot include backslashes">\</error>t</error><error descr="'}' expected">'</error>
|
||||
f'{<error descr="Expression expected"><error descr="Expression fragments inside f-strings cannot include backslashes">\</error>N{GREEK SMALL LETTER ALPHA}</error>}'
|
||||
f'{Formatable():\n\t}'
|
||||
f'{42:{<error descr="Expression expected"><error descr="Expression fragments inside f-strings cannot include backslashes">\</error>t</error>}}'
|
||||
f'{f"""{"<error descr="Expression fragments inside f-strings cannot include backslashes">\</error>n"}"""}'
|
||||
@@ -0,0 +1,7 @@
|
||||
f'{<error descr="Expression expected"><error descr="Python version 3.6 does not allow backslashes inside expression parts of f-strings">\</error>t</error>}'
|
||||
f'{<error descr="Expression expected"><error descr="Python version 3.6 does not allow backslashes inside expression parts of f-strings">\</error>N{GREEK SMALL LETTER ALPHA}</error>}'
|
||||
f'{Formatable():\n\t}'
|
||||
f'{42:{<error descr="Expression expected"><error descr="Python version 3.6 does not allow backslashes inside expression parts of f-strings">\</error>t</error>}}'
|
||||
f'{f"""{"<error descr="Python version 3.6 does not allow backslashes inside expression parts of f-strings">\</error>n"}"""}'
|
||||
f'{<error descr="Expression expected"><error descr="Python version 3.6 does not allow backslashes inside expression parts of f-strings">\</error>t<error descr="Python version 3.6 does not allow nesting of string literals with the same quote type inside f-strings">'</error><error descr="Python version 3.6 does not allow new lines in expression parts of non-triple-quoted f-strings">
|
||||
</error></error><EOLError descr="Type conversion, ':' or '}' expected"></EOLError><EOLError descr="' expected"></EOLError>
|
||||
@@ -0,0 +1,3 @@
|
||||
f'''{[
|
||||
42 <error descr="Python version 3.6 does not allow comments inside expression parts of f-strings"># foo</error>
|
||||
]}'''
|
||||
@@ -1,10 +1,7 @@
|
||||
f'{<error descr="Expression expected">}</error>'
|
||||
f'{<error descr="'}' expected"><error descr="Expression expected">'</error></error>
|
||||
f'{<EOLError descr="Type conversion, ':' or '}' expected"></EOLError><EOLError descr="Expression expected"></EOLError><EOLError descr="' expected"></EOLError>
|
||||
f'{<error descr="Expression expected">!</error>r}'
|
||||
f'{<error descr="Expression expected">:</error>2.3}'
|
||||
f'{42:2.{<error descr="Expression expected">}</error>}'
|
||||
f'{<error descr="Expression expected"> </error>}'
|
||||
f'{42:{<error descr="Expression expected"> </error>}}'
|
||||
f'{<error descr="Expression expected"> </error>:{<error descr="Expression expected"> </error><error descr="'}' expected">'</error>
|
||||
f'{<error descr="Expression expected"> </error>!r:{<error descr="Expression expected"> </error>:42}}'
|
||||
@@ -0,0 +1,19 @@
|
||||
import math
|
||||
s1 = f'{math.pi = :.2f}'
|
||||
s2 = f'{f"{3.1415=:.1f}":*^20}'
|
||||
s3 = f'{0 == 1}'
|
||||
x = 'A string'
|
||||
s4 = f'{x=!s}'
|
||||
x = 2.71828
|
||||
s5 = f'{x=:.2f}'
|
||||
s6 = f'{x=:}'
|
||||
s7 = f'{x=!r:^20}'
|
||||
s8 = f'{x=!s:^20}'
|
||||
s9 = f'{x= !a:^20}'
|
||||
s10 = f'{3 * x + 15=}'
|
||||
pi = 'π'
|
||||
s11 = f'alpha α {pi = } ω omega'
|
||||
s12 = f'''{
|
||||
3
|
||||
=}'''
|
||||
s13 = f'{"="}'
|
||||
@@ -1,10 +0,0 @@
|
||||
f'{<error descr="Expression expected"><error descr="Expression fragments inside f-strings cannot include line comments">#'</error></error><EOLError descr="Type conversion, ':' or '}' expected"></EOLError><EOLError descr="' expected"></EOLError>
|
||||
f'{<error descr="Expression expected"><error descr="Expression fragments inside f-strings cannot include line comments">#</error></error><EOLError descr="Type conversion, ':' or '}' expected"></EOLError><EOLError descr="' expected"></EOLError>
|
||||
f'{<error descr="Expression expected"><error descr="Expression fragments inside f-strings cannot include line comments">#foo#}'</error></error><EOLError descr="Type conversion, ':' or '}' expected"></EOLError><EOLError descr="' expected"></EOLError>
|
||||
f'{42:#}'
|
||||
f'{42:{<error descr="Expression expected"><error descr="Expression fragments inside f-strings cannot include line comments">#}}'</error></error><EOLError descr="Type conversion, ':' or '}' expected"></EOLError><EOLError descr="' expected"></EOLError>
|
||||
f'{x<error descr="Type conversion, ':' or '}' expected"> </error><error descr="Expression fragments inside f-strings cannot include line comments">### foo}'</error><EOLError descr="' expected"></EOLError>
|
||||
f'{"###"}'
|
||||
f'''{[
|
||||
42 <error descr="Expression fragments inside f-strings cannot include line comments"># foo</error>
|
||||
]}'''
|
||||
@@ -5,5 +5,3 @@ f'{42<error descr="An illegal conversion character 'z': should be one of 's', 'r
|
||||
f'{42<error descr="An illegal conversion character 'foo': should be one of 's', 'r', 'a'">!foo</error>}'
|
||||
f'{42<error descr="A conversion character is expected: should be one of 's', 'r', 'a'">!</error>}'
|
||||
f'{42<error descr="A conversion character is expected: should be one of 's', 'r', 'a'">!</error>:2}'
|
||||
f'{42<error descr="A conversion character is expected: should be one of 's', 'r', 'a'">!</error><error descr="'}' expected">'</error>
|
||||
f'{42<error descr="A conversion character is expected: should be one of 's', 'r', 'a'">!</error><EOLError descr=": or '}' expected"></EOLError><EOLError descr="' expected"></EOLError>
|
||||
|
||||
@@ -1,10 +1 @@
|
||||
f'{42}'
|
||||
f'{42!r}'
|
||||
f'{42!r:03}'
|
||||
f'{42:03}'
|
||||
f'{42!r:{y}.{z}}'
|
||||
f'{<error descr="'}' expected"><error descr="Expression expected">'</error></error>
|
||||
f'{42:{<error descr="'}' expected"><error descr="Expression expected">'</error></error>
|
||||
f'{42!r:{<error descr="'}' expected"><error descr="Expression expected">'</error></error>
|
||||
f'{{'
|
||||
f'{{{<error descr="'}' expected"><error descr="Expression expected">'</error></error>
|
||||
f'{<error descr="Missing closing quote [']"><error descr="Python version 3.6 does not allow nesting of string literals with the same quote type inside f-strings">'</error></error><EOLError descr="Type conversion, ':' or '}' expected"></EOLError><EOLError descr="' expected"></EOLError>
|
||||
@@ -0,0 +1,2 @@
|
||||
s = f'{1 +<error descr="Python version 3.11 does not allow new lines in expression parts of non-triple-quoted f-strings">
|
||||
</error>2}'
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
s = f'{42:{1 +<error descr="Python version 3.11 does not allow new lines in expression parts of non-triple-quoted f-strings">
|
||||
</error>2}}'
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
s = f"{f'{1 +<error descr="Python version 3.11 does not allow new lines in expression parts of non-triple-quoted f-strings">
|
||||
</error>2}'}"
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
s = f"{f'{42:{1 +<error descr="Python version 3.11 does not allow new lines in expression parts of non-triple-quoted f-strings">
|
||||
</error>2}}'}"
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
s = f"{f'foo{42:bar
|
||||
baz}'}"
|
||||
@@ -0,0 +1,2 @@
|
||||
s = f'{<error descr="Python version 3.11 does not allow new lines in expression parts of non-triple-quoted f-strings">"""
|
||||
"""</error>}'
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
s = f'{foo:{<error descr="Python version 3.11 does not allow new lines in expression parts of non-triple-quoted f-strings">"""
|
||||
"""</error>}}'
|
||||
@@ -0,0 +1 @@
|
||||
s = f'{f"{42:<error descr="Python version 3.11 does not allow nesting of string literals with the same quote type inside f-strings">'</error>}"}'
|
||||
@@ -0,0 +1 @@
|
||||
s = f'foo{f"baz<error descr="Python version 3.11 does not allow nesting of string literals with the same quote type inside f-strings">'</error>quux"}bar'
|
||||
@@ -0,0 +1 @@
|
||||
s = f'foo{f"<error descr="Python version 3.11 does not allow nesting of string literals with the same quote type inside f-strings">'</error>"}baz'
|
||||
+1
@@ -0,0 +1 @@
|
||||
s = f'{42:{f"<error descr="Python version 3.11 does not allow nesting of string literals with the same quote type inside f-strings">'</error>"}}'
|
||||
+1
@@ -0,0 +1 @@
|
||||
s = f'{f"""{f"<error descr="Python version 3.11 does not allow nesting of string literals with the same quote type inside f-strings">'</error>"}"""}'
|
||||
+1
@@ -0,0 +1 @@
|
||||
s = f'{f"""{42:{f"<error descr="Python version 3.11 does not allow nesting of string literals with the same quote type inside f-strings">'</error>"}}"""}'
|
||||
+1
@@ -0,0 +1 @@
|
||||
s = f'{f"""{"<error descr="Python version 3.11 does not allow nesting of string literals with the same quote type inside f-strings">'</error>"}"""}'
|
||||
+1
@@ -0,0 +1 @@
|
||||
s = f'{f"""{42:{"<error descr="Python version 3.11 does not allow nesting of string literals with the same quote type inside f-strings">'</error>"}}"""}'
|
||||
@@ -0,0 +1 @@
|
||||
s = f'foo{"<error descr="Python version 3.11 does not allow nesting of string literals with the same quote type inside f-strings">'</error>"}baz'
|
||||
+1
@@ -0,0 +1 @@
|
||||
s = f'{42:{"<error descr="Python version 3.11 does not allow nesting of string literals with the same quote type inside f-strings">'</error>"}}'
|
||||
@@ -0,0 +1 @@
|
||||
s = f'foo{f<error descr="Python version 3.11 does not allow nesting of string literals with the same quote type inside f-strings">'</error>bar'}baz'
|
||||
+1
@@ -0,0 +1 @@
|
||||
s = f'{42:{f<error descr="Python version 3.11 does not allow nesting of string literals with the same quote type inside f-strings">'</error>foo'}}'
|
||||
+1
@@ -0,0 +1 @@
|
||||
s = f'{f"{f<error descr="Python version 3.11 does not allow nesting of string literals with the same quote type inside f-strings">'</error>foo'}"}'
|
||||
+1
@@ -0,0 +1 @@
|
||||
s = f'{f"{42:{f<error descr="Python version 3.11 does not allow nesting of string literals with the same quote type inside f-strings">'</error>foo'}}"}'
|
||||
@@ -0,0 +1 @@
|
||||
s = f'{f"{<error descr="Python version 3.11 does not allow nesting of string literals with the same quote type inside f-strings">'</error>foo'}"}'
|
||||
+1
@@ -0,0 +1 @@
|
||||
s = f'{f"{42:{<error descr="Python version 3.11 does not allow nesting of string literals with the same quote type inside f-strings">'</error>foo'}}"}'
|
||||
@@ -0,0 +1 @@
|
||||
s = f'foo{<error descr="Python version 3.11 does not allow nesting of string literals with the same quote type inside f-strings">'</error>bar'}baz'
|
||||
+1
@@ -0,0 +1 @@
|
||||
s = f'{42:{<error descr="Python version 3.11 does not allow nesting of string literals with the same quote type inside f-strings" textAttributesKey="ERRORS_ATTRIBUTES">'</error>foo'}}'
|
||||
@@ -1,7 +0,0 @@
|
||||
f'{x:{y:<error descr="Expression fragment inside an f-string is nested too deeply">{<error descr="Expression expected">}</error></error>}}'
|
||||
f'{x:{y:<error descr="Expression fragment inside an f-string is nested too deeply">{<error descr="Expression expected"><error descr="Expression fragments inside f-strings cannot include line comments"># foo}}}'</error></error></error><EOLError descr="Type conversion, ':' or '}' expected"></EOLError><EOLError descr="' expected"></EOLError>
|
||||
f'{x:{y:<error descr="Expression fragment inside an f-string is nested too deeply">{z<error descr="An illegal conversion character 'z': should be one of 's', 'r', 'a'">!z</error>}</error>}}'
|
||||
f'{x:{y:<error descr="Expression fragment inside an f-string is nested too deeply">{z:<error descr="Expression fragment inside an f-string is nested too deeply">{42}</error>}</error>}}'
|
||||
f'{<error descr="Expression expected">:</error>{<error descr="Expression expected">:</error><error descr="Expression fragment inside an f-string is nested too deeply">{<error descr="Expression expected">:</error><error descr="Expression fragment inside an f-string is nested too deeply">{<error descr="Expression expected">}</error></error>}</error>}}'
|
||||
f'{x:{y:<error descr="Expression fragment inside an f-string is nested too deeply">{z</error><error descr="'}' expected">'</error>
|
||||
f'{x:{y:<error descr="Expression fragment inside an f-string is nested too deeply">{z</error><EOLError descr="Type conversion, ':' or '}' expected"></EOLError><EOLError descr="' expected"></EOLError>
|
||||
@@ -0,0 +1,5 @@
|
||||
f'{x:{y:<error descr="Python version 3.6 does not allow nesting expressions in format specifiers this deep">{<error descr="Expression expected">}</error></error>}}'
|
||||
f'{x:{y:<error descr="Python version 3.6 does not allow nesting expressions in format specifiers this deep">{z<error descr="An illegal conversion character 'z': should be one of 's', 'r', 'a'">!z</error>}</error>}}'
|
||||
f'{x:{y:<error descr="Python version 3.6 does not allow nesting expressions in format specifiers this deep">{z:<error descr="Python version 3.6 does not allow nesting expressions in format specifiers this deep">{42}</error>}</error>}}'
|
||||
f'{<error descr="Expression expected">:</error>{<error descr="Expression expected">:</error><error descr="Python version 3.6 does not allow nesting expressions in format specifiers this deep">{<error descr="Expression expected">:</error><error descr="Python version 3.6 does not allow nesting expressions in format specifiers this deep">{<error descr="Expression expected">}</error></error>}</error>}}'
|
||||
f'{x:{y:<error descr="Python version 3.6 does not allow nesting expressions in format specifiers this deep">{z</error><EOLError descr="Type conversion, ':' or '}' expected"></EOLError><EOLError descr="' expected"></EOLError>
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
pass
|
||||
f'''{1 +
|
||||
2}'''
|
||||
@@ -0,0 +1,2 @@
|
||||
s = f'''{1 +
|
||||
2}'''
|
||||
+1
@@ -0,0 +1 @@
|
||||
s = f'{ (lambda x: <error descr="Python version 3.11 does not allow nesting of string literals with the same quote type inside f-strings">'</error>foo') }'
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
s = f'''{
|
||||
<error descr="Python version 3.11 does not allow nesting of string literals with the same quote type inside f-strings">'''</error>'''
|
||||
}'''
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
s = f"""{f'''
|
||||
{"bar"
|
||||
}
|
||||
'''
|
||||
}"""
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
s = f"""{f'{1 +<error descr="Python version 3.11 does not allow new lines in expression parts of non-triple-quoted f-strings">
|
||||
</error>2}'}"""
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
s = f"""{f'{(1 +<error descr="Python version 3.11 does not allow new lines in expression parts of non-triple-quoted f-strings">
|
||||
</error>2)}'}"""
|
||||
@@ -13,6 +13,6 @@ PyFile:FStringFragmentIncompleteTypeConversionBeforeClosingQuote.py
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('42')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_TYPE_CONVERSION)('!')
|
||||
PsiErrorElement:'}' expected
|
||||
PsiErrorElement:: or '}' expected
|
||||
<empty list>
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)(''')
|
||||
@@ -5,13 +5,16 @@ PyFile:FStringIncompleteFragment.py
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: {42
|
||||
PyStringLiteralExpression: {42'
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('42')
|
||||
PsiErrorElement:'}' expected
|
||||
PsiErrorElement:Unexpected expression part
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)(''')
|
||||
PsiErrorElement:Type conversion, ':' or '}' expected
|
||||
<empty list>
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
PsiErrorElement:' expected
|
||||
<empty list>
|
||||
@@ -13,6 +13,6 @@ PyFile:FStringIncompleteFragmentWithTypeConversion.py
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('42')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_TYPE_CONVERSION)('!r')
|
||||
PsiErrorElement:'}' expected
|
||||
PsiErrorElement:: or '}' expected
|
||||
<empty list>
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)(''')
|
||||
@@ -0,0 +1,23 @@
|
||||
PyFile:FStringNotTerminatedByLineBreakInExpression.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: {1 +
|
||||
2}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyBinaryExpression
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('1')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:PLUS)('+')
|
||||
PsiWhiteSpace('\n')
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('2')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
+8
-20
@@ -1,4 +1,4 @@
|
||||
PyFile:FStringTerminatedByLineBreakInExpressionInFormatPart.py
|
||||
PyFile:FStringNotTerminatedByLineBreakInExpressionInFormatPart.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
@@ -6,6 +6,7 @@ PyFile:FStringTerminatedByLineBreakInExpressionInFormatPart.py
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: {42:{1 +
|
||||
2}}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PyFStringFragment
|
||||
@@ -21,22 +22,9 @@ PyFile:FStringTerminatedByLineBreakInExpressionInFormatPart.py
|
||||
PsiElement(Py:INTEGER_LITERAL)('1')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:PLUS)('+')
|
||||
PsiErrorElement:Expression expected
|
||||
<empty list>
|
||||
PsiErrorElement:' expected
|
||||
<empty list>
|
||||
PsiWhiteSpace('\n')
|
||||
PyExpressionStatement
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('2')
|
||||
PsiErrorElement:End of statement expected
|
||||
<empty list>
|
||||
PsiElement(Py:RBRACE)('}')
|
||||
PsiErrorElement:Statement expected, found Py:RBRACE
|
||||
<empty list>
|
||||
PsiElement(Py:RBRACE)('}')
|
||||
PsiErrorElement:Statement expected, found Py:RBRACE
|
||||
<empty list>
|
||||
PyExpressionStatement
|
||||
PyStringLiteralExpression:
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)(''')
|
||||
PsiWhiteSpace('\n')
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('2')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
+10
-19
@@ -1,4 +1,4 @@
|
||||
PyFile:FStringTerminatedByLineBreakInNestedExpression.py
|
||||
PyFile:FStringNotTerminatedByLineBreakInNestedExpression.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
@@ -6,11 +6,13 @@ PyFile:FStringTerminatedByLineBreakInNestedExpression.py
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: {f'{1 +
|
||||
2}'}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f"')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression: {1 +
|
||||
2}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PyFStringFragment
|
||||
@@ -20,21 +22,10 @@ PyFile:FStringTerminatedByLineBreakInNestedExpression.py
|
||||
PsiElement(Py:INTEGER_LITERAL)('1')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:PLUS)('+')
|
||||
PsiErrorElement:Expression expected
|
||||
<empty list>
|
||||
PsiErrorElement:' expected
|
||||
<empty list>
|
||||
PsiErrorElement:" expected
|
||||
<empty list>
|
||||
PsiWhiteSpace('\n')
|
||||
PyExpressionStatement
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('2')
|
||||
PsiErrorElement:End of statement expected
|
||||
<empty list>
|
||||
PsiElement(Py:RBRACE)('}')
|
||||
PsiErrorElement:Statement expected, found Py:RBRACE
|
||||
<empty list>
|
||||
PyExpressionStatement
|
||||
PyStringLiteralExpression: }"
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)(''}"')
|
||||
PsiWhiteSpace('\n')
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('2')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)('"')
|
||||
+11
-22
@@ -1,4 +1,4 @@
|
||||
PyFile:FStringTerminatedByLineBreakInNestedExpressionInFormatPart.py
|
||||
PyFile:FStringNotTerminatedByLineBreakInNestedExpressionInFormatPart.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
@@ -6,11 +6,13 @@ PyFile:FStringTerminatedByLineBreakInNestedExpressionInFormatPart.py
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: {f'{42:{1 +
|
||||
2}}'}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f"')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression: {42:{1 +
|
||||
2}}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PyFStringFragment
|
||||
@@ -26,24 +28,11 @@ PyFile:FStringTerminatedByLineBreakInNestedExpressionInFormatPart.py
|
||||
PsiElement(Py:INTEGER_LITERAL)('1')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:PLUS)('+')
|
||||
PsiErrorElement:Expression expected
|
||||
<empty list>
|
||||
PsiErrorElement:' expected
|
||||
<empty list>
|
||||
PsiErrorElement:" expected
|
||||
<empty list>
|
||||
PsiWhiteSpace('\n')
|
||||
PyExpressionStatement
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('2')
|
||||
PsiErrorElement:End of statement expected
|
||||
<empty list>
|
||||
PsiElement(Py:RBRACE)('}')
|
||||
PsiErrorElement:Statement expected, found Py:RBRACE
|
||||
<empty list>
|
||||
PsiElement(Py:RBRACE)('}')
|
||||
PsiErrorElement:Statement expected, found Py:RBRACE
|
||||
<empty list>
|
||||
PyExpressionStatement
|
||||
PyStringLiteralExpression: }"
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)(''}"')
|
||||
PsiWhiteSpace('\n')
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('2')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)('"')
|
||||
+6
-10
@@ -1,4 +1,4 @@
|
||||
PyFile:FStringTerminatedByLineBreakInStringLiteral.py
|
||||
PyFile:FStringNotTerminatedByLineBreakInStringLiteral.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
@@ -6,17 +6,13 @@ PyFile:FStringTerminatedByLineBreakInStringLiteral.py
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: {"""
|
||||
"""}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression:
|
||||
PsiElement(Py:TRIPLE_QUOTED_STRING)('"""')
|
||||
PsiErrorElement:Type conversion, ':' or '}' expected
|
||||
<empty list>
|
||||
PsiErrorElement:' expected
|
||||
<empty list>
|
||||
PsiWhiteSpace('\n')
|
||||
PyExpressionStatement
|
||||
PyStringLiteralExpression: }'
|
||||
PsiElement(Py:TRIPLE_QUOTED_STRING)('"""}'')
|
||||
|
||||
PsiElement(Py:TRIPLE_QUOTED_STRING)('"""\n"""')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
+7
-10
@@ -1,4 +1,4 @@
|
||||
PyFile:FStringTerminatedByLineBreakInStringLiteralInFormatPart.py
|
||||
PyFile:FStringNotTerminatedByLineBreakInStringLiteralInFormatPart.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
@@ -6,6 +6,7 @@ PyFile:FStringTerminatedByLineBreakInStringLiteralInFormatPart.py
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: {foo:{"""
|
||||
"""}}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PyFStringFragment
|
||||
@@ -17,12 +18,8 @@ PyFile:FStringTerminatedByLineBreakInStringLiteralInFormatPart.py
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression:
|
||||
PsiElement(Py:TRIPLE_QUOTED_STRING)('"""')
|
||||
PsiErrorElement:Type conversion, ':' or '}' expected
|
||||
<empty list>
|
||||
PsiErrorElement:' expected
|
||||
<empty list>
|
||||
PsiWhiteSpace('\n')
|
||||
PyExpressionStatement
|
||||
PyStringLiteralExpression: }}'
|
||||
PsiElement(Py:TRIPLE_QUOTED_STRING)('"""}}'')
|
||||
|
||||
PsiElement(Py:TRIPLE_QUOTED_STRING)('"""\n"""')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
+8
-16
@@ -1,16 +1,16 @@
|
||||
PyFile:FStringTerminatedByQuoteInNestedFormatPart.py
|
||||
PyFile:FStringNotTerminatedByQuoteInNestedFormatPart.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: {f"{42:
|
||||
PyStringLiteralExpression: {f"{42:'}"}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression: {42:
|
||||
PyStringLiteralExpression: {42:'}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f"')
|
||||
PyFStringFragment
|
||||
@@ -19,16 +19,8 @@ PyFile:FStringTerminatedByQuoteInNestedFormatPart.py
|
||||
PsiElement(Py:INTEGER_LITERAL)('42')
|
||||
PyFStringFragmentFormatPart
|
||||
PsiElement(Py:FSTRING_FRAGMENT_FORMAT_START)(':')
|
||||
PsiErrorElement:'}' expected
|
||||
<empty list>
|
||||
PsiErrorElement:" expected
|
||||
<empty list>
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
PsiErrorElement:End of statement expected
|
||||
<empty list>
|
||||
PsiElement(Py:RBRACE)('}')
|
||||
PsiErrorElement:Statement expected, found Py:RBRACE
|
||||
<empty list>
|
||||
PyExpressionStatement
|
||||
PyStringLiteralExpression: }'
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)('"}'')
|
||||
PsiElement(Py:FSTRING_TEXT)(''')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)('"')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
@@ -0,0 +1,21 @@
|
||||
PyFile:FStringNotTerminatedByQuoteInNestedLiteralPart.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: foo{f"baz'quux"}bar
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PsiElement(Py:FSTRING_TEXT)('foo')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression: baz'quux
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f"')
|
||||
PsiElement(Py:FSTRING_TEXT)('baz'quux')
|
||||
PsiElement(Py:FSTRING_END)('"')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_TEXT)('bar')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
+8
-9
@@ -1,22 +1,21 @@
|
||||
PyFile:FStringTerminatedByQuoteInsideFStringLiteral.py
|
||||
PyFile:FStringNotTerminatedByQuoteInsideFStringLiteral.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: foo{f"}baz'
|
||||
PyStringLiteralExpression: foo{f"'"}baz
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PsiElement(Py:FSTRING_TEXT)('foo')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression:
|
||||
PyStringLiteralExpression: '
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f"')
|
||||
PsiErrorElement:" expected
|
||||
<empty list>
|
||||
PsiErrorElement:'}' expected
|
||||
<empty list>
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)('"}baz'')
|
||||
PsiElement(Py:FSTRING_TEXT)(''')
|
||||
PsiElement(Py:FSTRING_END)('"')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_TEXT)('baz')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
+8
-9
@@ -1,11 +1,11 @@
|
||||
PyFile:FStringTerminatedByQuoteInsideFStringLiteralInFormatPart.py
|
||||
PyFile:FStringNotTerminatedByQuoteInsideFStringLiteralInFormatPart.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: {42:{f"}}'
|
||||
PyStringLiteralExpression: {42:{f"'"}}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PyFStringFragment
|
||||
@@ -16,12 +16,11 @@ PyFile:FStringTerminatedByQuoteInsideFStringLiteralInFormatPart.py
|
||||
PsiElement(Py:FSTRING_FRAGMENT_FORMAT_START)(':')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression:
|
||||
PyStringLiteralExpression: '
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f"')
|
||||
PsiErrorElement:" expected
|
||||
<empty list>
|
||||
PsiErrorElement:'}' expected
|
||||
<empty list>
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)('"}}'')
|
||||
PsiElement(Py:FSTRING_TEXT)(''')
|
||||
PsiElement(Py:FSTRING_END)('"')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
@@ -0,0 +1,26 @@
|
||||
PyFile:FStringNotTerminatedByQuoteInsideNestedFStringLiteral.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: {f"""{f"'"}"""}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression: {f"'"}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f"""')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression: '
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f"')
|
||||
PsiElement(Py:FSTRING_TEXT)(''')
|
||||
PsiElement(Py:FSTRING_END)('"')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)('"""')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
+11
-21
@@ -1,16 +1,16 @@
|
||||
PyFile:FStringTerminatedByQuoteInsideNestedFStringLiteralInFormatPart.py
|
||||
PyFile:FStringNotTerminatedByQuoteInsideNestedFStringLiteralInFormatPart.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: {f"""{42:{f"}}
|
||||
PyStringLiteralExpression: {f"""{42:{f"'"}}"""}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression: {42:{f"
|
||||
PyStringLiteralExpression: {42:{f"'"}}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f"""')
|
||||
PyFStringFragment
|
||||
@@ -21,23 +21,13 @@ PyFile:FStringTerminatedByQuoteInsideNestedFStringLiteralInFormatPart.py
|
||||
PsiElement(Py:FSTRING_FRAGMENT_FORMAT_START)(':')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression:
|
||||
PyStringLiteralExpression: '
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f"')
|
||||
PsiErrorElement:" expected
|
||||
<empty list>
|
||||
PsiErrorElement:'}' expected
|
||||
<empty list>
|
||||
PsiErrorElement:""" expected
|
||||
<empty list>
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)('"}}"')
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)('""')
|
||||
PsiErrorElement:End of statement expected
|
||||
<empty list>
|
||||
PsiElement(Py:RBRACE)('}')
|
||||
PsiErrorElement:Statement expected, found Py:RBRACE
|
||||
<empty list>
|
||||
PyExpressionStatement
|
||||
PyStringLiteralExpression:
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)(''')
|
||||
PsiElement(Py:FSTRING_TEXT)(''')
|
||||
PsiElement(Py:FSTRING_END)('"')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)('"""')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
@@ -0,0 +1,23 @@
|
||||
PyFile:FStringNotTerminatedByQuoteInsideNestedStringLiteral.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: {f"""{"'"}"""}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression: {"'"}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f"""')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression: '
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)('"'"')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)('"""')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
PyFile:FStringNotTerminatedByQuoteInsideNestedStringLiteralInFormatPart.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: {f"""{42:{"'"}}"""}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression: {42:{"'"}}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f"""')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('42')
|
||||
PyFStringFragmentFormatPart
|
||||
PsiElement(Py:FSTRING_FRAGMENT_FORMAT_START)(':')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression: '
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)('"'"')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)('"""')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
+7
-8
@@ -1,19 +1,18 @@
|
||||
PyFile:FStringTerminatedByQuoteInsideStringLiteral.py
|
||||
PyFile:FStringNotTerminatedByQuoteInsideStringLiteral.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: foo{"}baz'
|
||||
PyStringLiteralExpression: foo{"'"}baz
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PsiElement(Py:FSTRING_TEXT)('foo')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression:
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)('"')
|
||||
PsiErrorElement:'}' expected
|
||||
<empty list>
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)('"}baz'')
|
||||
PyStringLiteralExpression: '
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)('"'"')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_TEXT)('baz')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
+7
-8
@@ -1,11 +1,11 @@
|
||||
PyFile:FStringTerminatedByQuoteInsideStringLiteralInFormatPart.py
|
||||
PyFile:FStringNotTerminatedByQuoteInsideStringLiteralInFormatPart.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: {42:{"}}'
|
||||
PyStringLiteralExpression: {42:{"'"}}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PyFStringFragment
|
||||
@@ -16,9 +16,8 @@ PyFile:FStringTerminatedByQuoteInsideStringLiteralInFormatPart.py
|
||||
PsiElement(Py:FSTRING_FRAGMENT_FORMAT_START)(':')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression:
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)('"')
|
||||
PsiErrorElement:'}' expected
|
||||
<empty list>
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)('"}}'')
|
||||
PyStringLiteralExpression: '
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)('"'"')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
@@ -0,0 +1,21 @@
|
||||
PyFile:FStringNotTerminatedByQuoteOfFStringLiteral.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: foo{f'bar'}baz
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PsiElement(Py:FSTRING_TEXT)('foo')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression: bar
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PsiElement(Py:FSTRING_TEXT)('bar')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_TEXT)('baz')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
@@ -0,0 +1,26 @@
|
||||
PyFile:FStringNotTerminatedByQuoteOfFStringLiteralInFormatPart.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: {42:{f'foo'}}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('42')
|
||||
PyFStringFragmentFormatPart
|
||||
PsiElement(Py:FSTRING_FRAGMENT_FORMAT_START)(':')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression: foo
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PsiElement(Py:FSTRING_TEXT)('foo')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
@@ -0,0 +1,26 @@
|
||||
PyFile:FStringNotTerminatedByQuoteOfNestedFStringLiteral.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: {f"{f'foo'}"}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression: {f'foo'}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f"')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression: foo
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PsiElement(Py:FSTRING_TEXT)('foo')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)('"')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
+13
-20
@@ -1,16 +1,16 @@
|
||||
PyFile:FStringTerminatedByQuoteOfNestedStringLiteralInFormatPart.py
|
||||
PyFile:FStringNotTerminatedByQuoteOfNestedFStringLiteralInFormatPart.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: {f"{42:{
|
||||
PyStringLiteralExpression: {f"{42:{f'foo'}}"}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression: {42:{
|
||||
PyStringLiteralExpression: {42:{f'foo'}}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f"')
|
||||
PyFStringFragment
|
||||
@@ -21,20 +21,13 @@ PyFile:FStringTerminatedByQuoteOfNestedStringLiteralInFormatPart.py
|
||||
PsiElement(Py:FSTRING_FRAGMENT_FORMAT_START)(':')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PsiErrorElement:Expression expected
|
||||
<empty list>
|
||||
PsiErrorElement:'}' expected
|
||||
<empty list>
|
||||
PsiErrorElement:" expected
|
||||
<empty list>
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
PsiErrorElement:End of statement expected
|
||||
<empty list>
|
||||
PyExpressionStatement
|
||||
PyReferenceExpression: foo
|
||||
PsiElement(Py:IDENTIFIER)('foo')
|
||||
PsiErrorElement:End of statement expected
|
||||
<empty list>
|
||||
PyExpressionStatement
|
||||
PyStringLiteralExpression: }}"}
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)(''}}"}'')
|
||||
PyStringLiteralExpression: foo
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PsiElement(Py:FSTRING_TEXT)('foo')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)('"')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
@@ -0,0 +1,23 @@
|
||||
PyFile:FStringNotTerminatedByQuoteOfNestedStringLiteral.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: {f"{'foo'}"}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression: {'foo'}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f"')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression: foo
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)(''foo'')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)('"')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
+10
-20
@@ -1,16 +1,16 @@
|
||||
PyFile:FStringTerminatedByQuoteOfNestedFStringLiteralInFormatPart.py
|
||||
PyFile:FStringNotTerminatedByQuoteOfNestedStringLiteralInFormatPart.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: {f"{42:{f
|
||||
PyStringLiteralExpression: {f"{42:{'foo'}}"}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression: {42:{f
|
||||
PyStringLiteralExpression: {42:{'foo'}}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f"')
|
||||
PyFStringFragment
|
||||
@@ -21,20 +21,10 @@ PyFile:FStringTerminatedByQuoteOfNestedFStringLiteralInFormatPart.py
|
||||
PsiElement(Py:FSTRING_FRAGMENT_FORMAT_START)(':')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyReferenceExpression: f
|
||||
PsiElement(Py:IDENTIFIER)('f')
|
||||
PsiErrorElement:'}' expected
|
||||
<empty list>
|
||||
PsiErrorElement:" expected
|
||||
<empty list>
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
PsiErrorElement:End of statement expected
|
||||
<empty list>
|
||||
PyExpressionStatement
|
||||
PyReferenceExpression: foo
|
||||
PsiElement(Py:IDENTIFIER)('foo')
|
||||
PsiErrorElement:End of statement expected
|
||||
<empty list>
|
||||
PyExpressionStatement
|
||||
PyStringLiteralExpression: }}"}
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)(''}}"}'')
|
||||
PyStringLiteralExpression: foo
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)(''foo'')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)('"')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
@@ -0,0 +1,18 @@
|
||||
PyFile:FStringNotTerminatedByQuoteOfStringLiteral.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: foo{'bar'}baz
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PsiElement(Py:FSTRING_TEXT)('foo')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression: bar
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)(''bar'')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_TEXT)('baz')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
@@ -0,0 +1,23 @@
|
||||
PyFile:FStringNotTerminatedByQuoteOfStringLiteralInFormatPart.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: {42:{'foo'}}
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyNumericLiteralExpression
|
||||
PsiElement(Py:INTEGER_LITERAL)('42')
|
||||
PyFStringFragmentFormatPart
|
||||
PsiElement(Py:FSTRING_FRAGMENT_FORMAT_START)(':')
|
||||
PyFStringFragment
|
||||
PsiElement(Py:FSTRING_FRAGMENT_START)('{')
|
||||
PyStringLiteralExpression: foo
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)(''foo'')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
+8
-15
@@ -1,11 +1,11 @@
|
||||
PyFile:MultilineFStringTerminatedByQuotesInsideParenthesizedExpression.py
|
||||
PyFile:FStringNotTerminatedByQuotesInsideParenthesizedExpression.py
|
||||
PyAssignmentStatement
|
||||
PyTargetExpression: s
|
||||
PsiElement(Py:IDENTIFIER)('s')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:EQ)('=')
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: { (lambda x:
|
||||
PyStringLiteralExpression: { (lambda x: 'foo') }
|
||||
PyFormattedStringElement
|
||||
PsiElement(Py:FSTRING_START)('f'')
|
||||
PyFStringFragment
|
||||
@@ -20,17 +20,10 @@ PyFile:MultilineFStringTerminatedByQuotesInsideParenthesizedExpression.py
|
||||
PyNamedParameter('x')
|
||||
PsiElement(Py:IDENTIFIER)('x')
|
||||
PsiElement(Py:COLON)(':')
|
||||
PsiErrorElement:Expression expected
|
||||
<empty list>
|
||||
PsiWhiteSpace(' ')
|
||||
PyStringLiteralExpression: foo
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)(''foo'')
|
||||
PsiElement(Py:RPAR)(')')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
PsiErrorElement:End of statement expected
|
||||
<empty list>
|
||||
PyExpressionStatement
|
||||
PyReferenceExpression: foo
|
||||
PsiElement(Py:IDENTIFIER)('foo')
|
||||
PsiErrorElement:End of statement expected
|
||||
<empty list>
|
||||
PyExpressionStatement
|
||||
PyStringLiteralExpression: ) }
|
||||
PsiElement(Py:SINGLE_QUOTED_STRING)('') }'')
|
||||
PsiElement(Py:FSTRING_FRAGMENT_END)('}')
|
||||
PsiElement(Py:FSTRING_END)(''')
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user