Write lambda expressions and local members parsing (light tree to FIR)
This commit is contained in:
committed by
Mikhail Glukhikh
parent
50573066fe
commit
8dd72a5cf2
@@ -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 {
|
||||
|
||||
+5
@@ -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) {
|
||||
|
||||
+2
@@ -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)
|
||||
|
||||
+98
-43
@@ -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)
|
||||
}
|
||||
}
|
||||
+129
-30
@@ -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}")
|
||||
}
|
||||
}
|
||||
+29
@@ -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,
|
||||
|
||||
+13
@@ -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
|
||||
|
||||
+72
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user