Synchronize state of parser and lexer for LONG_TEMPLATE_ENTRY (KT-14865)
Lexer monitors "long string template" state end and will produce LONG_TEMPLATE_ENTRY_END token when it is reached. If parser continues without waiting for it, it will eventually get handling token that will produce irrelevant error. Such behaviour also breaks lazy elements (LAMBDA_EXPRESSION in this case) contract: range of parsed text in eager mode should be same to one parsed in lazy mode. #KT-14865 Fixed
This commit is contained in:
@@ -764,9 +764,24 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
|
||||
|
||||
advance(); // LONG_TEMPLATE_ENTRY_START
|
||||
|
||||
parseExpression();
|
||||
while (!eof()) {
|
||||
int offset = myBuilder.getCurrentOffset();
|
||||
|
||||
parseExpression();
|
||||
|
||||
if (_at(LONG_TEMPLATE_ENTRY_END)) {
|
||||
advance();
|
||||
break;
|
||||
}
|
||||
else {
|
||||
error("Expecting '}'");
|
||||
if (offset == myBuilder.getCurrentOffset()) {
|
||||
// Prevent hang if can't advance with parseExpression()
|
||||
advance();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
expect(LONG_TEMPLATE_ENTRY_END, "Expecting '}'", TokenSet.create(CLOSING_QUOTE, DANGLING_NEWLINE, REGULAR_STRING_PART, ESCAPE_SEQUENCE, SHORT_TEMPLATE_ENTRY_START));
|
||||
longTemplateEntry.done(LONG_STRING_TEMPLATE_ENTRY);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
fun some1() {
|
||||
{
|
||||
"""${dM$ { "$a -> $" }}
|
||||
|
||||
"""}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
JetFile: lambdaExpressionInString_1.kt
|
||||
PACKAGE_DIRECTIVE
|
||||
<empty list>
|
||||
IMPORT_LIST
|
||||
<empty list>
|
||||
FUN
|
||||
PsiElement(fun)('fun')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(IDENTIFIER)('some1')
|
||||
VALUE_PARAMETER_LIST
|
||||
PsiElement(LPAR)('(')
|
||||
PsiElement(RPAR)(')')
|
||||
PsiWhiteSpace(' ')
|
||||
BLOCK
|
||||
PsiElement(LBRACE)('{')
|
||||
PsiWhiteSpace('\n ')
|
||||
LAMBDA_EXPRESSION
|
||||
FUNCTION_LITERAL
|
||||
PsiElement(LBRACE)('{')
|
||||
PsiWhiteSpace('\n ')
|
||||
BLOCK
|
||||
STRING_TEMPLATE
|
||||
PsiElement(OPEN_QUOTE)('"""')
|
||||
LONG_STRING_TEMPLATE_ENTRY
|
||||
PsiElement(LONG_TEMPLATE_ENTRY_START)('${')
|
||||
REFERENCE_EXPRESSION
|
||||
PsiElement(IDENTIFIER)('dM')
|
||||
PsiErrorElement:Expecting '}'
|
||||
<empty list>
|
||||
PsiElement(BAD_CHARACTER)('$')
|
||||
PsiWhiteSpace(' ')
|
||||
LAMBDA_EXPRESSION
|
||||
FUNCTION_LITERAL
|
||||
PsiElement(LBRACE)('{')
|
||||
PsiWhiteSpace(' ')
|
||||
BLOCK
|
||||
STRING_TEMPLATE
|
||||
PsiElement(OPEN_QUOTE)('"')
|
||||
SHORT_STRING_TEMPLATE_ENTRY
|
||||
PsiElement(SHORT_TEMPLATE_ENTRY_START)('$')
|
||||
REFERENCE_EXPRESSION
|
||||
PsiElement(IDENTIFIER)('a')
|
||||
LITERAL_STRING_TEMPLATE_ENTRY
|
||||
PsiElement(REGULAR_STRING_PART)(' -> ')
|
||||
LITERAL_STRING_TEMPLATE_ENTRY
|
||||
PsiElement(REGULAR_STRING_PART)('$')
|
||||
PsiElement(CLOSING_QUOTE)('"')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(RBRACE)('}')
|
||||
PsiElement(LONG_TEMPLATE_ENTRY_END)('}')
|
||||
LITERAL_STRING_TEMPLATE_ENTRY
|
||||
PsiElement(REGULAR_STRING_PART)('\n')
|
||||
LITERAL_STRING_TEMPLATE_ENTRY
|
||||
PsiElement(REGULAR_STRING_PART)('\n')
|
||||
LITERAL_STRING_TEMPLATE_ENTRY
|
||||
PsiElement(REGULAR_STRING_PART)(' ')
|
||||
PsiElement(CLOSING_QUOTE)('"""')
|
||||
PsiElement(RBRACE)('}')
|
||||
PsiWhiteSpace('\n')
|
||||
PsiElement(RBRACE)('}')
|
||||
@@ -0,0 +1,4 @@
|
||||
fun main(args: Array<String>) {
|
||||
{ "${"}
|
||||
{ "" }
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
JetFile: lambdaExpressionInString_2.kt
|
||||
PACKAGE_DIRECTIVE
|
||||
<empty list>
|
||||
IMPORT_LIST
|
||||
<empty list>
|
||||
FUN
|
||||
PsiElement(fun)('fun')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(IDENTIFIER)('main')
|
||||
VALUE_PARAMETER_LIST
|
||||
PsiElement(LPAR)('(')
|
||||
VALUE_PARAMETER
|
||||
PsiElement(IDENTIFIER)('args')
|
||||
PsiElement(COLON)(':')
|
||||
PsiWhiteSpace(' ')
|
||||
TYPE_REFERENCE
|
||||
USER_TYPE
|
||||
REFERENCE_EXPRESSION
|
||||
PsiElement(IDENTIFIER)('Array')
|
||||
TYPE_ARGUMENT_LIST
|
||||
PsiElement(LT)('<')
|
||||
TYPE_PROJECTION
|
||||
TYPE_REFERENCE
|
||||
USER_TYPE
|
||||
REFERENCE_EXPRESSION
|
||||
PsiElement(IDENTIFIER)('String')
|
||||
PsiElement(GT)('>')
|
||||
PsiElement(RPAR)(')')
|
||||
PsiWhiteSpace(' ')
|
||||
BLOCK
|
||||
PsiElement(LBRACE)('{')
|
||||
PsiWhiteSpace('\n ')
|
||||
LAMBDA_EXPRESSION
|
||||
FUNCTION_LITERAL
|
||||
PsiElement(LBRACE)('{')
|
||||
PsiWhiteSpace(' ')
|
||||
BLOCK
|
||||
STRING_TEMPLATE
|
||||
PsiElement(OPEN_QUOTE)('"')
|
||||
LONG_STRING_TEMPLATE_ENTRY
|
||||
PsiElement(LONG_TEMPLATE_ENTRY_START)('${')
|
||||
STRING_TEMPLATE
|
||||
PsiElement(OPEN_QUOTE)('"')
|
||||
LITERAL_STRING_TEMPLATE_ENTRY
|
||||
PsiElement(REGULAR_STRING_PART)('}')
|
||||
PsiErrorElement:Expecting '"'
|
||||
<empty list>
|
||||
PsiErrorElement:Expecting '}'
|
||||
<empty list>
|
||||
PsiWhiteSpace('\n ')
|
||||
LAMBDA_EXPRESSION
|
||||
FUNCTION_LITERAL
|
||||
PsiElement(LBRACE)('{')
|
||||
PsiWhiteSpace(' ')
|
||||
BLOCK
|
||||
STRING_TEMPLATE
|
||||
PsiElement(OPEN_QUOTE)('"')
|
||||
PsiElement(CLOSING_QUOTE)('"')
|
||||
PsiWhiteSpace(' ')
|
||||
PsiElement(RBRACE)('}')
|
||||
PsiWhiteSpace('\n')
|
||||
PsiElement(LONG_TEMPLATE_ENTRY_END)('}')
|
||||
PsiErrorElement:Expecting '"'
|
||||
<empty list>
|
||||
PsiErrorElement:Expecting '}'
|
||||
<empty list>
|
||||
@@ -2305,6 +2305,18 @@ public class ParsingTestGenerated extends AbstractParsingTest {
|
||||
doParsingTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lambdaExpressionInString_1.kt")
|
||||
public void testLambdaExpressionInString_1() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/psi/recovery/lambdaExpressionInString_1.kt");
|
||||
doParsingTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("lambdaExpressionInString_2.kt")
|
||||
public void testLambdaExpressionInString_2() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/psi/recovery/lambdaExpressionInString_2.kt");
|
||||
doParsingTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("MissingCommaInConstructorValueParameterList.kt")
|
||||
public void testMissingCommaInConstructorValueParameterList() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/psi/recovery/MissingCommaInConstructorValueParameterList.kt");
|
||||
|
||||
Reference in New Issue
Block a user