Write annotation's conversion (light tree to FIR)
This commit is contained in:
committed by
Mikhail Glukhikh
parent
8bcea1cf85
commit
5a24c2253a
+7
-5
@@ -11,7 +11,9 @@ import com.intellij.psi.tree.IElementType
|
|||||||
import com.intellij.util.diff.FlyweightCapableTreeStructure
|
import com.intellij.util.diff.FlyweightCapableTreeStructure
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.types.impl.*
|
import org.jetbrains.kotlin.fir.types.impl.*
|
||||||
|
import org.jetbrains.kotlin.lexer.KtToken
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens.*
|
||||||
|
|
||||||
open class BaseConverter(
|
open class BaseConverter(
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
@@ -39,12 +41,12 @@ open class BaseConverter(
|
|||||||
return kidsRef.get()
|
return kidsRef.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected inline fun LighterASTNode.forEachChildren(f: (LighterASTNode) -> Unit) {
|
protected inline fun LighterASTNode.forEachChildren(vararg skipTokens: KtToken, f: (LighterASTNode) -> Unit) {
|
||||||
val kidsArray = this.getChildrenAsArray()
|
val kidsArray = this.getChildrenAsArray()
|
||||||
for (kid in kidsArray) {
|
for (kid in kidsArray) {
|
||||||
if (kid == null) continue
|
if (kid == null) break
|
||||||
val tokenType = kid.tokenType
|
val tokenType = kid.tokenType
|
||||||
if (KtTokens.COMMENTS.contains(tokenType) || tokenType == KtTokens.WHITE_SPACE || tokenType == KtTokens.SEMICOLON) continue
|
if (COMMENTS.contains(tokenType) || tokenType == WHITE_SPACE || tokenType == SEMICOLON || tokenType in skipTokens) continue
|
||||||
f(kid)
|
f(kid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,9 +56,9 @@ open class BaseConverter(
|
|||||||
|
|
||||||
val container = mutableListOf<T>()
|
val container = mutableListOf<T>()
|
||||||
for (kid in kidsArray) {
|
for (kid in kidsArray) {
|
||||||
if (kid == null) continue
|
if (kid == null) break
|
||||||
val tokenType = kid.tokenType
|
val tokenType = kid.tokenType
|
||||||
if (KtTokens.COMMENTS.contains(tokenType) || tokenType == KtTokens.WHITE_SPACE || tokenType == KtTokens.SEMICOLON) continue
|
if (COMMENTS.contains(tokenType) || tokenType == WHITE_SPACE || tokenType == SEMICOLON) continue
|
||||||
f(kid, container)
|
f(kid, container)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+19
-10
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.FirFunctionTarget
|
|||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.declarations.impl.*
|
import org.jetbrains.kotlin.fir.declarations.impl.*
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
|
import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.*
|
import org.jetbrains.kotlin.fir.expressions.impl.*
|
||||||
@@ -56,6 +57,10 @@ object ConverterUtil {
|
|||||||
return this.toString()
|
return this.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun LighterASTNode.getAsStringUnescapedValue(): String {
|
||||||
|
return this.toString().replaceFirst("\\", "")
|
||||||
|
}
|
||||||
|
|
||||||
fun LighterASTNode.isExpression(): Boolean {
|
fun LighterASTNode.isExpression(): Boolean {
|
||||||
return when (this.tokenType) {
|
return when (this.tokenType) {
|
||||||
is KtNodeType,
|
is KtNodeType,
|
||||||
@@ -139,8 +144,7 @@ object ConverterUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <T : FirCallWithArgumentList> T.extractArgumentsFrom(container: List<FirExpression>, stubMode: Boolean): T {
|
fun <T : FirCallWithArgumentList> T.extractArgumentsFrom(container: List<FirExpression>, stubMode: Boolean): T {
|
||||||
if (!stubMode) {
|
if (!stubMode || this is FirAnnotationCall) {
|
||||||
//TODO("not implemented")
|
|
||||||
this.arguments += container
|
this.arguments += container
|
||||||
}
|
}
|
||||||
return this
|
return this
|
||||||
@@ -165,7 +169,8 @@ object ClassNameUtil {
|
|||||||
val currentClassId
|
val currentClassId
|
||||||
get() = ClassId(
|
get() = ClassId(
|
||||||
packageFqName,
|
packageFqName,
|
||||||
className, false)
|
className, false
|
||||||
|
)
|
||||||
|
|
||||||
fun callableIdForName(name: Name, local: Boolean = false) =
|
fun callableIdForName(name: Name, local: Boolean = false) =
|
||||||
when {
|
when {
|
||||||
@@ -173,14 +178,16 @@ object ClassNameUtil {
|
|||||||
className == FqName.ROOT -> CallableId(packageFqName, name)
|
className == FqName.ROOT -> CallableId(packageFqName, name)
|
||||||
else -> CallableId(
|
else -> CallableId(
|
||||||
packageFqName,
|
packageFqName,
|
||||||
className, name)
|
className, name
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun callableIdForClassConstructor() =
|
fun callableIdForClassConstructor() =
|
||||||
if (className == FqName.ROOT) CallableId(packageFqName, Name.special("<anonymous-init>"))
|
if (className == FqName.ROOT) CallableId(packageFqName, Name.special("<anonymous-init>"))
|
||||||
else CallableId(
|
else CallableId(
|
||||||
packageFqName,
|
packageFqName,
|
||||||
className, className.shortName())
|
className, className.shortName()
|
||||||
|
)
|
||||||
|
|
||||||
var className: FqName = FqName.ROOT
|
var className: FqName = FqName.ROOT
|
||||||
}
|
}
|
||||||
@@ -257,11 +264,13 @@ object DataClassUtil {
|
|||||||
firPrimaryConstructor: FirConstructor,
|
firPrimaryConstructor: FirConstructor,
|
||||||
properties: List<FirProperty>
|
properties: List<FirProperty>
|
||||||
) {
|
) {
|
||||||
val symbol = FirFunctionSymbol(CallableId(
|
val symbol = FirFunctionSymbol(
|
||||||
ClassNameUtil.packageFqName,
|
CallableId(
|
||||||
ClassNameUtil.className,
|
ClassNameUtil.packageFqName,
|
||||||
copyName
|
ClassNameUtil.className,
|
||||||
))
|
copyName
|
||||||
|
)
|
||||||
|
)
|
||||||
firClass.addDeclaration(
|
firClass.addDeclaration(
|
||||||
FirMemberFunctionImpl(
|
FirMemberFunctionImpl(
|
||||||
session, null, symbol, copyName,
|
session, null, symbol, copyName,
|
||||||
|
|||||||
+29
-59
@@ -53,6 +53,7 @@ class DeclarationsConverter(
|
|||||||
private val stubMode: Boolean,
|
private val stubMode: Boolean,
|
||||||
tree: FlyweightCapableTreeStructure<LighterASTNode>
|
tree: FlyweightCapableTreeStructure<LighterASTNode>
|
||||||
) : BaseConverter(session, tree) {
|
) : BaseConverter(session, tree) {
|
||||||
|
private val expressionConverter = ExpressionsConverter(session, stubMode, tree)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [org.jetbrains.kotlin.parsing.KotlinParsing.parseFile]
|
* [org.jetbrains.kotlin.parsing.KotlinParsing.parseFile]
|
||||||
@@ -171,7 +172,7 @@ class DeclarationsConverter(
|
|||||||
modifiers.forEachChildren {
|
modifiers.forEachChildren {
|
||||||
when (it.tokenType) {
|
when (it.tokenType) {
|
||||||
ANNOTATION -> modifier.annotations += convertAnnotation(it)
|
ANNOTATION -> modifier.annotations += convertAnnotation(it)
|
||||||
ANNOTATION_ENTRY -> modifier.annotations += convertAnnotationEntry(it, null)
|
ANNOTATION_ENTRY -> modifier.annotations += convertAnnotationEntry(it)
|
||||||
is KtModifierKeywordToken -> modifier.addModifier(it)
|
is KtModifierKeywordToken -> modifier.addModifier(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -186,7 +187,7 @@ class DeclarationsConverter(
|
|||||||
modifiers.forEachChildren {
|
modifiers.forEachChildren {
|
||||||
when (it.tokenType) {
|
when (it.tokenType) {
|
||||||
ANNOTATION -> typeModifierList.annotations += convertAnnotation(it)
|
ANNOTATION -> typeModifierList.annotations += convertAnnotation(it)
|
||||||
ANNOTATION_ENTRY -> typeModifierList.annotations += convertAnnotationEntry(it, null)
|
ANNOTATION_ENTRY -> typeModifierList.annotations += convertAnnotationEntry(it)
|
||||||
is KtModifierKeywordToken -> typeModifierList.addModifier(it)
|
is KtModifierKeywordToken -> typeModifierList.addModifier(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,7 +202,7 @@ class DeclarationsConverter(
|
|||||||
modifiers.forEachChildren {
|
modifiers.forEachChildren {
|
||||||
when (it.tokenType) {
|
when (it.tokenType) {
|
||||||
ANNOTATION -> typeArgumentModifierList.annotations += convertAnnotation(it)
|
ANNOTATION -> typeArgumentModifierList.annotations += convertAnnotation(it)
|
||||||
ANNOTATION_ENTRY -> typeArgumentModifierList.annotations += convertAnnotationEntry(it, null)
|
ANNOTATION_ENTRY -> typeArgumentModifierList.annotations += convertAnnotationEntry(it)
|
||||||
is KtModifierKeywordToken -> typeArgumentModifierList.addModifier(it)
|
is KtModifierKeywordToken -> typeArgumentModifierList.addModifier(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -216,7 +217,7 @@ class DeclarationsConverter(
|
|||||||
modifiers.forEachChildren {
|
modifiers.forEachChildren {
|
||||||
when (it.tokenType) {
|
when (it.tokenType) {
|
||||||
ANNOTATION -> modifier.annotations += convertAnnotation(it)
|
ANNOTATION -> modifier.annotations += convertAnnotation(it)
|
||||||
ANNOTATION_ENTRY -> modifier.annotations += convertAnnotationEntry(it, null)
|
ANNOTATION_ENTRY -> modifier.annotations += convertAnnotationEntry(it)
|
||||||
is KtModifierKeywordToken -> modifier.addModifier(it)
|
is KtModifierKeywordToken -> modifier.addModifier(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -231,7 +232,7 @@ class DeclarationsConverter(
|
|||||||
return fileAnnotationList.forEachChildrenReturnList { node, container ->
|
return fileAnnotationList.forEachChildrenReturnList { node, container ->
|
||||||
when (node.tokenType) {
|
when (node.tokenType) {
|
||||||
ANNOTATION -> container += convertAnnotation(node)
|
ANNOTATION -> container += convertAnnotation(node)
|
||||||
ANNOTATION_ENTRY -> container += convertAnnotationEntry(node, AnnotationUseSiteTarget.FILE)
|
ANNOTATION_ENTRY -> container += convertAnnotationEntry(node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -250,12 +251,13 @@ class DeclarationsConverter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* org.jetbrains.kotlin.parsing.KotlinParsing.parseAnnotationTarget
|
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseAnnotationTarget
|
||||||
*/
|
*/
|
||||||
private fun convertAnnotationTarget(annotationUseSiteTarget: LighterASTNode): AnnotationUseSiteTarget {
|
private fun convertAnnotationTarget(annotationUseSiteTarget: LighterASTNode): AnnotationUseSiteTarget {
|
||||||
lateinit var annotationTarget: AnnotationUseSiteTarget
|
lateinit var annotationTarget: AnnotationUseSiteTarget
|
||||||
annotationUseSiteTarget.forEachChildren {
|
annotationUseSiteTarget.forEachChildren {
|
||||||
when (it.tokenType) {
|
when (it.tokenType) {
|
||||||
|
FIELD_KEYWORD -> annotationTarget = AnnotationUseSiteTarget.FIELD
|
||||||
FILE_KEYWORD -> annotationTarget = AnnotationUseSiteTarget.FILE
|
FILE_KEYWORD -> annotationTarget = AnnotationUseSiteTarget.FILE
|
||||||
PROPERTY_KEYWORD -> annotationTarget = AnnotationUseSiteTarget.PROPERTY
|
PROPERTY_KEYWORD -> annotationTarget = AnnotationUseSiteTarget.PROPERTY
|
||||||
GET_KEYWORD -> annotationTarget = AnnotationUseSiteTarget.PROPERTY_GETTER
|
GET_KEYWORD -> annotationTarget = AnnotationUseSiteTarget.PROPERTY_GETTER
|
||||||
@@ -276,18 +278,22 @@ class DeclarationsConverter(
|
|||||||
*/
|
*/
|
||||||
private fun convertAnnotationEntry(
|
private fun convertAnnotationEntry(
|
||||||
unescapedAnnotation: LighterASTNode,
|
unescapedAnnotation: LighterASTNode,
|
||||||
annotationUseSiteTarget: AnnotationUseSiteTarget?
|
defaultAnnotationUseSiteTarget: AnnotationUseSiteTarget? = null
|
||||||
): FirAnnotationCall {
|
): FirAnnotationCall {
|
||||||
//TODO not implemented
|
var annotationUseSiteTarget: AnnotationUseSiteTarget? = null
|
||||||
val pair = convertConstructorInvocation(unescapedAnnotation)
|
lateinit var constructorCalleePair: Pair<FirTypeRef, List<FirExpression>>
|
||||||
|
unescapedAnnotation.forEachChildren {
|
||||||
|
when (it.tokenType) {
|
||||||
|
ANNOTATION_TARGET -> annotationUseSiteTarget = convertAnnotationTarget(it)
|
||||||
|
CONSTRUCTOR_CALLEE -> constructorCalleePair = convertConstructorInvocation(unescapedAnnotation)
|
||||||
|
}
|
||||||
|
}
|
||||||
return FirAnnotationCallImpl(
|
return FirAnnotationCallImpl(
|
||||||
session,
|
session,
|
||||||
null,
|
null,
|
||||||
annotationUseSiteTarget,
|
annotationUseSiteTarget ?: defaultAnnotationUseSiteTarget,
|
||||||
pair.first
|
constructorCalleePair.first
|
||||||
).apply {
|
).extractArgumentsFrom(constructorCalleePair.second, stubMode)
|
||||||
arguments += pair.second
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** DECLARATIONS *****/
|
/***** DECLARATIONS *****/
|
||||||
@@ -566,10 +572,11 @@ class DeclarationsConverter(
|
|||||||
classWrapper: ClassWrapper
|
classWrapper: ClassWrapper
|
||||||
): FirDelegatedConstructorCallImpl {
|
): FirDelegatedConstructorCallImpl {
|
||||||
var thisKeywordPresent = false
|
var thisKeywordPresent = false
|
||||||
|
val firValueArguments = mutableListOf<FirExpression>()
|
||||||
constructorDelegationCall.forEachChildren {
|
constructorDelegationCall.forEachChildren {
|
||||||
when (it.tokenType) {
|
when (it.tokenType) {
|
||||||
CONSTRUCTOR_DELEGATION_REFERENCE -> if (it.getAsString() == "this") thisKeywordPresent = true
|
CONSTRUCTOR_DELEGATION_REFERENCE -> if (it.getAsString() == "this") thisKeywordPresent = true
|
||||||
VALUE_ARGUMENT_LIST -> "" //TODO implement
|
VALUE_ARGUMENT_LIST -> firValueArguments += expressionConverter.convertValueArguments(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -585,7 +592,7 @@ class DeclarationsConverter(
|
|||||||
null,
|
null,
|
||||||
delegatedType,
|
delegatedType,
|
||||||
isThis
|
isThis
|
||||||
).extractArgumentsFrom(listOf(), stubMode) //TODO implement
|
).extractArgumentsFrom(firValueArguments, stubMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -654,7 +661,7 @@ class DeclarationsConverter(
|
|||||||
val propertyAccessor = convertGetterOrSetter(it, returnType)
|
val propertyAccessor = convertGetterOrSetter(it, returnType)
|
||||||
if (propertyAccessor.isGetter) getter = propertyAccessor else setter = propertyAccessor
|
if (propertyAccessor.isGetter) getter = propertyAccessor else setter = propertyAccessor
|
||||||
}
|
}
|
||||||
else -> if (it.isExpression()) firExpression = visitExpression(it)
|
else -> if (it.isExpression()) firExpression = expressionConverter.visitExpression(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -724,7 +731,7 @@ class DeclarationsConverter(
|
|||||||
TYPE_REFERENCE -> returnType = convertType(it)
|
TYPE_REFERENCE -> returnType = convertType(it)
|
||||||
VALUE_PARAMETER_LIST -> firValueParameters = convertSetterParameter(it, propertyTypeRef)
|
VALUE_PARAMETER_LIST -> firValueParameters = convertSetterParameter(it, propertyTypeRef)
|
||||||
BLOCK -> firBlock = visitBlock(it)
|
BLOCK -> firBlock = visitBlock(it)
|
||||||
else -> if (it.isExpression()) firExpression = visitExpression(it)
|
else -> if (it.isExpression()) firExpression = expressionConverter.visitExpression(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -801,7 +808,7 @@ class DeclarationsConverter(
|
|||||||
TYPE_REFERENCE -> if (isReturnType) returnType = convertType(it) else receiverType = convertType(it)
|
TYPE_REFERENCE -> if (isReturnType) returnType = convertType(it) else receiverType = convertType(it)
|
||||||
TYPE_CONSTRAINT_LIST -> typeConstraints += convertTypeConstraints(it)
|
TYPE_CONSTRAINT_LIST -> typeConstraints += convertTypeConstraints(it)
|
||||||
BLOCK -> firBlock = visitBlock(it)
|
BLOCK -> firBlock = visitBlock(it)
|
||||||
else -> if (it.isExpression()) firExpression = visitExpression(it)
|
else -> if (it.isExpression()) firExpression = expressionConverter.visitExpression(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -923,7 +930,7 @@ class DeclarationsConverter(
|
|||||||
constructorInvocation.forEachChildren {
|
constructorInvocation.forEachChildren {
|
||||||
when (it.tokenType) {
|
when (it.tokenType) {
|
||||||
CONSTRUCTOR_CALLEE -> firTypeRef = convertType(it)
|
CONSTRUCTOR_CALLEE -> firTypeRef = convertType(it)
|
||||||
VALUE_ARGUMENT_LIST -> firValueArguments += convertValueArguments(it)
|
VALUE_ARGUMENT_LIST -> firValueArguments += expressionConverter.convertValueArguments(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Pair(firTypeRef, firValueArguments)
|
return Pair(firTypeRef, firValueArguments)
|
||||||
@@ -942,7 +949,7 @@ class DeclarationsConverter(
|
|||||||
explicitDelegation.forEachChildren {
|
explicitDelegation.forEachChildren {
|
||||||
when (it.tokenType) {
|
when (it.tokenType) {
|
||||||
TYPE_REFERENCE -> firTypeRef = convertType(it)
|
TYPE_REFERENCE -> firTypeRef = convertType(it)
|
||||||
else -> if (it.isExpression()) firExpression = visitExpression(it)
|
else -> if (it.isExpression()) firExpression = expressionConverter.visitExpression(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1193,7 +1200,7 @@ class DeclarationsConverter(
|
|||||||
VAR_KEYWORD -> isVar = true
|
VAR_KEYWORD -> isVar = true
|
||||||
IDENTIFIER -> identifier = it.getAsString()
|
IDENTIFIER -> identifier = it.getAsString()
|
||||||
TYPE_REFERENCE -> firType = convertType(it)
|
TYPE_REFERENCE -> firType = convertType(it)
|
||||||
else -> if (it.isExpression()) firExpression = visitExpression(it)
|
else -> if (it.isExpression()) firExpression = expressionConverter.visitExpression(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1209,41 +1216,4 @@ class DeclarationsConverter(
|
|||||||
).apply { annotations += modifiers.annotations }
|
).apply { annotations += modifiers.annotations }
|
||||||
return ValueParameter(isVal, isVar, modifiers, firValueParameter)
|
return ValueParameter(isVal, isVar, modifiers, firValueParameter)
|
||||||
}
|
}
|
||||||
|
|
||||||
/***** EXPRESSIONS *****/
|
|
||||||
//TODO move to parsing class?
|
|
||||||
/**
|
|
||||||
* @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseValueArgumentList
|
|
||||||
*/
|
|
||||||
private fun convertValueArguments(valueArguments: LighterASTNode): List<FirExpression> {
|
|
||||||
return valueArguments.forEachChildrenReturnList { node, container ->
|
|
||||||
when (node.tokenType) {
|
|
||||||
VALUE_ARGUMENT -> container += convertValueArgument(node)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun convertValueArgument(valueArgument: LighterASTNode): FirExpression {
|
|
||||||
return FirErrorExpressionImpl(session, null, "Not implemented")
|
|
||||||
//TODO implement
|
|
||||||
|
|
||||||
/*
|
|
||||||
this ?: return FirErrorExpressionImpl(session, this as? KtElement, "No argument given")
|
|
||||||
val expression = this.getArgumentExpression()
|
|
||||||
return when (expression) {
|
|
||||||
is KtConstantExpression, is KtStringTemplateExpression -> {
|
|
||||||
expression.accept(this@Visitor, Unit) as FirExpression
|
|
||||||
}
|
|
||||||
|
|
||||||
else -> {
|
|
||||||
{ expression }.toFirExpression("Argument is absent")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun visitExpression(expression: LighterASTNode): FirExpression {
|
|
||||||
return if (stubMode) FirExpressionStub(session, null)
|
|
||||||
else TODO("not implemented")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+162
@@ -7,7 +7,19 @@ package org.jetbrains.kotlin.fir.lightTree.converter
|
|||||||
|
|
||||||
import com.intellij.lang.LighterASTNode
|
import com.intellij.lang.LighterASTNode
|
||||||
import com.intellij.util.diff.FlyweightCapableTreeStructure
|
import com.intellij.util.diff.FlyweightCapableTreeStructure
|
||||||
|
import org.jetbrains.kotlin.KtNodeTypes.*
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
|
import org.jetbrains.kotlin.fir.builder.parseCharacter
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.impl.*
|
||||||
|
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.ir.expressions.IrConstKind
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens.*
|
||||||
|
import org.jetbrains.kotlin.psi.stubs.elements.KtConstantExpressionElementType
|
||||||
|
import org.jetbrains.kotlin.resolve.constants.evaluate.*
|
||||||
|
|
||||||
class ExpressionsConverter(
|
class ExpressionsConverter(
|
||||||
private val session: FirSession,
|
private val session: FirSession,
|
||||||
@@ -15,4 +27,154 @@ class ExpressionsConverter(
|
|||||||
tree: FlyweightCapableTreeStructure<LighterASTNode>
|
tree: FlyweightCapableTreeStructure<LighterASTNode>
|
||||||
) : BaseConverter(session, tree) {
|
) : BaseConverter(session, tree) {
|
||||||
|
|
||||||
|
/***** EXPRESSIONS *****/
|
||||||
|
fun visitExpression(expression: LighterASTNode): FirExpression {
|
||||||
|
if (!stubMode) {
|
||||||
|
when (expression.tokenType) {
|
||||||
|
STRING_TEMPLATE -> return convertStringTemplate(expression)
|
||||||
|
is KtConstantExpressionElementType -> return convertConstantExpression(expression)
|
||||||
|
}
|
||||||
|
TODO("not implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
return FirExpressionStub(session, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.jetbrains.kotlin.fir.builder.ConversionUtilsKt.toInterpolatingCall
|
||||||
|
*/
|
||||||
|
private fun convertStringTemplate(stringTemplate: LighterASTNode): FirExpression {
|
||||||
|
val sb = StringBuilder()
|
||||||
|
var hasExpressions = false
|
||||||
|
var result: FirExpression? = null
|
||||||
|
var callCreated = false
|
||||||
|
stringTemplate.forEachChildren(OPEN_QUOTE, CLOSING_QUOTE) {
|
||||||
|
val nextArgument = when (it.tokenType) {
|
||||||
|
LITERAL_STRING_TEMPLATE_ENTRY -> {
|
||||||
|
sb.append(it.getAsString())
|
||||||
|
FirConstExpressionImpl(session, null, IrConstKind.String, it.getAsString())
|
||||||
|
}
|
||||||
|
ESCAPE_STRING_TEMPLATE_ENTRY -> {
|
||||||
|
sb.append(it.getAsStringUnescapedValue())
|
||||||
|
FirConstExpressionImpl(session, null, IrConstKind.String, it.getAsStringUnescapedValue())
|
||||||
|
}
|
||||||
|
SHORT_STRING_TEMPLATE_ENTRY, LONG_STRING_TEMPLATE_ENTRY -> {
|
||||||
|
hasExpressions = true
|
||||||
|
convertShortOrLongStringTemplate(it)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
hasExpressions = true
|
||||||
|
FirErrorExpressionImpl(session, null, "Incorrect template entry: ${it.getAsString()}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = when {
|
||||||
|
result == null -> nextArgument
|
||||||
|
callCreated && result is FirStringConcatenationCallImpl -> (result as FirStringConcatenationCallImpl).apply {
|
||||||
|
//TODO smart cast to FirStringConcatenationCallImpl isn't working
|
||||||
|
arguments += nextArgument
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
callCreated = true
|
||||||
|
FirStringConcatenationCallImpl(session, null).apply {
|
||||||
|
arguments += result!!
|
||||||
|
arguments += nextArgument
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return if (hasExpressions) result!! else FirConstExpressionImpl(session, null, IrConstKind.String, sb.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun convertShortOrLongStringTemplate(shortOrLongString: LighterASTNode): FirExpression {
|
||||||
|
lateinit var firExpression: FirExpression
|
||||||
|
shortOrLongString.forEachChildren {
|
||||||
|
firExpression = visitExpression(it)
|
||||||
|
}
|
||||||
|
return firExpression
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.jetbrains.kotlin.fir.builder.ConversionUtilsKt.generateConstantExpressionByLiteral
|
||||||
|
*/
|
||||||
|
private fun convertConstantExpression(constantExpression: LighterASTNode): FirExpression {
|
||||||
|
val type = constantExpression.tokenType
|
||||||
|
val text: String = constantExpression.getAsString()
|
||||||
|
val convertedText: Any? = when (type) {
|
||||||
|
INTEGER_CONSTANT, FLOAT_CONSTANT -> parseNumericLiteral(text, type)
|
||||||
|
BOOLEAN_CONSTANT -> parseBoolean(text)
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
|
||||||
|
return when (type) {
|
||||||
|
INTEGER_CONSTANT ->
|
||||||
|
if (convertedText is Long &&
|
||||||
|
(hasLongSuffix(text) || hasUnsignedLongSuffix(text) || hasUnsignedSuffix(text) ||
|
||||||
|
convertedText > Int.MAX_VALUE || convertedText < Int.MIN_VALUE)
|
||||||
|
) {
|
||||||
|
FirConstExpressionImpl(
|
||||||
|
session, null, IrConstKind.Long, convertedText, "Incorrect long: $text"
|
||||||
|
)
|
||||||
|
} else if (convertedText is Number) {
|
||||||
|
// TODO: support byte / short
|
||||||
|
FirConstExpressionImpl(session, null, IrConstKind.Int, convertedText.toInt(), "Incorrect int: $text")
|
||||||
|
} else {
|
||||||
|
FirErrorExpressionImpl(session, null, reason = "Incorrect constant expression: $text")
|
||||||
|
}
|
||||||
|
FLOAT_CONSTANT ->
|
||||||
|
if (convertedText is Float) {
|
||||||
|
FirConstExpressionImpl(
|
||||||
|
session, null, IrConstKind.Float, convertedText, "Incorrect float: $text"
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
FirConstExpressionImpl(
|
||||||
|
session, null, IrConstKind.Double, convertedText as Double, "Incorrect double: $text"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
CHARACTER_CONSTANT ->
|
||||||
|
FirConstExpressionImpl(
|
||||||
|
session, null, IrConstKind.Char, text.parseCharacter(), "Incorrect character: $text"
|
||||||
|
)
|
||||||
|
BOOLEAN_CONSTANT ->
|
||||||
|
FirConstExpressionImpl(session, null, IrConstKind.Boolean, convertedText as Boolean)
|
||||||
|
NULL ->
|
||||||
|
FirConstExpressionImpl(session, null, IrConstKind.Null, null)
|
||||||
|
else ->
|
||||||
|
throw AssertionError("Unknown literal type: $type, $text")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseValueArgumentList
|
||||||
|
*/
|
||||||
|
fun convertValueArguments(valueArguments: LighterASTNode): List<FirExpression> {
|
||||||
|
return valueArguments.forEachChildrenReturnList { node, container ->
|
||||||
|
when (node.tokenType) {
|
||||||
|
VALUE_ARGUMENT -> container += convertValueArgument(node)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseValueArgument
|
||||||
|
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.toFirExpression(org.jetbrains.kotlin.psi.ValueArgument)
|
||||||
|
*/
|
||||||
|
private fun convertValueArgument(valueArgument: LighterASTNode): FirExpression {
|
||||||
|
var identifier: String? = null
|
||||||
|
var isSpread = false
|
||||||
|
lateinit var firExpression: FirExpression
|
||||||
|
valueArgument.forEachChildren {
|
||||||
|
when (it.tokenType) {
|
||||||
|
VALUE_ARGUMENT_NAME -> identifier = it.getAsString()
|
||||||
|
MUL -> isSpread = true
|
||||||
|
STRING_TEMPLATE -> firExpression = convertStringTemplate(it)
|
||||||
|
is KtConstantExpressionElementType -> firExpression = convertConstantExpression(it)
|
||||||
|
else -> if (it.isExpression()) firExpression = visitExpression(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return when {
|
||||||
|
identifier != null -> FirNamedArgumentExpressionImpl(session, null, identifier.nameAsSafeName(), isSpread, firExpression)
|
||||||
|
isSpread -> FirSpreadArgumentExpressionImpl(session, null, firExpression)
|
||||||
|
else -> firExpression
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+4
@@ -64,6 +64,10 @@ class TreesCompareTest : AbstractRawFirBuilderTestCase() {
|
|||||||
compare(stubMode = true)
|
compare(stubMode = true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun testCompareAll() {
|
||||||
|
compare(stubMode = false)
|
||||||
|
}
|
||||||
|
|
||||||
fun testStubCompareWithoutAnnotations() {
|
fun testStubCompareWithoutAnnotations() {
|
||||||
compare(stubMode = true, visitAnnotation = false)
|
compare(stubMode = true, visitAnnotation = false)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user