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:
Nikolay Krasko
2017-03-15 16:52:50 +03:00
parent 87ff70ee0f
commit afc0892d1f
6 changed files with 165 additions and 2 deletions
@@ -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");