Write binary and unary expressions parsing (light tree to FIR)
This commit is contained in:
committed by
Mikhail Glukhikh
parent
be073ce2e6
commit
a13a043169
+11
-2
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.fir.types.impl.*
|
|||||||
import org.jetbrains.kotlin.lexer.KtToken
|
import org.jetbrains.kotlin.lexer.KtToken
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens.*
|
import org.jetbrains.kotlin.lexer.KtTokens.*
|
||||||
|
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.isExpression
|
||||||
|
|
||||||
open class BaseConverter(
|
open class BaseConverter(
|
||||||
session: FirSession,
|
session: FirSession,
|
||||||
@@ -25,7 +26,7 @@ open class BaseConverter(
|
|||||||
protected val implicitAnnotationType = FirImplicitAnnotationTypeRef(session, null)
|
protected val implicitAnnotationType = FirImplicitAnnotationTypeRef(session, null)
|
||||||
protected val implicitType = FirImplicitTypeRefImpl(session, null)
|
protected val implicitType = FirImplicitTypeRefImpl(session, null)
|
||||||
|
|
||||||
protected fun LighterASTNode?.getChildNodesByType(type: IElementType): List<LighterASTNode> {
|
fun LighterASTNode?.getChildNodesByType(type: IElementType): List<LighterASTNode> {
|
||||||
return this?.forEachChildrenReturnList { node, container ->
|
return this?.forEachChildrenReturnList { node, container ->
|
||||||
when (node.tokenType) {
|
when (node.tokenType) {
|
||||||
type -> container += node
|
type -> container += node
|
||||||
@@ -33,7 +34,7 @@ open class BaseConverter(
|
|||||||
} ?: listOf()
|
} ?: listOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun LighterASTNode?.getChildrenAsArray(): Array<LighterASTNode?> {
|
fun LighterASTNode?.getChildrenAsArray(): Array<LighterASTNode?> {
|
||||||
if (this == null) return arrayOf()
|
if (this == null) return arrayOf()
|
||||||
|
|
||||||
val kidsRef = Ref<Array<LighterASTNode?>>()
|
val kidsRef = Ref<Array<LighterASTNode?>>()
|
||||||
@@ -41,6 +42,14 @@ open class BaseConverter(
|
|||||||
return kidsRef.get()
|
return kidsRef.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun LighterASTNode.getExpressionInParentheses(): LighterASTNode {
|
||||||
|
this.forEachChildren {
|
||||||
|
if (it.isExpression()) return it
|
||||||
|
}
|
||||||
|
|
||||||
|
throw Exception()
|
||||||
|
}
|
||||||
|
|
||||||
protected inline fun LighterASTNode.forEachChildren(vararg skipTokens: KtToken, 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) {
|
||||||
|
|||||||
+10
-3
@@ -6,29 +6,35 @@
|
|||||||
package org.jetbrains.kotlin.fir.lightTree.converter
|
package org.jetbrains.kotlin.fir.lightTree.converter
|
||||||
|
|
||||||
import com.intellij.lang.LighterASTNode
|
import com.intellij.lang.LighterASTNode
|
||||||
|
import com.intellij.psi.tree.IElementType
|
||||||
import org.jetbrains.kotlin.KtNodeType
|
import org.jetbrains.kotlin.KtNodeType
|
||||||
import org.jetbrains.kotlin.KtNodeTypes
|
import org.jetbrains.kotlin.KtNodeTypes
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||||
import org.jetbrains.kotlin.fir.FirFunctionTarget
|
import org.jetbrains.kotlin.fir.FirFunctionTarget
|
||||||
|
import org.jetbrains.kotlin.fir.FirReference
|
||||||
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.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.*
|
import org.jetbrains.kotlin.fir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.fir.lightTree.fir.TypeConstraint
|
import org.jetbrains.kotlin.fir.lightTree.fir.TypeConstraint
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirExplicitThisReference
|
||||||
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
|
import org.jetbrains.kotlin.fir.references.FirResolvedCallableReferenceImpl
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference
|
||||||
import org.jetbrains.kotlin.fir.symbols.CallableId
|
import org.jetbrains.kotlin.fir.symbols.CallableId
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
|
||||||
import org.jetbrains.kotlin.fir.types.*
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.impl.*
|
import org.jetbrains.kotlin.fir.types.impl.*
|
||||||
|
import org.jetbrains.kotlin.lexer.KtSingleValueToken
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
import org.jetbrains.kotlin.name.ClassId
|
import org.jetbrains.kotlin.name.ClassId
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.name.SpecialNames
|
import org.jetbrains.kotlin.name.SpecialNames
|
||||||
|
import org.jetbrains.kotlin.parsing.KotlinExpressionParsing
|
||||||
import org.jetbrains.kotlin.psi.stubs.elements.KtConstantExpressionElementType
|
import org.jetbrains.kotlin.psi.stubs.elements.KtConstantExpressionElementType
|
||||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStringTemplateExpressionElementType
|
import org.jetbrains.kotlin.psi.stubs.elements.KtStringTemplateExpressionElementType
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
@@ -194,6 +200,7 @@ object ClassNameUtil {
|
|||||||
|
|
||||||
object FunctionUtil {
|
object FunctionUtil {
|
||||||
val firFunctions = mutableListOf<FirFunction>()
|
val firFunctions = mutableListOf<FirFunction>()
|
||||||
|
val firFunctionCalls = mutableListOf<FirFunctionCall>()
|
||||||
|
|
||||||
fun <T> MutableList<T>.removeLast() {
|
fun <T> MutableList<T>.removeLast() {
|
||||||
removeAt(size - 1)
|
removeAt(size - 1)
|
||||||
|
|||||||
+37
-22
@@ -15,11 +15,9 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
|||||||
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.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirBlock
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirDelegatedConstructorCall
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.*
|
import org.jetbrains.kotlin.fir.expressions.impl.*
|
||||||
|
import org.jetbrains.kotlin.fir.lightTree.LightTree2Fir
|
||||||
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.extractArgumentsFrom
|
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.extractArgumentsFrom
|
||||||
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.getAsString
|
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.getAsString
|
||||||
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.getAsStringWithoutBacktick
|
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.getAsStringWithoutBacktick
|
||||||
@@ -53,7 +51,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)
|
private val expressionConverter = ExpressionsConverter(session, stubMode, tree, this)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [org.jetbrains.kotlin.parsing.KotlinParsing.parseFile]
|
* [org.jetbrains.kotlin.parsing.KotlinParsing.parseFile]
|
||||||
@@ -96,6 +94,31 @@ class DeclarationsConverter(
|
|||||||
return firFile
|
return firFile
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseBlockExpression
|
||||||
|
*/
|
||||||
|
private fun convertBlockExpression(block: LighterASTNode): FirBlock {
|
||||||
|
val firStatements = mutableListOf<FirStatement>()
|
||||||
|
block.forEachChildren {
|
||||||
|
when (it.tokenType) {
|
||||||
|
//TODO("not implemented")
|
||||||
|
BLOCK -> ""
|
||||||
|
BINARY_EXPRESSION -> firStatements += expressionConverter.convertBinaryExpression(it)
|
||||||
|
PREFIX_EXPRESSION, POSTFIX_EXPRESSION -> firStatements += expressionConverter.convertUnaryExpression(it)
|
||||||
|
else -> if (it.isExpression()) firStatements += expressionConverter.visitExpression(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FirBlockImpl(session, null).apply {
|
||||||
|
firStatements.forEach { firStatement ->
|
||||||
|
if (firStatement !is FirBlock || firStatement.annotations.isNotEmpty()) {
|
||||||
|
statements += firStatement
|
||||||
|
} else {
|
||||||
|
statements += firStatement.statements
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/***** PREAMBLE *****/
|
/***** PREAMBLE *****/
|
||||||
/**
|
/**
|
||||||
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parsePackageName
|
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parsePackageName
|
||||||
@@ -639,7 +662,7 @@ class DeclarationsConverter(
|
|||||||
lateinit var identifier: String
|
lateinit var identifier: String
|
||||||
val firTypeParameters = mutableListOf<FirTypeParameter>()
|
val firTypeParameters = mutableListOf<FirTypeParameter>()
|
||||||
var isReturnType = false
|
var isReturnType = false
|
||||||
var isDelegate = false
|
var firDelegateExpression: FirExpression? = null
|
||||||
var isVar = false
|
var isVar = false
|
||||||
var receiverType: FirTypeRef? = null
|
var receiverType: FirTypeRef? = null
|
||||||
var returnType: FirTypeRef = implicitType
|
var returnType: FirTypeRef = implicitType
|
||||||
@@ -655,7 +678,7 @@ class DeclarationsConverter(
|
|||||||
COLON -> isReturnType = true
|
COLON -> isReturnType = true
|
||||||
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)
|
||||||
PROPERTY_DELEGATE -> isDelegate = true
|
PROPERTY_DELEGATE -> firDelegateExpression = expressionConverter.visitExpression(it)
|
||||||
VAR_KEYWORD -> isVar = true
|
VAR_KEYWORD -> isVar = true
|
||||||
PROPERTY_ACCESSOR -> {
|
PROPERTY_ACCESSOR -> {
|
||||||
val propertyAccessor = convertGetterOrSetter(it, returnType)
|
val propertyAccessor = convertGetterOrSetter(it, returnType)
|
||||||
@@ -675,11 +698,7 @@ class DeclarationsConverter(
|
|||||||
returnType,
|
returnType,
|
||||||
isVar,
|
isVar,
|
||||||
firExpression,
|
firExpression,
|
||||||
delegate = if (isDelegate) {
|
delegate = firDelegateExpression
|
||||||
FirExpressionStub(session, null)
|
|
||||||
//TODO("not implemented")
|
|
||||||
//{ property.delegate?.expression }.toFirExpression("Should have delegate")
|
|
||||||
} else null
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
FirMemberPropertyImpl(
|
FirMemberPropertyImpl(
|
||||||
@@ -700,11 +719,7 @@ class DeclarationsConverter(
|
|||||||
firExpression,
|
firExpression,
|
||||||
getter ?: FirDefaultPropertyGetter(session, null, returnType, modifiers.getVisibility()),
|
getter ?: FirDefaultPropertyGetter(session, null, returnType, modifiers.getVisibility()),
|
||||||
if (isVar) setter ?: FirDefaultPropertySetter(session, null, returnType, modifiers.getVisibility()) else null,
|
if (isVar) setter ?: FirDefaultPropertySetter(session, null, returnType, modifiers.getVisibility()) else null,
|
||||||
if (isDelegate) {
|
firDelegateExpression
|
||||||
FirExpressionStub(session, null)
|
|
||||||
//TODO("not implemented")
|
|
||||||
//{ property.delegate?.expression }.toFirExpression("Should have delegate")
|
|
||||||
} else null
|
|
||||||
).apply {
|
).apply {
|
||||||
this.typeParameters += firTypeParameters
|
this.typeParameters += firTypeParameters
|
||||||
this.joinTypeParameters(typeConstraints)
|
this.joinTypeParameters(typeConstraints)
|
||||||
@@ -854,6 +869,7 @@ class DeclarationsConverter(
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseFunctionBody
|
* @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(firBlock: FirBlock?, firExpression: FirExpression?): FirBlock? {
|
||||||
return when {
|
return when {
|
||||||
@@ -878,11 +894,10 @@ class DeclarationsConverter(
|
|||||||
/**
|
/**
|
||||||
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseBlock
|
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseBlock
|
||||||
*/
|
*/
|
||||||
private fun visitBlock(block: LighterASTNode?): FirBlock {
|
private fun visitBlock(block: LighterASTNode): FirBlock {
|
||||||
return if (!stubMode) {
|
return if (!stubMode) {
|
||||||
//TODO("not implemented")
|
val blockTree = LightTree2Fir.buildLightTreeBlockExpression(block.getAsString())
|
||||||
FirBlockImpl(session, null)
|
return DeclarationsConverter(session, stubMode, blockTree).convertBlockExpression(blockTree.root)
|
||||||
//visitStatements(ctx.statements())
|
|
||||||
} else {
|
} else {
|
||||||
FirSingleExpressionBlock(
|
FirSingleExpressionBlock(
|
||||||
session,
|
session,
|
||||||
@@ -1116,7 +1131,7 @@ class DeclarationsConverter(
|
|||||||
/**
|
/**
|
||||||
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseTypeArgumentList
|
* @see org.jetbrains.kotlin.parsing.KotlinParsing.parseTypeArgumentList
|
||||||
*/
|
*/
|
||||||
private fun convertTypeArguments(typeArguments: LighterASTNode): List<FirTypeProjection> {
|
fun convertTypeArguments(typeArguments: LighterASTNode): List<FirTypeProjection> {
|
||||||
return typeArguments.forEachChildrenReturnList { node, container ->
|
return typeArguments.forEachChildrenReturnList { node, container ->
|
||||||
when (node.tokenType) {
|
when (node.tokenType) {
|
||||||
TYPE_PROJECTION -> container += convertTypeProjection(node)
|
TYPE_PROJECTION -> container += convertTypeProjection(node)
|
||||||
|
|||||||
+255
-5
@@ -8,39 +8,238 @@ 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.KtNodeTypes.*
|
||||||
|
import org.jetbrains.kotlin.fir.FirReference
|
||||||
import org.jetbrains.kotlin.fir.FirSession
|
import org.jetbrains.kotlin.fir.FirSession
|
||||||
import org.jetbrains.kotlin.fir.builder.parseCharacter
|
import org.jetbrains.kotlin.fir.builder.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.expressions.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.impl.*
|
import org.jetbrains.kotlin.fir.expressions.impl.*
|
||||||
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.getAsString
|
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.isExpression
|
||||||
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.nameAsSafeName
|
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.getAsStringUnescapedValue
|
||||||
|
import org.jetbrains.kotlin.fir.lightTree.converter.ConverterUtil.extractArgumentsFrom
|
||||||
|
import org.jetbrains.kotlin.fir.lightTree.converter.FunctionUtil.removeLast
|
||||||
|
import org.jetbrains.kotlin.fir.lightTree.converter.utils.*
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirSimpleNamedReference
|
||||||
|
import org.jetbrains.kotlin.fir.types.FirTypeProjection
|
||||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens.*
|
import org.jetbrains.kotlin.lexer.KtTokens.*
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.stubs.elements.KtConstantExpressionElementType
|
import org.jetbrains.kotlin.psi.stubs.elements.KtConstantExpressionElementType
|
||||||
import org.jetbrains.kotlin.resolve.constants.evaluate.*
|
import org.jetbrains.kotlin.resolve.constants.evaluate.*
|
||||||
|
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||||
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
|
||||||
class ExpressionsConverter(
|
class ExpressionsConverter(
|
||||||
private val session: FirSession,
|
val session: FirSession,
|
||||||
private val stubMode: Boolean,
|
private val stubMode: Boolean,
|
||||||
tree: FlyweightCapableTreeStructure<LighterASTNode>
|
tree: FlyweightCapableTreeStructure<LighterASTNode>,
|
||||||
|
private val declarationsConverter: DeclarationsConverter
|
||||||
) : BaseConverter(session, tree) {
|
) : BaseConverter(session, tree) {
|
||||||
|
|
||||||
/***** EXPRESSIONS *****/
|
/***** EXPRESSIONS *****/
|
||||||
fun visitExpression(expression: LighterASTNode): FirExpression {
|
fun visitExpression(expression: LighterASTNode): FirExpression {
|
||||||
if (!stubMode) {
|
if (!stubMode) {
|
||||||
when (expression.tokenType) {
|
when (expression.tokenType) {
|
||||||
|
BINARY_EXPRESSION -> return convertBinaryExpression(expression) as FirExpression
|
||||||
|
PREFIX_EXPRESSION, POSTFIX_EXPRESSION -> return convertUnaryExpression(expression) as FirExpression
|
||||||
|
in qualifiedAccessTokens -> return convertQualifiedExpression(expression)
|
||||||
|
CALL_EXPRESSION -> return convertCallExpression(expression)
|
||||||
|
ARRAY_ACCESS_EXPRESSION -> return convertArrayAccessExpression(expression)
|
||||||
STRING_TEMPLATE -> return convertStringTemplate(expression)
|
STRING_TEMPLATE -> return convertStringTemplate(expression)
|
||||||
is KtConstantExpressionElementType -> return convertConstantExpression(expression)
|
is KtConstantExpressionElementType -> return convertConstantExpression(expression)
|
||||||
|
REFERENCE_EXPRESSION -> return convertSimpleNameExpression(expression)
|
||||||
|
PARENTHESIZED, PROPERTY_DELEGATE, INDICES -> return visitExpression(expression.getExpressionInParentheses())
|
||||||
}
|
}
|
||||||
//TODO("not implemented")
|
return FirExpressionStub(session, null)
|
||||||
|
//TODO("not fully implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
return FirExpressionStub(session, null)
|
return FirExpressionStub(session, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseBinaryExpression
|
||||||
|
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitBinaryExpression
|
||||||
|
*/
|
||||||
|
fun convertBinaryExpression(binaryExpression: LighterASTNode): FirStatement {
|
||||||
|
var isLeftArgument = true
|
||||||
|
lateinit var operationTokenName: String
|
||||||
|
lateinit var leftArgNode: LighterASTNode
|
||||||
|
lateinit var rightArgAsFir: FirExpression
|
||||||
|
binaryExpression.forEachChildren {
|
||||||
|
when (it.tokenType) {
|
||||||
|
OPERATION_REFERENCE -> {
|
||||||
|
isLeftArgument = false
|
||||||
|
operationTokenName = it.getAsString()
|
||||||
|
}
|
||||||
|
else -> if (it.isExpression()) {
|
||||||
|
if (isLeftArgument) {
|
||||||
|
leftArgNode = it
|
||||||
|
} else {
|
||||||
|
rightArgAsFir = visitExpression(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val operationToken = operationTokenName.getOperationSymbol()
|
||||||
|
when (operationToken) {
|
||||||
|
ELVIS ->
|
||||||
|
return visitExpression(leftArgNode).generateNotNullOrOther(session, rightArgAsFir, "elvis", null)
|
||||||
|
ANDAND, OROR ->
|
||||||
|
return visitExpression(leftArgNode).generateLazyLogicalOperation(session, rightArgAsFir, operationToken == ANDAND, null)
|
||||||
|
in OperatorConventions.IN_OPERATIONS ->
|
||||||
|
return rightArgAsFir.generateContainsOperation(session, visitExpression(leftArgNode), operationToken == NOT_IN, null, null)
|
||||||
|
}
|
||||||
|
val conventionCallName = operationToken.toBinaryName()
|
||||||
|
return if (conventionCallName != null || operationToken == IDENTIFIER) {
|
||||||
|
FirFunctionCallImpl(session, null).apply {
|
||||||
|
calleeReference = FirSimpleNamedReference(
|
||||||
|
this@ExpressionsConverter.session, null,
|
||||||
|
conventionCallName ?: operationTokenName.nameAsSafeName()
|
||||||
|
)
|
||||||
|
explicitReceiver = visitExpression(leftArgNode)
|
||||||
|
arguments += rightArgAsFir
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val firOperation = operationToken.toFirOperation()
|
||||||
|
if (firOperation in FirOperation.ASSIGNMENTS) {
|
||||||
|
return convertAssignment(leftArgNode, rightArgAsFir, firOperation)
|
||||||
|
} else {
|
||||||
|
FirOperatorCallImpl(session, null, firOperation).apply {
|
||||||
|
arguments += visitExpression(leftArgNode)
|
||||||
|
arguments += rightArgAsFir
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parsePostfixExpression
|
||||||
|
* @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parsePrefixExpression
|
||||||
|
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitUnaryExpression
|
||||||
|
*/
|
||||||
|
fun convertUnaryExpression(unaryExpression: LighterASTNode): FirStatement {
|
||||||
|
lateinit var operationTokenName: String
|
||||||
|
lateinit var argument: LighterASTNode
|
||||||
|
unaryExpression.forEachChildren {
|
||||||
|
when (it.tokenType) {
|
||||||
|
OPERATION_REFERENCE -> operationTokenName = it.getAsString()
|
||||||
|
else -> if (it.isExpression()) argument = it
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val operationToken = operationTokenName.getOperationSymbol()
|
||||||
|
if (operationToken == EXCLEXCL) {
|
||||||
|
return bangBangToWhen(session, visitExpression(argument))
|
||||||
|
}
|
||||||
|
|
||||||
|
val conventionCallName = operationToken.toUnaryName()
|
||||||
|
return if (conventionCallName != null) {
|
||||||
|
if (operationToken in OperatorConventions.INCREMENT_OPERATIONS) {
|
||||||
|
return generateIncrementOrDecrementBlock(
|
||||||
|
argument,
|
||||||
|
callName = conventionCallName,
|
||||||
|
prefix = unaryExpression.tokenType == PREFIX_EXPRESSION
|
||||||
|
)
|
||||||
|
}
|
||||||
|
FirFunctionCallImpl(session, null).apply {
|
||||||
|
calleeReference = FirSimpleNamedReference(this@ExpressionsConverter.session, null, conventionCallName)
|
||||||
|
explicitReceiver = visitExpression(argument)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val firOperation = operationToken.toFirOperation()
|
||||||
|
FirOperatorCallImpl(session, null, firOperation).apply {
|
||||||
|
arguments += visitExpression(argument)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parsePostfixExpression
|
||||||
|
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitQualifiedExpression
|
||||||
|
*/
|
||||||
|
private fun convertQualifiedExpression(dotQualifiedExpression: LighterASTNode): FirExpression {
|
||||||
|
var isSelector = false
|
||||||
|
var isSafe = false
|
||||||
|
var firSelector: FirExpression? = null //after dot
|
||||||
|
lateinit var firReceiver: FirExpression //before dot
|
||||||
|
dotQualifiedExpression.forEachChildren {
|
||||||
|
when (it.tokenType) {
|
||||||
|
DOT -> isSelector = true
|
||||||
|
SAFE_ACCESS -> {
|
||||||
|
isSafe = true
|
||||||
|
isSelector = true
|
||||||
|
}
|
||||||
|
else -> if (isSelector) firSelector = visitExpression(it) else firReceiver = visitExpression(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firSelector == null) {
|
||||||
|
return FirErrorExpressionImpl(session, null, "Qualified expression without selector")
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO use contracts?
|
||||||
|
if (firSelector is FirModifiableQualifiedAccess<*>) {
|
||||||
|
(firSelector as FirModifiableQualifiedAccess<*>).safe = isSafe
|
||||||
|
(firSelector as FirModifiableQualifiedAccess<*>).explicitReceiver = firReceiver
|
||||||
|
}
|
||||||
|
return firSelector!!
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseCallSuffix
|
||||||
|
*/
|
||||||
|
private fun convertCallExpression(callSuffix: LighterASTNode): FirExpression {
|
||||||
|
var name: String? = null
|
||||||
|
val firTypeArguments = mutableListOf<FirTypeProjection>()
|
||||||
|
val firValueArguments = mutableListOf<FirExpression>()
|
||||||
|
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)
|
||||||
|
else -> additionalArgument = visitExpression(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return FirFunctionCallImpl(session, null).apply {
|
||||||
|
val calleeReference = when {
|
||||||
|
name != null -> FirSimpleNamedReference(this@ExpressionsConverter.session, null, name.nameAsSafeName())
|
||||||
|
additionalArgument != null -> {
|
||||||
|
arguments += additionalArgument!!
|
||||||
|
FirSimpleNamedReference(this@ExpressionsConverter.session, null, OperatorNameConventions.INVOKE)
|
||||||
|
}
|
||||||
|
else -> FirErrorNamedReference(this@ExpressionsConverter.session, null, "Call has no callee")
|
||||||
|
}
|
||||||
|
this.calleeReference = calleeReference
|
||||||
|
FunctionUtil.firFunctionCalls += this
|
||||||
|
this.extractArgumentsFrom(firValueArguments, 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
|
* @see org.jetbrains.kotlin.fir.builder.ConversionUtilsKt.toInterpolatingCall
|
||||||
*/
|
*/
|
||||||
private fun convertStringTemplate(stringTemplate: LighterASTNode): FirExpression {
|
private fun convertStringTemplate(stringTemplate: LighterASTNode): FirExpression {
|
||||||
@@ -94,6 +293,7 @@ class ExpressionsConverter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseLiteralConstant
|
||||||
* @see org.jetbrains.kotlin.fir.builder.ConversionUtilsKt.generateConstantExpressionByLiteral
|
* @see org.jetbrains.kotlin.fir.builder.ConversionUtilsKt.generateConstantExpressionByLiteral
|
||||||
*/
|
*/
|
||||||
private fun convertConstantExpression(constantExpression: LighterASTNode): FirExpression {
|
private fun convertConstantExpression(constantExpression: LighterASTNode): FirExpression {
|
||||||
@@ -143,6 +343,39 @@ class ExpressionsConverter(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseArrayAccess
|
||||||
|
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitArrayAccessExpression
|
||||||
|
*/
|
||||||
|
private fun convertArrayAccessExpression(arrayAccess: LighterASTNode): FirFunctionCall {//Pair<LighterASTNode, List<FirExpression>> {
|
||||||
|
lateinit var expression: FirExpression
|
||||||
|
val indexes: MutableList<FirExpression> = mutableListOf()
|
||||||
|
arrayAccess.forEachChildren {
|
||||||
|
when (it.tokenType) {
|
||||||
|
INDICES -> indexes += visitExpression(it)
|
||||||
|
else -> if (it.isExpression()) expression = visitExpression(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FirFunctionCallImpl(session, null).apply {
|
||||||
|
calleeReference = FirSimpleNamedReference(this@ExpressionsConverter.session, null, OperatorNameConventions.GET)
|
||||||
|
explicitReceiver = expression
|
||||||
|
for (indexExpression in indexes) {
|
||||||
|
arguments += indexExpression
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseSimpleNameExpression
|
||||||
|
* @see org.jetbrains.kotlin.fir.builder.RawFirBuilder.Visitor.visitSimpleNameExpression
|
||||||
|
*/
|
||||||
|
private fun convertSimpleNameExpression(referenceExpression: LighterASTNode): FirQualifiedAccessExpression {
|
||||||
|
return FirQualifiedAccessExpressionImpl(session, null).apply {
|
||||||
|
calleeReference =
|
||||||
|
FirSimpleNamedReference(this@ExpressionsConverter.session, null, referenceExpression.getAsString().nameAsSafeName())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseValueArgumentList
|
* @see org.jetbrains.kotlin.parsing.KotlinExpressionParsing.parseValueArgumentList
|
||||||
*/
|
*/
|
||||||
@@ -177,4 +410,21 @@ class ExpressionsConverter(
|
|||||||
else -> firExpression
|
else -> firExpression
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun convertLValue(leftArgNode: LighterASTNode, container: FirModifiableQualifiedAccess<*>): FirReference {
|
||||||
|
leftArgNode.forEachChildren {
|
||||||
|
return when (it.tokenType) {
|
||||||
|
//THIS_EXPRESSION -> FirExplicitThisReference(session, left, left.getLabelName())
|
||||||
|
REFERENCE_EXPRESSION -> FirSimpleNamedReference(session, null, it.getAsString().nameAsSafeName())
|
||||||
|
in qualifiedAccessTokens -> (visitExpression(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 FirErrorNamedReference(session, null, "Unsupported LValue: ${leftArgNode.tokenType}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+161
@@ -0,0 +1,161 @@
|
|||||||
|
/*
|
||||||
|
* 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.converter.utils
|
||||||
|
|
||||||
|
import com.intellij.lang.LighterASTNode
|
||||||
|
import com.intellij.psi.tree.IElementType
|
||||||
|
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.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.references.FirSimpleNamedReference
|
||||||
|
import org.jetbrains.kotlin.lexer.KtSingleValueToken
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens.DOT
|
||||||
|
import org.jetbrains.kotlin.lexer.KtTokens.SAFE_ACCESS
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.parsing.KotlinExpressionParsing
|
||||||
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
|
|
||||||
|
val qualifiedAccessTokens = TokenSet.create(DOT_QUALIFIED_EXPRESSION, SAFE_ACCESS_EXPRESSION)
|
||||||
|
|
||||||
|
fun String.getOperationSymbol(): IElementType {
|
||||||
|
KotlinExpressionParsing.ALL_OPERATIONS.types.forEach {
|
||||||
|
if (it is KtSingleValueToken && it.value == this) return it
|
||||||
|
}
|
||||||
|
return KtTokens.IDENTIFIER
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ExpressionsConverter.convertAssignment(
|
||||||
|
leftArgNode: LighterASTNode,
|
||||||
|
rightArgAsFir: FirExpression,
|
||||||
|
operation: FirOperation
|
||||||
|
): FirStatement {
|
||||||
|
if (leftArgNode.tokenType == PARENTHESIZED) {
|
||||||
|
return convertAssignment(leftArgNode.getExpressionInParentheses(), rightArgAsFir, operation)
|
||||||
|
}
|
||||||
|
if (leftArgNode.tokenType == ARRAY_ACCESS_EXPRESSION) {
|
||||||
|
val arrayAccessFunctionCall = visitExpression(leftArgNode) as FirFunctionCall
|
||||||
|
val firArrayExpression = arrayAccessFunctionCall.explicitReceiver!!
|
||||||
|
val arraySet = if (operation != FirOperation.ASSIGN) {
|
||||||
|
FirArraySetCallImpl(session, null, rightArgAsFir, operation).apply {
|
||||||
|
indexes += arrayAccessFunctionCall.arguments
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return FirFunctionCallImpl(session, null).apply {
|
||||||
|
calleeReference = FirSimpleNamedReference(this@convertAssignment.session, null, OperatorNameConventions.SET)
|
||||||
|
explicitReceiver = firArrayExpression
|
||||||
|
arguments += arrayAccessFunctionCall.arguments
|
||||||
|
arguments += rightArgAsFir
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (leftArgNode.getChildNodesByType(REFERENCE_EXPRESSION).isNotEmpty()) {
|
||||||
|
return arraySet.apply {
|
||||||
|
lValue = (firArrayExpression as FirQualifiedAccess).calleeReference
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FirBlockImpl(this@convertAssignment.session, null).apply {
|
||||||
|
val name = Name.special("<array-set>")
|
||||||
|
statements += generateTemporaryVariable(this@convertAssignment.session, null, name, firArrayExpression)
|
||||||
|
statements += arraySet.apply { lValue = FirSimpleNamedReference(this@convertAssignment.session, null, name) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (operation != FirOperation.ASSIGN &&
|
||||||
|
leftArgNode.tokenType != REFERENCE_EXPRESSION && leftArgNode.tokenType != THIS_EXPRESSION &&
|
||||||
|
(leftArgNode.tokenType !in qualifiedAccessTokens || getSelectorType(leftArgNode.getChildrenAsArray()) != REFERENCE_EXPRESSION)
|
||||||
|
) {
|
||||||
|
return FirBlockImpl(session, null).apply {
|
||||||
|
val name = Name.special("<complex-set>")
|
||||||
|
statements += generateTemporaryVariable(this@convertAssignment.session, null, name, visitExpression(leftArgNode))
|
||||||
|
statements += FirVariableAssignmentImpl(this@convertAssignment.session, null, rightArgAsFir, operation).apply {
|
||||||
|
lValue = FirSimpleNamedReference(this@convertAssignment.session, null, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return FirVariableAssignmentImpl(session, null, rightArgAsFir, operation).apply {
|
||||||
|
lValue = convertLValue(leftArgNode, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fun ExpressionsConverter.generateIncrementOrDecrementBlock(
|
||||||
|
argument: LighterASTNode?,
|
||||||
|
callName: Name,
|
||||||
|
prefix: Boolean
|
||||||
|
): FirExpression {
|
||||||
|
if (argument == null) {
|
||||||
|
return FirErrorExpressionImpl(session, null, "Inc/dec without operand")
|
||||||
|
}
|
||||||
|
return FirBlockImpl(session, null).apply {
|
||||||
|
val tempName = Name.special("<unary>")
|
||||||
|
val temporaryVariable = generateTemporaryVariable(this@generateIncrementOrDecrementBlock.session, null, tempName, visitExpression(argument))
|
||||||
|
statements += temporaryVariable
|
||||||
|
val resultName = Name.special("<unary-result>")
|
||||||
|
val resultInitializer = FirFunctionCallImpl(this@generateIncrementOrDecrementBlock.session, null).apply {
|
||||||
|
this.calleeReference = FirSimpleNamedReference(this@generateIncrementOrDecrementBlock.session, null, callName)
|
||||||
|
this.explicitReceiver = generateResolvedAccessExpression(this@generateIncrementOrDecrementBlock.session, null, temporaryVariable)
|
||||||
|
}
|
||||||
|
val resultVar = generateTemporaryVariable(this@generateIncrementOrDecrementBlock.session, null, resultName, resultInitializer)
|
||||||
|
val assignment = convertAssignment(
|
||||||
|
argument,
|
||||||
|
if (prefix && argument.tokenType != REFERENCE_EXPRESSION)
|
||||||
|
generateResolvedAccessExpression(this@generateIncrementOrDecrementBlock.session, null, resultVar)
|
||||||
|
else
|
||||||
|
resultInitializer,
|
||||||
|
FirOperation.ASSIGN
|
||||||
|
)
|
||||||
|
|
||||||
|
fun appendAssignment() {
|
||||||
|
if (assignment is FirBlock) {
|
||||||
|
statements += assignment.statements
|
||||||
|
} else {
|
||||||
|
statements += assignment
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prefix) {
|
||||||
|
if (argument.tokenType != REFERENCE_EXPRESSION) {
|
||||||
|
statements += resultVar
|
||||||
|
appendAssignment()
|
||||||
|
statements += generateResolvedAccessExpression(this@generateIncrementOrDecrementBlock.session, null, resultVar)
|
||||||
|
} else {
|
||||||
|
appendAssignment()
|
||||||
|
statements += generateAccessExpression(this@generateIncrementOrDecrementBlock.session, null, argument.getAsString().nameAsSafeName())
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
appendAssignment()
|
||||||
|
statements += generateResolvedAccessExpression(this@generateIncrementOrDecrementBlock.session, null, temporaryVariable)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun bangBangToWhen(session: FirSession, baseExpression: FirExpression): FirWhenExpression {
|
||||||
|
return baseExpression.generateNotNullOrOther(
|
||||||
|
session,
|
||||||
|
FirThrowExpressionImpl(
|
||||||
|
session, null, FirFunctionCallImpl(session, null).apply {
|
||||||
|
calleeReference = FirSimpleNamedReference(session, null, RawFirBuilder.KNPE)
|
||||||
|
}
|
||||||
|
), "bangbang", null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getSelectorType(qualifiedAccessChildren: Array<LighterASTNode?>): IElementType? {
|
||||||
|
var isSelector = false
|
||||||
|
qualifiedAccessChildren.forEach {
|
||||||
|
if (it == null) return null
|
||||||
|
when (it.tokenType) {
|
||||||
|
DOT, SAFE_ACCESS -> isSelector = true
|
||||||
|
else -> if (isSelector) return it.tokenType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
+9
-3
@@ -7,11 +7,17 @@ package org.jetbrains.kotlin.fir.lightTree.compare
|
|||||||
|
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
import com.intellij.openapi.vfs.CharsetToolkit
|
import com.intellij.openapi.vfs.CharsetToolkit
|
||||||
|
import com.intellij.psi.PsiFileFactory
|
||||||
|
import com.intellij.psi.PsiManager
|
||||||
|
import com.intellij.psi.impl.PsiFileFactoryImpl
|
||||||
|
import com.intellij.psi.impl.PsiManagerImpl
|
||||||
import com.intellij.testFramework.TestDataPath
|
import com.intellij.testFramework.TestDataPath
|
||||||
import com.intellij.util.PathUtil
|
import com.intellij.util.PathUtil
|
||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
|
import org.jetbrains.kotlin.fir.FirElement
|
||||||
import org.jetbrains.kotlin.fir.FirRenderer
|
import org.jetbrains.kotlin.fir.FirRenderer
|
||||||
import org.jetbrains.kotlin.fir.builder.AbstractRawFirBuilderTestCase
|
import org.jetbrains.kotlin.fir.builder.AbstractRawFirBuilderTestCase
|
||||||
|
import org.jetbrains.kotlin.fir.builder.RawFirBuilder
|
||||||
import org.jetbrains.kotlin.fir.lightTree.LightTree2Fir
|
import org.jetbrains.kotlin.fir.lightTree.LightTree2Fir
|
||||||
import org.jetbrains.kotlin.fir.lightTree.walkTopDown
|
import org.jetbrains.kotlin.fir.lightTree.walkTopDown
|
||||||
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
|
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
|
||||||
@@ -23,7 +29,7 @@ import java.io.File
|
|||||||
@TestDataPath("\$PROJECT_ROOT")
|
@TestDataPath("\$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners::class)
|
@RunWith(JUnit3RunnerWithInners::class)
|
||||||
class TreesCompareTest : AbstractRawFirBuilderTestCase() {
|
class TreesCompareTest : AbstractRawFirBuilderTestCase() {
|
||||||
private fun compareBase(stubMode: Boolean, compareFir: (File) -> Boolean) {
|
private fun compareBase(compareFir: (File) -> Boolean) {
|
||||||
val path = System.getProperty("user.dir")
|
val path = System.getProperty("user.dir")
|
||||||
var counter = 0
|
var counter = 0
|
||||||
var errorCounter = 0
|
var errorCounter = 0
|
||||||
@@ -40,7 +46,7 @@ class TreesCompareTest : AbstractRawFirBuilderTestCase() {
|
|||||||
|
|
||||||
private fun compareAll(stubMode: Boolean) {
|
private fun compareAll(stubMode: Boolean) {
|
||||||
val lightTreeConverter = LightTree2Fir(stubMode, myProject)
|
val lightTreeConverter = LightTree2Fir(stubMode, myProject)
|
||||||
compareBase(stubMode) { file ->
|
compareBase { file ->
|
||||||
val text = FileUtil.loadFile(file, CharsetToolkit.UTF8, true).trim()
|
val text = FileUtil.loadFile(file, CharsetToolkit.UTF8, true).trim()
|
||||||
|
|
||||||
//light tree
|
//light tree
|
||||||
@@ -122,7 +128,7 @@ class TreesCompareTest : AbstractRawFirBuilderTestCase() {
|
|||||||
visitAssignment = visitAssignment
|
visitAssignment = visitAssignment
|
||||||
)
|
)
|
||||||
val lightTreeConverter = LightTree2Fir(stubMode, myProject)
|
val lightTreeConverter = LightTree2Fir(stubMode, myProject)
|
||||||
compareBase(stubMode) { file ->
|
compareBase { file ->
|
||||||
val text = FileUtil.loadFile(file, CharsetToolkit.UTF8, true).trim()
|
val text = FileUtil.loadFile(file, CharsetToolkit.UTF8, true).trim()
|
||||||
|
|
||||||
//light tree
|
//light tree
|
||||||
|
|||||||
@@ -149,15 +149,15 @@ internal fun generateConstantExpressionByLiteral(expression: KtConstantExpressio
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun IElementType.toBinaryName(): Name? {
|
fun IElementType.toBinaryName(): Name? {
|
||||||
return OperatorConventions.BINARY_OPERATION_NAMES[this]
|
return OperatorConventions.BINARY_OPERATION_NAMES[this]
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun IElementType.toUnaryName(): Name? {
|
fun IElementType.toUnaryName(): Name? {
|
||||||
return OperatorConventions.UNARY_OPERATION_NAMES[this]
|
return OperatorConventions.UNARY_OPERATION_NAMES[this]
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun IElementType.toFirOperation(): FirOperation =
|
fun IElementType.toFirOperation(): FirOperation =
|
||||||
when (this) {
|
when (this) {
|
||||||
KtTokens.LT -> FirOperation.LT
|
KtTokens.LT -> FirOperation.LT
|
||||||
KtTokens.GT -> FirOperation.GT
|
KtTokens.GT -> FirOperation.GT
|
||||||
@@ -181,8 +181,8 @@ internal fun IElementType.toFirOperation(): FirOperation =
|
|||||||
else -> throw AssertionError(this.toString())
|
else -> throw AssertionError(this.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun FirExpression.generateNotNullOrOther(
|
fun FirExpression.generateNotNullOrOther(
|
||||||
session: FirSession, other: FirExpression, caseId: String, basePsi: KtElement
|
session: FirSession, other: FirExpression, caseId: String, basePsi: KtElement?
|
||||||
): FirWhenExpression {
|
): FirWhenExpression {
|
||||||
val subjectName = Name.special("<$caseId>")
|
val subjectName = Name.special("<$caseId>")
|
||||||
val subjectVariable = generateTemporaryVariable(session, basePsi, subjectName, this)
|
val subjectVariable = generateTemporaryVariable(session, basePsi, subjectName, this)
|
||||||
@@ -209,8 +209,8 @@ internal fun FirExpression.generateNotNullOrOther(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun FirExpression.generateLazyLogicalOperation(
|
fun FirExpression.generateLazyLogicalOperation(
|
||||||
other: FirExpression, isAnd: Boolean, basePsi: KtElement
|
other: FirExpression, isAnd: Boolean, basePsi: KtElement?
|
||||||
): FirWhenExpression {
|
): FirWhenExpression {
|
||||||
val terminalExpression = FirConstExpressionImpl(psi, IrConstKind.Boolean, !isAnd)
|
val terminalExpression = FirConstExpressionImpl(psi, IrConstKind.Boolean, !isAnd)
|
||||||
val terminalBlock = FirSingleExpressionBlock(terminalExpression)
|
val terminalBlock = FirSingleExpressionBlock(terminalExpression)
|
||||||
@@ -328,11 +328,11 @@ internal fun Array<KtStringTemplateEntry>.toInterpolatingCall(
|
|||||||
return if (hasExpressions) result!! else FirConstExpressionImpl(base, IrConstKind.String, sb.toString())
|
return if (hasExpressions) result!! else FirConstExpressionImpl(base, IrConstKind.String, sb.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun FirExpression.generateContainsOperation(
|
fun FirExpression.generateContainsOperation(
|
||||||
argument: FirExpression,
|
argument: FirExpression,
|
||||||
inverted: Boolean,
|
inverted: Boolean,
|
||||||
base: KtExpression?,
|
base: KtExpression?,
|
||||||
operationReference: KtOperationReferenceExpression
|
operationReference: KtOperationReferenceExpression?
|
||||||
): FirFunctionCall {
|
): FirFunctionCall {
|
||||||
val containsCall = FirFunctionCallImpl(base).apply {
|
val containsCall = FirFunctionCallImpl(base).apply {
|
||||||
calleeReference = FirSimpleNamedReference(operationReference, OperatorNameConventions.CONTAINS)
|
calleeReference = FirSimpleNamedReference(operationReference, OperatorNameConventions.CONTAINS)
|
||||||
@@ -425,12 +425,12 @@ internal fun generateIncrementOrDecrementBlock(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun generateAccessExpression(psi: PsiElement?, name: Name): FirQualifiedAccessExpression =
|
fun generateAccessExpression(psi: PsiElement?, name: Name): FirQualifiedAccessExpression =
|
||||||
FirQualifiedAccessExpressionImpl(psi).apply {
|
FirQualifiedAccessExpressionImpl(psi).apply {
|
||||||
calleeReference = FirSimpleNamedReference(psi, name)
|
calleeReference = FirSimpleNamedReference(psi, name)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun generateResolvedAccessExpression(psi: PsiElement?, variable: FirVariable<*>): FirQualifiedAccessExpression =
|
fun generateResolvedAccessExpression(psi: PsiElement?, variable: FirVariable<*>): FirQualifiedAccessExpression =
|
||||||
FirQualifiedAccessExpressionImpl(psi).apply {
|
FirQualifiedAccessExpressionImpl(psi).apply {
|
||||||
calleeReference = FirResolvedCallableReferenceImpl(psi, variable.name, variable.symbol)
|
calleeReference = FirResolvedCallableReferenceImpl(psi, variable.name, variable.symbol)
|
||||||
}
|
}
|
||||||
@@ -462,7 +462,7 @@ internal fun generateDestructuringBlock(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun generateTemporaryVariable(
|
fun generateTemporaryVariable(
|
||||||
session: FirSession, psi: PsiElement?, name: Name, initializer: FirExpression
|
session: FirSession, psi: PsiElement?, name: Name, initializer: FirExpression
|
||||||
): FirVariable<*> =
|
): FirVariable<*> =
|
||||||
FirVariableImpl(session, psi, name, FirImplicitTypeRefImpl(psi), false, initializer, FirVariableSymbol(name)).apply {
|
FirVariableImpl(session, psi, name, FirImplicitTypeRefImpl(psi), false, initializer, FirVariableSymbol(name)).apply {
|
||||||
|
|||||||
Reference in New Issue
Block a user