Make KtLambdaExpression lazy parsable element

(cherry picked from commit 533fca1)
This commit is contained in:
Nikolay Krasko
2016-09-05 16:28:42 +03:00
committed by Nikolay Krasko
parent 1d24fc3a7b
commit 37492fcc78
5 changed files with 108 additions and 9 deletions
@@ -16,9 +16,20 @@
package org.jetbrains.kotlin;
import com.intellij.lang.ASTNode;
import com.intellij.lang.Language;
import com.intellij.lang.PsiBuilder;
import com.intellij.lang.PsiBuilderFactory;
import com.intellij.lexer.Lexer;
import com.intellij.openapi.project.Project;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.IErrorCounterReparseableElementType;
import com.intellij.psi.tree.IFileElementType;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.idea.KotlinLanguage;
import org.jetbrains.kotlin.lexer.KotlinLexer;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.parsing.KotlinParser;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes;
@@ -115,7 +126,48 @@ public interface KtNodeTypes {
KtNodeType LOOP_RANGE = new KtNodeType("LOOP_RANGE", KtContainerNode.class);
KtNodeType BODY = new KtNodeType("BODY", KtContainerNode.class);
KtNodeType BLOCK = new KtNodeType("BLOCK", KtBlockExpression.class);
KtNodeType LAMBDA_EXPRESSION = new KtNodeType("LAMBDA_EXPRESSION", KtLambdaExpression.class);
IElementType LAMBDA_EXPRESSION = new IErrorCounterReparseableElementType("LAMBDA_EXPRESSION", KotlinLanguage.INSTANCE) {
@Override
public ASTNode parseContents(ASTNode chameleon) {
Project project = chameleon.getPsi().getProject();
PsiBuilder builder = PsiBuilderFactory.getInstance().createBuilder(project, chameleon, null, KotlinLanguage.INSTANCE, chameleon.getChars());
return KotlinParser.parseLambdaExpression(builder).getFirstChildNode();
}
@Nullable
@Override
public ASTNode createNode(CharSequence text) {
return new KtLambdaExpression(text);
}
@Override
public int getErrorsCount(CharSequence seq, Language fileLanguage, Project project) {
Lexer lexer = new KotlinLexer();
lexer.start(seq);
if (lexer.getTokenType() != KtTokens.LBRACE) return IErrorCounterReparseableElementType.FATAL_ERROR;
lexer.advance();
int balance = 1;
while (true) {
IElementType type = lexer.getTokenType();
if (type == null) break;
if (balance == 0) {
return IErrorCounterReparseableElementType.FATAL_ERROR;
}
if (type == KtTokens.LBRACE) {
balance++;
}
else if (type == KtTokens.RBRACE) {
balance--;
}
lexer.advance();
}
return balance;
}
};
KtNodeType FUNCTION_LITERAL = new KtNodeType("FUNCTION_LITERAL", KtFunctionLiteral.class);
KtNodeType ANNOTATED_EXPRESSION = new KtNodeType("ANNOTATED_EXPRESSION", KtAnnotatedExpression.class);
@@ -573,7 +573,7 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
return false;
}
parseFunctionLiteral(preferBlock);
parseFunctionLiteral(preferBlock, /* collapse = */true);
doneOrDrop(labeled, LABELED_EXPRESSION, wasLabel);
doneOrDrop(annotated, ANNOTATED_EXPRESSION, wereAnnotations);
@@ -1033,10 +1033,10 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
* ;
*/
private void parseFunctionLiteral() {
parseFunctionLiteral(/* preferBlock = */false);
parseFunctionLiteral(/* preferBlock = */false, /* collapse = */true);
}
private void parseFunctionLiteral(boolean preferBlock) {
public void parseFunctionLiteral(boolean preferBlock, boolean collapse) {
assert _at(LBRACE);
PsiBuilder.Marker literalExpression = mark();
@@ -1088,7 +1088,12 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing {
myBuilder.restoreNewlinesState();
literal.done(FUNCTION_LITERAL);
literalExpression.done(LAMBDA_EXPRESSION);
if (collapse) {
literalExpression.collapse(LAMBDA_EXPRESSION);
}
else {
literalExpression.done(LAMBDA_EXPRESSION);
}
}
private boolean rollbackOrDropAt(PsiBuilder.Marker rollbackMarker, IElementType dropAt) {
@@ -73,4 +73,11 @@ public class KotlinParser implements PsiParser {
ktParsing.parseBlockCodeFragment();
return psiBuilder.getTreeBuilt();
}
@NotNull
public static ASTNode parseLambdaExpression(PsiBuilder psiBuilder) {
KotlinParsing ktParsing = KotlinParsing.createForTopLevel(new SemanticWhitespaceAwarePsiBuilderImpl(psiBuilder));
ktParsing.parseLambdaExpression();
return psiBuilder.getTreeBuilt();
}
}
@@ -156,6 +156,10 @@ public class KotlinParsing extends AbstractKotlinParsing {
marker.done(BLOCK_CODE_FRAGMENT);
}
void parseLambdaExpression() {
myExpressionParsing.parseFunctionLiteral(/* preferBlock = */ false, /* collapse = */false);
}
void parseScript() {
PsiBuilder.Marker fileMarker = mark();
@@ -17,6 +17,9 @@
package org.jetbrains.kotlin.psi;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElementVisitor;
import com.intellij.psi.PsiFile;
import com.intellij.psi.impl.source.tree.LazyParseablePsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.KtNodeTypes;
@@ -24,9 +27,9 @@ import org.jetbrains.kotlin.lexer.KtTokens;
import java.util.List;
public class KtLambdaExpression extends KtExpressionImpl {
public KtLambdaExpression(@NotNull ASTNode node) {
super(node);
public class KtLambdaExpression extends LazyParseablePsiElement implements KtExpression {
public KtLambdaExpression(CharSequence text) {
super(KtNodeTypes.LAMBDA_EXPRESSION, text);
}
@Override
@@ -36,7 +39,7 @@ public class KtLambdaExpression extends KtExpressionImpl {
@NotNull
public KtFunctionLiteral getFunctionLiteral() {
return (KtFunctionLiteral) findChildByType(KtNodeTypes.FUNCTION_LITERAL);
return findChildByType(KtNodeTypes.FUNCTION_LITERAL).getPsi(KtFunctionLiteral.class);
}
@NotNull
@@ -67,4 +70,32 @@ public class KtLambdaExpression extends KtExpressionImpl {
public ASTNode getRightCurlyBrace() {
return getFunctionLiteral().getNode().findChildByType(KtTokens.RBRACE);
}
@NotNull
@Override
public KtFile getContainingKtFile() {
PsiFile file = getContainingFile();
assert file instanceof KtFile : "KtElement not inside KtFile: " + file + " " + file.getText();
return (KtFile) file;
}
@Override
public <D> void acceptChildren(@NotNull KtVisitor<Void, D> visitor, D data) {
KtPsiUtil.visitChildren(this, visitor, data);
}
@Override
public final void accept(@NotNull PsiElementVisitor visitor) {
if (visitor instanceof KtVisitor) {
accept((KtVisitor) visitor, null);
}
else {
visitor.visitElement(this);
}
}
@Override
public String toString() {
return getNode().getElementType().toString();
}
}