From b07e4f26efe90b505722b9ab48805cde73068af3 Mon Sep 17 00:00:00 2001 From: Kirill Rakhman Date: Wed, 3 May 2023 16:21:28 +0200 Subject: [PATCH] [LT, Parsing] Parse blocks and lambdas eagerly for Light Tree --- .../kotlin/fir/lightTree/LightTree2Fir.kt | 19 ++----- .../fir/lightTree/converter/BaseConverter.kt | 6 +-- .../converter/DeclarationsConverter.kt | 20 +------ .../converter/ExpressionsConverter.kt | 54 +++++++------------ .../kotlin/parsing/AbstractKotlinParsing.java | 6 +++ .../parsing/KotlinExpressionParsing.java | 8 ++- .../kotlin/parsing/KotlinLightParser.java | 14 +---- .../kotlin/parsing/KotlinParsing.java | 25 +++++---- 8 files changed, 54 insertions(+), 98 deletions(-) diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/LightTree2Fir.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/LightTree2Fir.kt index 66c2795a666..096722be539 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/LightTree2Fir.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/LightTree2Fir.kt @@ -6,7 +6,7 @@ package org.jetbrains.kotlin.fir.lightTree import com.intellij.lang.LighterASTNode -import com.intellij.lang.impl.PsiBuilderFactoryImpl +import com.intellij.lang.PsiBuilderFactory import com.intellij.util.diff.FlyweightCapableTreeStructure import org.jetbrains.kotlin.KtIoFileSourceFile import org.jetbrains.kotlin.KtSourceFile @@ -36,22 +36,9 @@ class LightTree2Fir( private val parserDefinition = KotlinParserDefinition() private fun makeLexer() = KotlinLexer() - fun buildLightTreeBlockExpression(code: String): FlyweightCapableTreeStructure { - val builder = PsiBuilderFactoryImpl().createBuilder(parserDefinition, makeLexer(), code) - KotlinLightParser.parseBlockExpression(builder) - return builder.lightTree - } - - fun buildLightTreeLambdaExpression(code: String): FlyweightCapableTreeStructure { - val builder = PsiBuilderFactoryImpl().createBuilder(parserDefinition, makeLexer(), code) - KotlinLightParser.parseLambdaExpression(builder) - return builder.lightTree - } - fun buildLightTree(code: CharSequence): FlyweightCapableTreeStructure { - val builder = PsiBuilderFactoryImpl().createBuilder(parserDefinition, makeLexer(), code) - KotlinLightParser.parse(builder) - return builder.lightTree + val builder = PsiBuilderFactory.getInstance().createBuilder(parserDefinition, makeLexer(), code) + return KotlinLightParser.parse(builder) } } diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/BaseConverter.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/BaseConverter.kt index 4dd524a32ef..3134fd9f9e6 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/BaseConverter.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/BaseConverter.kt @@ -27,15 +27,13 @@ abstract class BaseConverter( val tree: FlyweightCapableTreeStructure, context: Context = Context() ) : BaseFirBuilder(baseSession, context) { - abstract val offset: Int - protected val implicitType = FirImplicitTypeRefImplWithoutSource protected open fun reportSyntaxError(node: LighterASTNode) {} override fun LighterASTNode.toFirSourceElement(kind: KtFakeSourceElementKind?): KtLightSourceElement { - val startOffset = offset + tree.getStartOffset(this) - val endOffset = offset + tree.getEndOffset(this) + val startOffset = tree.getStartOffset(this) + val endOffset = tree.getEndOffset(this) return toKtLightSourceElement(tree, kind ?: context.forcedElementSourceKind ?: KtRealSourceElementKind, startOffset, endOffset) } diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt index 8944f39b777..3093ecec2d5 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt @@ -69,23 +69,11 @@ class DeclarationsConverter( session: FirSession, internal val baseScopeProvider: FirScopeProvider, tree: FlyweightCapableTreeStructure, - @set:PrivateForInline override var offset: Int = 0, context: Context = Context(), private val diagnosticsReporter: DiagnosticReporter? = null, - private val diagnosticContext: DiagnosticContext? = null + private val diagnosticContext: DiagnosticContext? = null, ) : BaseConverter(session, tree, context) { - @OptIn(PrivateForInline::class) - inline fun withOffset(newOffset: Int, block: () -> R): R { - val oldOffset = offset - offset = newOffset - return try { - block() - } finally { - offset = oldOffset - } - } - private val expressionConverter = ExpressionsConverter(session, tree, this, context) override fun reportSyntaxError(node: LighterASTNode) { @@ -1809,11 +1797,7 @@ class DeclarationsConverter( ) } - val blockTree = LightTree2Fir.buildLightTreeBlockExpression(block.asText) - return DeclarationsConverter( - baseSession, baseScopeProvider, blockTree, offset = offset + tree.getStartOffset(block), context, - diagnosticsReporter, diagnosticContext - ).convertBlockExpression(blockTree.root) + return convertBlockExpression(block) } /** diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt index 7307802fbca..ece6946935f 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt @@ -58,10 +58,8 @@ class ExpressionsConverter( session: FirSession, tree: FlyweightCapableTreeStructure, private val declarationsConverter: DeclarationsConverter, - context: Context = Context() + context: Context = Context(), ) : BaseConverter(session, tree, context) { - override val offset: Int - get() = declarationsConverter.offset inline fun getAsFirExpression(expression: LighterASTNode?, errorReason: String = ""): R { val converted = expression?.let { convertExpression(it, errorReason) } @@ -76,17 +74,7 @@ class ExpressionsConverter( /***** EXPRESSIONS *****/ fun convertExpression(expression: LighterASTNode, errorReason: String): FirElement { return when (expression.tokenType) { - LAMBDA_EXPRESSION -> { - val lambdaTree = LightTree2Fir.buildLightTreeLambdaExpression(expression.asText) - // Pass on label user to the lambda root - context.forwardLabelUsagePermission(expression, lambdaTree.root) - val lambdaDeclarationsConverter = DeclarationsConverter( - baseSession, declarationsConverter.baseScopeProvider, lambdaTree, - offset = offset + expression.startOffset, context - ) - ExpressionsConverter(baseSession, lambdaTree, lambdaDeclarationsConverter, context) - .convertLambdaExpression(lambdaTree.root) - } + LAMBDA_EXPRESSION -> convertLambdaExpression(expression) BINARY_EXPRESSION -> convertBinaryExpression(expression) BINARY_WITH_TYPE -> convertBinaryWithTypeRHSExpression(expression) { this.getOperationSymbol().toFirOperation() @@ -200,29 +188,27 @@ class ExpressionsConverter( } body = if (block != null) { - declarationsConverter.withOffset(expressionSource.startOffset) { - declarationsConverter.convertBlockExpressionWithoutBuilding(block!!).apply { - statements.firstOrNull()?.let { - if (it.isContractBlockFirCheck()) { - this@buildAnonymousFunction.contractDescription = it.toLegacyRawContractDescription() - statements[0] = FirContractCallBlock(it) - } + declarationsConverter.convertBlockExpressionWithoutBuilding(block!!).apply { + statements.firstOrNull()?.let { + if (it.isContractBlockFirCheck()) { + this@buildAnonymousFunction.contractDescription = it.toLegacyRawContractDescription() + statements[0] = FirContractCallBlock(it) } + } - if (statements.isEmpty()) { - statements.add( - buildReturnExpression { - source = expressionSource.fakeElement(KtFakeSourceElementKind.ImplicitReturn.FromExpressionBody) - this.target = target - result = buildUnitExpression { - source = expressionSource.fakeElement(KtFakeSourceElementKind.ImplicitUnit) - } + if (statements.isEmpty()) { + statements.add( + buildReturnExpression { + source = expressionSource.fakeElement(KtFakeSourceElementKind.ImplicitReturn.FromExpressionBody) + this.target = target + result = buildUnitExpression { + source = expressionSource.fakeElement(KtFakeSourceElementKind.ImplicitUnit) } - ) - } - statements.addAll(0, destructuringStatements) - }.build() - } + } + ) + } + statements.addAll(0, destructuringStatements) + }.build() } else { buildSingleExpressionBlock(buildErrorExpression(null, ConeSimpleDiagnostic("Lambda has no body", DiagnosticKind.Syntax))) } diff --git a/compiler/psi/src/org/jetbrains/kotlin/parsing/AbstractKotlinParsing.java b/compiler/psi/src/org/jetbrains/kotlin/parsing/AbstractKotlinParsing.java index d6f4034135f..6d3e84afbd0 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/parsing/AbstractKotlinParsing.java +++ b/compiler/psi/src/org/jetbrains/kotlin/parsing/AbstractKotlinParsing.java @@ -51,9 +51,15 @@ import static org.jetbrains.kotlin.lexer.KtTokens.*; } protected final SemanticWhitespaceAwarePsiBuilder myBuilder; + protected final boolean isLazy; public AbstractKotlinParsing(SemanticWhitespaceAwarePsiBuilder builder) { + this(builder, true); + } + + public AbstractKotlinParsing(SemanticWhitespaceAwarePsiBuilder builder, boolean isLazy) { this.myBuilder = builder; + this.isLazy = isLazy; } protected IElementType getLastToken() { diff --git a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java index 931b5aa4b44..46c2d1a5f1a 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java +++ b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinExpressionParsing.java @@ -280,7 +280,11 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing { private final KotlinParsing myKotlinParsing; public KotlinExpressionParsing(SemanticWhitespaceAwarePsiBuilder builder, KotlinParsing kotlinParsing) { - super(builder); + this(builder, kotlinParsing, true); + } + + public KotlinExpressionParsing(SemanticWhitespaceAwarePsiBuilder builder, KotlinParsing kotlinParsing, boolean isLazy) { + super(builder, isLazy); myKotlinParsing = kotlinParsing; } @@ -1191,7 +1195,7 @@ public class KotlinExpressionParsing extends AbstractKotlinParsing { return; } - if (collapse) { + if (collapse && isLazy) { myKotlinParsing.advanceBalancedBlock(); literal.done(FUNCTION_LITERAL); literalExpression.collapse(LAMBDA_EXPRESSION); diff --git a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinLightParser.java b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinLightParser.java index 4e5172b37c6..17757df019f 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinLightParser.java +++ b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinLightParser.java @@ -11,21 +11,9 @@ import com.intellij.util.diff.FlyweightCapableTreeStructure; public class KotlinLightParser { public static FlyweightCapableTreeStructure parse(PsiBuilder builder) { - KotlinParsing ktParsing = KotlinParsing.createForTopLevel(new SemanticWhitespaceAwarePsiBuilderImpl(builder)); + KotlinParsing ktParsing = KotlinParsing.createForTopLevelNonLazy(new SemanticWhitespaceAwarePsiBuilderImpl(builder)); ktParsing.parseFile(); return builder.getLightTree(); } - - public static FlyweightCapableTreeStructure parseLambdaExpression(PsiBuilder psiBuilder) { - KotlinParsing ktParsing = KotlinParsing.createForTopLevel(new SemanticWhitespaceAwarePsiBuilderImpl(psiBuilder)); - ktParsing.parseLambdaExpression(); - return psiBuilder.getLightTree(); - } - - public static FlyweightCapableTreeStructure parseBlockExpression(PsiBuilder builder) { - KotlinParsing ktParsing = KotlinParsing.createForTopLevel(new SemanticWhitespaceAwarePsiBuilderImpl(builder)); - ktParsing.parseBlockExpression(); - return builder.getLightTree(); - } } diff --git a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java index 1bf9760b766..b1e896ad7e1 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java +++ b/compiler/psi/src/org/jetbrains/kotlin/parsing/KotlinParsing.java @@ -106,11 +106,15 @@ public class KotlinParsing extends AbstractKotlinParsing { private final static TokenSet CLASS_INTERFACE_SET = TokenSet.create(CLASS_KEYWORD, INTERFACE_KEYWORD); static KotlinParsing createForTopLevel(SemanticWhitespaceAwarePsiBuilder builder) { - return new KotlinParsing(builder, true); + return new KotlinParsing(builder, true, true); } - private static KotlinParsing createForByClause(SemanticWhitespaceAwarePsiBuilder builder) { - return new KotlinParsing(new SemanticWhitespaceAwarePsiBuilderForByClause(builder), false); + static KotlinParsing createForTopLevelNonLazy(SemanticWhitespaceAwarePsiBuilder builder) { + return new KotlinParsing(builder, true, false); + } + + private static KotlinParsing createForByClause(SemanticWhitespaceAwarePsiBuilder builder, boolean isLazy) { + return new KotlinParsing(new SemanticWhitespaceAwarePsiBuilderForByClause(builder), false, isLazy); } private final KotlinExpressionParsing myExpressionParsing; @@ -142,11 +146,11 @@ public class KotlinParsing extends AbstractKotlinParsing { } }); - private KotlinParsing(SemanticWhitespaceAwarePsiBuilder builder, boolean isTopLevel) { - super(builder); + private KotlinParsing(SemanticWhitespaceAwarePsiBuilder builder, boolean isTopLevel, boolean isLazy) { + super(builder, isLazy); myExpressionParsing = isTopLevel - ? new KotlinExpressionParsing(builder, this) - : new KotlinExpressionParsing(builder, this) { + ? new KotlinExpressionParsing(builder, this, isLazy) + : new KotlinExpressionParsing(builder, this, isLazy) { @Override protected boolean parseCallWithClosure() { if (((SemanticWhitespaceAwarePsiBuilderForByClause) builder).getStackSize() > 0) { @@ -157,7 +161,7 @@ public class KotlinParsing extends AbstractKotlinParsing { @Override protected KotlinParsing create(SemanticWhitespaceAwarePsiBuilder builder) { - return createForByClause(builder); + return createForByClause(builder, isLazy); } }; } @@ -1914,13 +1918,12 @@ public class KotlinParsing extends AbstractKotlinParsing { } private void parseBlock(boolean collapse) { - PsiBuilder.Marker lazyBlock = mark(); myBuilder.enableNewlines(); boolean hasOpeningBrace = expect(LBRACE, "Expecting '{' to open a block"); - boolean canCollapse = collapse && hasOpeningBrace; + boolean canCollapse = collapse && hasOpeningBrace && isLazy; if (canCollapse) { advanceBalancedBlock(); @@ -1997,7 +2000,7 @@ public class KotlinParsing extends AbstractKotlinParsing { if (at(BY_KEYWORD)) { reference.drop(); advance(); // BY_KEYWORD - createForByClause(myBuilder).myExpressionParsing.parseExpression(); + createForByClause(myBuilder, isLazy).myExpressionParsing.parseExpression(); delegator.done(DELEGATED_SUPER_TYPE_ENTRY); } else if (at(LPAR)) {