From 8dd72a5cf26cc1a7256f14299fdb2182790041e7 Mon Sep 17 00:00:00 2001 From: Ivan Cilcic Date: Wed, 17 Jul 2019 23:59:25 +0300 Subject: [PATCH] Write lambda expressions and local members parsing (light tree to FIR) --- .../kotlin/fir/lightTree/LightTree2Fir.kt | 7 + .../fir/lightTree/converter/BaseConverter.kt | 5 + .../fir/lightTree/converter/ConverterUtil.kt | 2 + .../converter/DeclarationsConverter.kt | 141 +++++++++++----- .../converter/ExpressionsConverter.kt | 159 ++++++++++++++---- .../converter/utils/ExpressionUtil.kt | 29 ++++ .../lightTree/fir/DestructuringDeclaration.kt | 13 ++ .../fir/lightTree/fir/ValueParameter.kt | 5 +- .../fir/lightTree/compare/TreesCompareTest.kt | 72 ++++++++ .../kotlin/parsing/MyKotlinParser.java | 6 + 10 files changed, 365 insertions(+), 74 deletions(-) create mode 100644 compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/DestructuringDeclaration.kt diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/LightTree2Fir.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/LightTree2Fir.kt index 7fea00a939a..fcfab7c2845 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/LightTree2Fir.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/LightTree2Fir.kt @@ -46,6 +46,13 @@ class LightTree2Fir( MyKotlinParser.parseBlockExpression(builder) return builder.lightTree } + + fun buildLightTreeLambdaExpression(code: String): FlyweightCapableTreeStructure { + val builder = PsiBuilderFactoryImpl().createBuilder(parserDefinition, lexer, code) + //KotlinParser.parseLambdaExpression(builder) + MyKotlinParser.parseLambdaExpression(builder) + return builder.lightTree + } } fun buildFirFile(path: Path): FirFile { diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/BaseConverter.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/BaseConverter.kt index 1200780f3ed..fa66449328f 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/BaseConverter.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/BaseConverter.kt @@ -26,6 +26,11 @@ open class BaseConverter( protected val implicitAnnotationType = FirImplicitAnnotationTypeRef(session, null) protected val implicitType = FirImplicitTypeRefImpl(session, null) + fun LighterASTNode.getParent(): LighterASTNode? { + val kidsRef = Ref>() + return tree.getParent(this) + } + fun LighterASTNode?.getChildNodesByType(type: IElementType): List { return this?.forEachChildrenReturnList { node, container -> when (node.tokenType) { diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/ConverterUtil.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/ConverterUtil.kt index aadf1f25c16..ea468ebead8 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/ConverterUtil.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/ConverterUtil.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.FirFunctionTarget +import org.jetbrains.kotlin.fir.FirLabel import org.jetbrains.kotlin.fir.FirReference import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.declarations.* @@ -201,6 +202,7 @@ object ClassNameUtil { object FunctionUtil { val firFunctions = mutableListOf() val firFunctionCalls = mutableListOf() + val firLabels = mutableListOf() fun MutableList.removeLast() { removeAt(size - 1) diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt index 861ab2abb73..ff8b5c33180 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.fir.lightTree.converter.DataClassUtil.generateCompon import org.jetbrains.kotlin.fir.lightTree.converter.DataClassUtil.generateCopyFunction import org.jetbrains.kotlin.fir.lightTree.converter.FunctionUtil.removeLast import org.jetbrains.kotlin.fir.lightTree.fir.ClassWrapper +import org.jetbrains.kotlin.fir.lightTree.fir.DestructuringDeclaration import org.jetbrains.kotlin.fir.lightTree.fir.TypeConstraint import org.jetbrains.kotlin.fir.lightTree.fir.ValueParameter import org.jetbrains.kotlin.fir.lightTree.fir.modifier.Modifier @@ -97,12 +98,20 @@ class DeclarationsConverter( /** * @see org.jetbrains.kotlin.parsing.KotlinParsing.parseBlockExpression */ - private fun convertBlockExpression(block: LighterASTNode): FirBlock { + fun convertBlockExpression(block: LighterASTNode): FirBlock { val firStatements = mutableListOf() block.forEachChildren { when (it.tokenType) { //TODO("not implemented") BLOCK -> "" + + CLASS -> firStatements += convertClass(it) as FirStatement + FUN -> firStatements += convertFunctionDeclaration(it) as FirStatement + PROPERTY -> firStatements += convertPropertyDeclaration(it) as FirStatement + TYPEALIAS -> firStatements += convertTypeAlias(it) as FirStatement + OBJECT_DECLARATION -> firStatements += convertClass(it) as FirStatement + CLASS_INITIALIZER -> firStatements += convertAnonymousInitializer(it) as FirStatement + else -> if (it.isExpression()) firStatements += expressionConverter.getAsFirExpression(it) } } @@ -371,7 +380,7 @@ class DeclarationsConverter( null, FirClassSymbol(ClassNameUtil.currentClassId), className, - if (FunctionUtil.firFunctions.isNotEmpty()) Visibilities.LOCAL else modifiers.getVisibility(), + if (classNode.getParent()?.tokenType == BLOCK) Visibilities.LOCAL else modifiers.getVisibility(), modifiers.getModality(), modifiers.hasExpect(), modifiers.hasActual(), @@ -569,14 +578,14 @@ class DeclarationsConverter( var modifiers = Modifier(session) val firValueParameters = mutableListOf() var constructorDelegationCall: FirDelegatedConstructorCall? = null - var firBlock: FirBlock? = null + var block: LighterASTNode? = null secondaryConstructor.forEachChildren { when (it.tokenType) { MODIFIER_LIST -> modifiers = convertModifierList(it) VALUE_PARAMETER_LIST -> firValueParameters += convertValueParameters(it) CONSTRUCTOR_DELEGATION_CALL -> constructorDelegationCall = convertConstructorDelegationCall(it, classWrapper) - BLOCK -> firBlock = visitBlock(it) + BLOCK -> block = it } } @@ -595,7 +604,7 @@ class DeclarationsConverter( firConstructor.annotations += modifiers.annotations firConstructor.typeParameters += ConverterUtil.typeParametersFromSelfType(classWrapper.delegatedSelfTypeRef) firConstructor.valueParameters += firValueParameters.map { it.firValueParameter } - firConstructor.body = visitFunctionBody(firBlock, null) + firConstructor.body = visitFunctionBody(block, null) FunctionUtil.firFunctions.removeLast() return firConstructor } @@ -704,7 +713,7 @@ class DeclarationsConverter( val propertyName = identifier.nameAsSafeName() - return if (FunctionUtil.firFunctions.isNotEmpty()) { + return if (property.getParent()?.tokenType == BLOCK) { FirVariableImpl( session, null, @@ -742,6 +751,44 @@ class DeclarationsConverter( } } + /** + * @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitDestructuringDeclaration + */ + private fun convertDestructingDeclaration(destructingDeclaration: LighterASTNode): DestructuringDeclaration { + var isVar = false + val entries = mutableListOf() + destructingDeclaration.forEachChildren { + when (it.tokenType) { + VAR_KEYWORD -> isVar = true + DESTRUCTURING_DECLARATION_ENTRY -> entries += convertDestructingDeclarationEntry(it) + } + } + + return DestructuringDeclaration(isVar, entries) + } + + /** + * @see org.jetbrains.kotlin.parsing.KotlinParsing.parseMultiDeclarationName + */ + private fun convertDestructingDeclarationEntry(entry: LighterASTNode): FirVariable { + var modifiers = Modifier(session) + lateinit var identifier: String + var firType: FirTypeRef? = null + entry.forEachChildren { + when (it.tokenType) { + MODIFIER_LIST -> modifiers = convertModifierList(it) + IDENTIFIER -> identifier = it.getAsString() + TYPE_REFERENCE -> firType = convertType(it) + } + } + + return FirVariableImpl( + session, null, identifier.nameAsSafeName(), firType ?: implicitType, false, null + ).apply { + annotations += modifiers.annotations + } + } + /** * @see org.jetbrains.kotlin.parsing.KotlinParsing.parsePropertyGetterOrSetter */ @@ -750,7 +797,7 @@ class DeclarationsConverter( var isGetter = true var returnType: FirTypeRef? = null var firValueParameters: FirValueParameter = FirDefaultSetterValueParameter(session, null, propertyTypeRef) - var firBlock: FirBlock? = null + var block: LighterASTNode? = null var firExpression: FirExpression? = null getterOrSetter.forEachChildren { if (it.getAsString() == "set") isGetter = false @@ -759,7 +806,7 @@ class DeclarationsConverter( MODIFIER_LIST -> modifiers = convertModifierList(it) TYPE_REFERENCE -> returnType = convertType(it) VALUE_PARAMETER_LIST -> firValueParameters = convertSetterParameter(it, propertyTypeRef) - BLOCK -> firBlock = visitBlock(it) + BLOCK -> block = it else -> if (it.isExpression()) firExpression = expressionConverter.getAsFirExpression(it) } } @@ -778,7 +825,7 @@ class DeclarationsConverter( firAccessor.valueParameters += firValueParameters } - firAccessor.body = visitFunctionBody(firBlock, firExpression) + firAccessor.body = visitFunctionBody(block, firExpression) FunctionUtil.firFunctions.removeLast() return firAccessor } @@ -816,16 +863,16 @@ class DeclarationsConverter( /** * @see org.jetbrains.kotlin.parsing.KotlinParsing.parseFunction */ - private fun convertFunctionDeclaration(functionDeclaration: LighterASTNode): FirDeclaration { + fun convertFunctionDeclaration(functionDeclaration: LighterASTNode): FirDeclaration { var modifiers = Modifier(session) - lateinit var identifier: String + var identifier: String? = null val firTypeParameters = mutableListOf() val valueParametersList = mutableListOf() var isReturnType = false var receiverType: FirTypeRef? = null var returnType: FirTypeRef? = null val typeConstraints = mutableListOf() - var firBlock: FirBlock? = null + var block: LighterASTNode? = null var firExpression: FirExpression? = null functionDeclaration.forEachChildren { when (it.tokenType) { @@ -836,47 +883,53 @@ class DeclarationsConverter( COLON -> isReturnType = true TYPE_REFERENCE -> if (isReturnType) returnType = convertType(it) else receiverType = convertType(it) TYPE_CONSTRAINT_LIST -> typeConstraints += convertTypeConstraints(it) - BLOCK -> firBlock = visitBlock(it) + BLOCK -> block = it else -> if (it.isExpression()) firExpression = expressionConverter.getAsFirExpression(it) } } if (returnType == null) { returnType = - if (firBlock != null || (firBlock == null && firExpression == null)) implicitUnitType + if (block != null || (block == null && firExpression == null)) implicitUnitType else implicitType } - val functionName = identifier.nameAsSafeName() - val isLocal = FunctionUtil.firFunctions.isNotEmpty() - val firFunction = FirMemberFunctionImpl( - session, - null, - FirFunctionSymbol(ClassNameUtil.callableIdForName(functionName, isLocal)), - functionName, - modifiers.getVisibility(), - modifiers.getModality(), - modifiers.hasExpect(), - modifiers.hasActual(), - modifiers.hasOverride(), - modifiers.hasOperator(), - modifiers.hasInfix(), - modifiers.hasInline(), - modifiers.hasTailrec(), - modifiers.hasExternal(), - modifiers.hasSuspend(), - receiverType, - returnType!! - ) + val isLocal = functionDeclaration.getParent()?.tokenType == BLOCK + val firFunction = if (identifier == null) { + FirAnonymousFunctionImpl(session, null, returnType!!, receiverType) + } else { + val functionName = identifier.nameAsSafeName() + FirMemberFunctionImpl( + session, + null, + FirFunctionSymbol(ClassNameUtil.callableIdForName(functionName, isLocal)), + functionName, + modifiers.getVisibility(), + modifiers.getModality(), + modifiers.hasExpect(), + modifiers.hasActual(), + modifiers.hasOverride(), + modifiers.hasOperator(), + modifiers.hasInfix(), + modifiers.hasInline(), + modifiers.hasTailrec(), + modifiers.hasExternal(), + modifiers.hasSuspend(), + receiverType, + returnType!! + ) + } FunctionUtil.firFunctions += firFunction firFunction.annotations += modifiers.annotations - firFunction.typeParameters += firTypeParameters - firFunction.joinTypeParameters(typeConstraints) + if (firFunction is FirMemberFunctionImpl) { + firFunction.typeParameters += firTypeParameters + firFunction.joinTypeParameters(typeConstraints) + } firFunction.valueParameters += valueParametersList.map { it.firValueParameter } - firFunction.body = visitFunctionBody(firBlock, firExpression) + firFunction.body = visitFunctionBody(block, firExpression) FunctionUtil.firFunctions.removeLast() return firFunction } @@ -885,10 +938,10 @@ class DeclarationsConverter( * @see org.jetbrains.kotlin.parsing.KotlinParsing.parseFunctionBody * @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.buildFirBody */ - private fun visitFunctionBody(firBlock: FirBlock?, firExpression: FirExpression?): FirBlock? { + private fun visitFunctionBody(blockNode: LighterASTNode?, firExpression: FirExpression?): FirBlock? { return when { - firBlock != null -> if (!stubMode) { - return firBlock + blockNode != null -> if (!stubMode) { + return visitBlock(blockNode) } else { FirSingleExpressionBlock( session, @@ -1205,7 +1258,7 @@ class DeclarationsConverter( /** * @see org.jetbrains.kotlin.parsing.KotlinParsing.parseValueParameterList */ - private fun convertValueParameters(valueParameters: LighterASTNode): List { + fun convertValueParameters(valueParameters: LighterASTNode): List { return valueParameters.forEachChildrenReturnList { node, container -> when (node.tokenType) { VALUE_PARAMETER -> container += convertValueParameter(node) @@ -1223,6 +1276,7 @@ class DeclarationsConverter( var identifier: String? = null var firType: FirTypeRef? = null var firExpression: FirExpression? = null + var destructuringDeclaration: DestructuringDeclaration? = null valueParameter.forEachChildren { when (it.tokenType) { MODIFIER_LIST -> modifiers = convertModifierList(it) @@ -1230,6 +1284,7 @@ class DeclarationsConverter( VAR_KEYWORD -> isVar = true IDENTIFIER -> identifier = it.getAsString() TYPE_REFERENCE -> firType = convertType(it) + DESTRUCTURING_DECLARATION -> destructuringDeclaration = convertDestructingDeclaration(it) else -> if (it.isExpression()) firExpression = expressionConverter.getAsFirExpression(it) } } @@ -1244,6 +1299,6 @@ class DeclarationsConverter( isNoinline = modifiers.hasNoinline(), isVararg = modifiers.hasVararg() ).apply { annotations += modifiers.annotations } - return ValueParameter(isVal, isVar, modifiers, firValueParameter) + return ValueParameter(isVal, isVar, modifiers, firValueParameter, destructuringDeclaration) } } \ No newline at end of file diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt index e778bfa5051..0ae36fb9d7c 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/ExpressionsConverter.kt @@ -12,15 +12,22 @@ import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirReference import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.builder.* +import org.jetbrains.kotlin.fir.declarations.impl.FirAnonymousFunctionImpl +import org.jetbrains.kotlin.fir.declarations.impl.FirValueParameterImpl import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.impl.* +import org.jetbrains.kotlin.fir.labels.FirLabelImpl +import org.jetbrains.kotlin.fir.lightTree.LightTree2Fir import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.getAsString import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.isExpression import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.nameAsSafeName import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.getAsStringUnescapedValue import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.extractArgumentsFrom +import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.toReturn import org.jetbrains.kotlin.fir.lightTree.converter.FunctionUtil.removeLast +import org.jetbrains.kotlin.fir.lightTree.converter.FunctionUtil.pop import org.jetbrains.kotlin.fir.lightTree.converter.utils.* +import org.jetbrains.kotlin.fir.lightTree.fir.ValueParameter import org.jetbrains.kotlin.fir.references.FirErrorNamedReference import org.jetbrains.kotlin.fir.references.FirExplicitSuperReference import org.jetbrains.kotlin.fir.references.FirExplicitThisReference @@ -28,8 +35,11 @@ import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.types.FirTypeProjection import org.jetbrains.kotlin.fir.types.FirTypeRef +import org.jetbrains.kotlin.fir.types.impl.FirImplicitTypeRefImpl import org.jetbrains.kotlin.ir.expressions.IrConstKind import org.jetbrains.kotlin.lexer.KtTokens.* +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.psi.KtLambdaExpression import org.jetbrains.kotlin.psi.stubs.elements.KtConstantExpressionElementType import org.jetbrains.kotlin.resolve.constants.evaluate.* import org.jetbrains.kotlin.types.expressions.OperatorConventions @@ -50,9 +60,14 @@ class ExpressionsConverter( fun convertExpression(expression: LighterASTNode): FirElement { if (!stubMode) { return when (expression.tokenType) { + LAMBDA_EXPRESSION -> { + val lambdaTree = LightTree2Fir.buildLightTreeLambdaExpression(expression.getAsString()) + ExpressionsConverter(session, stubMode, lambdaTree, declarationsConverter).convertLambdaExpression(lambdaTree.root) + } BINARY_EXPRESSION -> convertBinaryExpression(expression) BINARY_WITH_TYPE -> convertBinaryWithType(expression) IS_EXPRESSION -> convertIsExpression(expression) + LABELED_EXPRESSION -> convertLabeledExpression(expression) PREFIX_EXPRESSION, POSTFIX_EXPRESSION -> convertUnaryExpression(expression) ANNOTATED_EXPRESSION -> convertAnnotatedExpression(expression) CLASS_LITERAL_EXPRESSION -> convertClassLiteralExpression(expression) @@ -64,9 +79,12 @@ class ExpressionsConverter( STRING_TEMPLATE -> convertStringTemplate(expression) is KtConstantExpressionElementType -> convertConstantExpression(expression) REFERENCE_EXPRESSION -> convertSimpleNameExpression(expression) + RETURN -> convertReturn(expression) PARENTHESIZED, PROPERTY_DELEGATE, INDICES -> convertExpression(expression.getExpressionInParentheses()) THIS_EXPRESSION -> convertThisExpression(expression) SUPER_EXPRESSION -> convertSuperExpression(expression) + + FUN -> declarationsConverter.convertFunctionDeclaration(expression) else -> FirExpressionStub(session, null) } //TODO("not fully implemented") @@ -75,6 +93,60 @@ class ExpressionsConverter( return FirExpressionStub(session, null) } + private fun convertLambdaExpression(lambdaExpression: LighterASTNode): FirExpression { + val valueParameterList = mutableListOf() + lateinit var block: LighterASTNode + lambdaExpression.getChildNodesByType(FUNCTION_LITERAL).first().forEachChildren { + when (it.tokenType) { + VALUE_PARAMETER_LIST -> valueParameterList += declarationsConverter.convertValueParameters(it) + BLOCK -> block = it + } + } + + return FirAnonymousFunctionImpl(session, null, implicitType, implicitType).apply { + FunctionUtil.firFunctions += this + var destructuringBlock: FirExpression? = null + for (valueParameter in valueParameterList) { + val multiDeclaration = valueParameter.destructuringDeclaration + valueParameters += if (multiDeclaration != null) { + val multiParameter = FirValueParameterImpl( + this@ExpressionsConverter.session, null, Name.special(""), + FirImplicitTypeRefImpl(this@ExpressionsConverter.session, null), + defaultValue = null, isCrossinline = false, isNoinline = false, isVararg = false + ) + destructuringBlock = generateDestructuringBlock( + this@ExpressionsConverter.session, + multiDeclaration, + multiParameter, + tmpVariable = false + ) + multiParameter + } else { + valueParameter.firValueParameter + } + } + label = FunctionUtil.firLabels.pop() ?: FunctionUtil.firFunctionCalls.lastOrNull()?.calleeReference?.name?.let { + FirLabelImpl(this@ExpressionsConverter.session, null, it.asString()) + } + val bodyExpression = declarationsConverter.convertBlockExpression(block) + body = if (bodyExpression is FirBlockImpl) { + if (bodyExpression.statements.isEmpty()) { + bodyExpression.statements.add(FirUnitExpression(this@ExpressionsConverter.session, null)) + } + if (destructuringBlock is FirBlock) { + for ((index, statement) in destructuringBlock.statements.withIndex()) { + bodyExpression.statements.add(index, statement) + } + } + bodyExpression + } else { + FirSingleExpressionBlock(this@ExpressionsConverter.session, bodyExpression.toReturn()) + } + + FunctionUtil.firFunctions.removeLast() + } + } + /** * @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseBinaryExpression * @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitBinaryExpression @@ -181,6 +253,27 @@ class ExpressionsConverter( } } + /** + * @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseLabeledExpression + * @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitLabeledExpression + */ + private fun convertLabeledExpression(labeledExpression: LighterASTNode): FirElement { + val size = FunctionUtil.firLabels.size + var firExpression: FirElement? = null + labeledExpression.forEachChildren { + when (it.tokenType) { + LABEL_QUALIFIER -> FunctionUtil.firLabels += FirLabelImpl(session, null, it.toString().replace("@", "")) + else -> if (it.isExpression()) firExpression = getAsFirExpression(it) + } + } + + if (size != FunctionUtil.firLabels.size) { + FunctionUtil.firLabels.removeLast() + //println("Unused label: ${labeledExpression.getAsString()}") + } + return firExpression ?: FirErrorExpressionImpl(session, null, "Empty label") + } + /** * @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parsePostfixExpression * @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parsePrefixExpression @@ -322,14 +415,13 @@ class ExpressionsConverter( private fun convertCallExpression(callSuffix: LighterASTNode): FirExpression { var name: String? = null val firTypeArguments = mutableListOf() - val firValueArguments = mutableListOf() + val valueArguments = mutableListOf() var additionalArgument: FirExpression? = null callSuffix.forEachChildren { when (it.tokenType) { REFERENCE_EXPRESSION -> name = it.getAsString() TYPE_ARGUMENT_LIST -> firTypeArguments += declarationsConverter.convertTypeArguments(it) - VALUE_ARGUMENT_LIST -> firValueArguments += convertValueArguments(it) - LAMBDA_ARGUMENT -> firValueArguments += convertAnnotatedLambda(it) + VALUE_ARGUMENT_LIST, LAMBDA_ARGUMENT -> valueArguments += it else -> additionalArgument = getAsFirExpression(it) } } @@ -345,26 +437,12 @@ class ExpressionsConverter( } this.calleeReference = calleeReference FunctionUtil.firFunctionCalls += this - this.extractArgumentsFrom(firValueArguments, stubMode) + this.extractArgumentsFrom(valueArguments.flatMap { convertValueArguments(it) }, stubMode) typeArguments += firTypeArguments FunctionUtil.firFunctionCalls.removeLast() } } - /** - * @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseAnnotatedLambda - */ - private fun convertAnnotatedLambda(annotatedLambda: LighterASTNode): FirExpression { - annotatedLambda.forEachChildren { - when (it.tokenType) { - LAMBDA_EXPRESSION -> "" - LABELED_EXPRESSION -> "" - ANNOTATED_EXPRESSION -> "" - } - } - return FirExpressionStub(session, null) - } - /** * @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseStringTemplate * @see org.jetbrains.kotlin.fir.builder.ConversionUtilsKt.toInterpolatingCall @@ -527,6 +605,24 @@ class ExpressionsConverter( } } + /** + * @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseReturn + * @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitReturnExpression + */ + private fun convertReturn(returnExpression: LighterASTNode): FirExpression { + var labelName: String? = null + var firExpression: FirExpression? = null + returnExpression.forEachChildren { + when (it.tokenType) { + LABEL_QUALIFIER -> labelName = it.getAsString().replace("@", "") + else -> if (it.isExpression()) firExpression = getAsFirExpression(it) + } + } + + val result = firExpression ?: FirUnitExpression(session, null) + return result.toReturn(labelName) + } + /** * @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseThisExpression * @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitThisExpression @@ -568,6 +664,9 @@ class ExpressionsConverter( return valueArguments.forEachChildrenReturnList { node, container -> when (node.tokenType) { VALUE_ARGUMENT -> container += convertValueArgument(node) + LAMBDA_EXPRESSION, + LABELED_EXPRESSION, + ANNOTATED_EXPRESSION -> container += FirLambdaArgumentExpressionImpl(session, null, getAsFirExpression(node)) } } } @@ -596,20 +695,20 @@ class ExpressionsConverter( } } + /** + * @see org.jetbrains.kotlin.fir.builder.ConversionUtilsKt.initializeLValue + */ fun convertLValue(leftArgNode: LighterASTNode, container: FirModifiableQualifiedAccess<*>): FirReference { - leftArgNode.forEachChildren { - return when (it.tokenType) { - THIS_EXPRESSION -> convertThisExpression(leftArgNode).calleeReference - REFERENCE_EXPRESSION -> FirSimpleNamedReference(session, null, it.getAsString().nameAsSafeName()) - in qualifiedAccessTokens -> (getAsFirExpression(it) as FirQualifiedAccess).let { firQualifiedAccess -> - container.explicitReceiver = firQualifiedAccess.explicitReceiver - container.safe = firQualifiedAccess.safe - return@let firQualifiedAccess.calleeReference - } - PARENTHESIZED -> convertLValue(it.getExpressionInParentheses(), container) - else -> FirErrorNamedReference(session, null, "Unsupported LValue: ${leftArgNode.tokenType}") + return when (leftArgNode.tokenType) { + THIS_EXPRESSION -> convertThisExpression(leftArgNode).calleeReference + REFERENCE_EXPRESSION -> FirSimpleNamedReference(session, null, leftArgNode.getAsString().nameAsSafeName()) + in qualifiedAccessTokens -> (getAsFirExpression(leftArgNode) as FirQualifiedAccess).let { firQualifiedAccess -> + container.explicitReceiver = firQualifiedAccess.explicitReceiver + container.safe = firQualifiedAccess.safe + return@let firQualifiedAccess.calleeReference } + PARENTHESIZED -> convertLValue(leftArgNode.getExpressionInParentheses(), container) + else -> FirErrorNamedReference(session, null, "Unsupported LValue: ${leftArgNode.tokenType}") } - return FirErrorNamedReference(session, null, "Unsupported LValue: ${leftArgNode.tokenType}") } } \ No newline at end of file diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/utils/ExpressionUtil.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/utils/ExpressionUtil.kt index 560b5d66cb5..b154fa4c1ac 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/utils/ExpressionUtil.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/converter/utils/ExpressionUtil.kt @@ -11,12 +11,16 @@ import com.intellij.psi.tree.TokenSet import org.jetbrains.kotlin.KtNodeTypes.* import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.builder.* +import org.jetbrains.kotlin.fir.declarations.impl.FirVariableImpl import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.impl.* import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.getAsString import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.nameAsSafeName import org.jetbrains.kotlin.fir.lightTree.converter.ExpressionsConverter +import org.jetbrains.kotlin.fir.lightTree.fir.DestructuringDeclaration import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference +import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol +import org.jetbrains.kotlin.fir.types.FirTypeRef import org.jetbrains.kotlin.lexer.KtSingleValueToken import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens.* @@ -143,6 +147,31 @@ fun ExpressionsConverter.generateIncrementOrDecrementBlock( } } +fun generateDestructuringBlock( + session: FirSession, + multiDeclaration: DestructuringDeclaration, + container: FirVariable, + tmpVariable: Boolean +): FirExpression { + return FirBlockImpl(session, null).apply { + if (tmpVariable) { + statements += container + } + val isVar = multiDeclaration.isVar + for ((index, entry) in multiDeclaration.entries.withIndex()) { + statements += FirVariableImpl( + session, null, entry.name, + entry.returnTypeRef, isVar, + FirComponentCallImpl(session, null, index + 1, generateResolvedAccessExpression(session, null, container)), + FirVariableSymbol(entry.name) // TODO? + ).apply { + annotations += entry.annotations + symbol.bind(this) + } + } + } +} + fun bangBangToWhen(session: FirSession, baseExpression: FirExpression): FirWhenExpression { return baseExpression.generateNotNullOrOther( session, diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/DestructuringDeclaration.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/DestructuringDeclaration.kt new file mode 100644 index 00000000000..a25361babfc --- /dev/null +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/DestructuringDeclaration.kt @@ -0,0 +1,13 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.fir.lightTree.fir + +import org.jetbrains.kotlin.fir.expressions.FirVariable + +data class DestructuringDeclaration( + val isVar: Boolean, + val entries: List +) \ No newline at end of file diff --git a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/ValueParameter.kt b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/ValueParameter.kt index 590043d161c..cce763dbf29 100644 --- a/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/ValueParameter.kt +++ b/compiler/fir/lightTree/src/org/jetbrains/kotlin/fir/lightTree/fir/ValueParameter.kt @@ -10,6 +10,8 @@ import org.jetbrains.kotlin.fir.declarations.FirValueParameter import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyGetter import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertySetter import org.jetbrains.kotlin.fir.declarations.impl.FirMemberPropertyImpl +import org.jetbrains.kotlin.fir.expressions.FirBlock +import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.impl.FirQualifiedAccessExpressionImpl import org.jetbrains.kotlin.fir.lightTree.converter.ClassNameUtil import org.jetbrains.kotlin.fir.lightTree.fir.modifier.Modifier @@ -20,7 +22,8 @@ class ValueParameter( private val isVal: Boolean, private val isVar: Boolean, private val modifiers: Modifier, - val firValueParameter: FirValueParameter + val firValueParameter: FirValueParameter, + val destructuringDeclaration: DestructuringDeclaration? = null ) { fun hasValOrVar(): Boolean { return isVal || isVar diff --git a/compiler/fir/lightTree/tests/org/jetbrains/kotlin/fir/lightTree/compare/TreesCompareTest.kt b/compiler/fir/lightTree/tests/org/jetbrains/kotlin/fir/lightTree/compare/TreesCompareTest.kt index 12c93915bae..5ab87d37664 100644 --- a/compiler/fir/lightTree/tests/org/jetbrains/kotlin/fir/lightTree/compare/TreesCompareTest.kt +++ b/compiler/fir/lightTree/tests/org/jetbrains/kotlin/fir/lightTree/compare/TreesCompareTest.kt @@ -186,4 +186,76 @@ class TreesCompareTest : AbstractRawFirBuilderTestCase() { visitCallableReferenceAccess = true ) } + + fun testLocalMembers() { + compare( + stubMode = false, + visitNamedFunction = true, + visitMemberDeclaration = true, + visitAnnotation = true, + visitTypeOperatorCall = true, + visitArrayOfCall = true, + visitFunctionCall = true, + visitGetClassCall = true, + visitConstExpression = true, + visitQualifiedAccessExpression = true, + visitCallableReferenceAccess = true + ) + } + + fun testReturn() { + compare( + stubMode = false, + visitNamedFunction = true, + visitMemberDeclaration = true, + visitAnnotation = true, + visitTypeOperatorCall = true, + visitArrayOfCall = true, + visitFunctionCall = true, + visitGetClassCall = true, + visitReturnExpression = true, + visitConstExpression = true, + visitQualifiedAccessExpression = true, + visitCallableReferenceAccess = true + ) + } + + fun testLambdaExpression() { + compare( + stubMode = false, + visitAnonymousFunction = true, + visitLambdaExpression = true, + visitNamedFunction = true, + visitMemberDeclaration = true, + visitAnnotation = true, + visitTypeOperatorCall = true, + visitArrayOfCall = true, + visitFunctionCall = true, + visitGetClassCall = true, + visitReturnExpression = true, + visitConstExpression = true, + visitQualifiedAccessExpression = true, + visitCallableReferenceAccess = true + ) + } + + fun testLambdaArgument() { + compare( + stubMode = false, + visitAnonymousFunction = true, + visitLambdaExpression = true, + visitNamedFunction = true, + visitMemberDeclaration = true, + visitAnnotation = true, + visitTypeOperatorCall = true, + visitArrayOfCall = true, + visitFunctionCall = true, + visitGetClassCall = true, + visitReturnExpression = true, + visitConstExpression = true, + visitQualifiedAccessExpression = true, + visitCallableReferenceAccess = true, + visitLambdaArgumentExpression = true + ) + } } diff --git a/compiler/psi/src/org/jetbrains/kotlin/parsing/MyKotlinParser.java b/compiler/psi/src/org/jetbrains/kotlin/parsing/MyKotlinParser.java index f69150776d4..518159fcbe6 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/parsing/MyKotlinParser.java +++ b/compiler/psi/src/org/jetbrains/kotlin/parsing/MyKotlinParser.java @@ -17,6 +17,12 @@ public class MyKotlinParser { 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();