Write lambda expressions and local members parsing (light tree to FIR)

This commit is contained in:
Ivan Cilcic
2019-07-17 23:59:25 +03:00
committed by Mikhail Glukhikh
parent 50573066fe
commit 8dd72a5cf2
10 changed files with 365 additions and 74 deletions
@@ -46,6 +46,13 @@ class LightTree2Fir(
MyKotlinParser.parseBlockExpression(builder)
return builder.lightTree
}
fun buildLightTreeLambdaExpression(code: String): FlyweightCapableTreeStructure<LighterASTNode> {
val builder = PsiBuilderFactoryImpl().createBuilder(parserDefinition, lexer, code)
//KotlinParser.parseLambdaExpression(builder)
MyKotlinParser.parseLambdaExpression(builder)
return builder.lightTree
}
}
fun buildFirFile(path: Path): FirFile {
@@ -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<Array<LighterASTNode?>>()
return tree.getParent(this)
}
fun LighterASTNode?.getChildNodesByType(type: IElementType): List<LighterASTNode> {
return this?.forEachChildrenReturnList { node, container ->
when (node.tokenType) {
@@ -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<FirFunction>()
val firFunctionCalls = mutableListOf<FirFunctionCall>()
val firLabels = mutableListOf<FirLabel>()
fun <T> MutableList<T>.removeLast() {
removeAt(size - 1)
@@ -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<FirStatement>()
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<FirStatement>(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<ValueParameter>()
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<FirVariable>()
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<FirTypeParameter>()
val valueParametersList = mutableListOf<ValueParameter>()
var isReturnType = false
var receiverType: FirTypeRef? = null
var returnType: FirTypeRef? = null
val typeConstraints = mutableListOf<TypeConstraint>()
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<ValueParameter> {
fun convertValueParameters(valueParameters: LighterASTNode): List<ValueParameter> {
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)
}
}
@@ -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<ValueParameter>()
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("<destruct>"),
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<FirTypeProjection>()
val firValueArguments = mutableListOf<FirExpression>()
val valueArguments = mutableListOf<LighterASTNode>()
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}")
}
}
@@ -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,
@@ -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<FirVariable>
)
@@ -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
@@ -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
)
}
}
@@ -17,6 +17,12 @@ public class MyKotlinParser {
return builder.getLightTree();
}
public static FlyweightCapableTreeStructure<LighterASTNode> parseLambdaExpression(PsiBuilder psiBuilder) {
KotlinParsing ktParsing = KotlinParsing.createForTopLevel(new SemanticWhitespaceAwarePsiBuilderImpl(psiBuilder));
ktParsing.parseLambdaExpression();
return psiBuilder.getLightTree();
}
public static FlyweightCapableTreeStructure<LighterASTNode> parseBlockExpression(PsiBuilder builder) {
KotlinParsing ktParsing = KotlinParsing.createForTopLevel(new SemanticWhitespaceAwarePsiBuilderImpl(builder));
ktParsing.parseBlockExpression();