[IR generator] Move each visitor printer into its own file
This commit is contained in:
committed by
Space Team
parent
8c75526130
commit
e4078d163b
+69
@@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 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.ir.generator.print
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.generators.tree.*
|
||||||
|
import org.jetbrains.kotlin.generators.tree.printer.GeneratedFile
|
||||||
|
import org.jetbrains.kotlin.generators.tree.printer.printBlock
|
||||||
|
import org.jetbrains.kotlin.ir.generator.elementTransformerType
|
||||||
|
import org.jetbrains.kotlin.ir.generator.elementVisitorType
|
||||||
|
import org.jetbrains.kotlin.ir.generator.model.Element
|
||||||
|
import org.jetbrains.kotlin.ir.generator.model.Field
|
||||||
|
import org.jetbrains.kotlin.ir.generator.model.Model
|
||||||
|
import org.jetbrains.kotlin.utils.SmartPrinter
|
||||||
|
import org.jetbrains.kotlin.utils.withIndent
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
private class TransformerPrinter(
|
||||||
|
printer: SmartPrinter,
|
||||||
|
override val visitorType: ClassRef<*>,
|
||||||
|
val rootElement: Element,
|
||||||
|
) : AbstractVisitorPrinter<Element, Field>(printer) {
|
||||||
|
|
||||||
|
override val visitorSuperType: ClassRef<PositionTypeParameterRef>
|
||||||
|
get() = elementVisitorType.withArgs(rootElement, dataTypeVariable)
|
||||||
|
|
||||||
|
override val visitorTypeParameters: List<TypeVariable>
|
||||||
|
get() = listOf(dataTypeVariable)
|
||||||
|
|
||||||
|
override val visitorDataType: TypeRef
|
||||||
|
get() = dataTypeVariable
|
||||||
|
|
||||||
|
override fun visitMethodReturnType(element: Element) = element.getTransformExplicitType()
|
||||||
|
|
||||||
|
override val allowTypeParametersInVisitorMethods: Boolean
|
||||||
|
get() = false
|
||||||
|
|
||||||
|
context(ImportCollector)
|
||||||
|
override fun printMethodsForElement(element: Element) {
|
||||||
|
printer.run {
|
||||||
|
val parent = element.parentInVisitor
|
||||||
|
if (element.transformByChildren || parent != null) {
|
||||||
|
println()
|
||||||
|
printVisitMethodDeclaration(
|
||||||
|
element = element,
|
||||||
|
override = true,
|
||||||
|
)
|
||||||
|
if (element.transformByChildren) {
|
||||||
|
printBlock {
|
||||||
|
println(element.visitorParameterName, ".transformChildren(this, data)")
|
||||||
|
println("return ", element.visitorParameterName)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println(" =")
|
||||||
|
withIndent {
|
||||||
|
println(parent!!.visitFunctionName, "(", element.visitorParameterName, ", data)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun printTransformer(generationPath: File, model: Model): GeneratedFile =
|
||||||
|
printVisitorCommon(generationPath, model, elementTransformerType) { printer, visitorType ->
|
||||||
|
TransformerPrinter(printer, visitorType, model.rootElement)
|
||||||
|
}
|
||||||
+142
@@ -0,0 +1,142 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 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.ir.generator.print
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.Modality
|
||||||
|
import org.jetbrains.kotlin.generators.tree.*
|
||||||
|
import org.jetbrains.kotlin.generators.tree.printer.*
|
||||||
|
import org.jetbrains.kotlin.ir.generator.IrTree
|
||||||
|
import org.jetbrains.kotlin.ir.generator.TREE_GENERATOR_README
|
||||||
|
import org.jetbrains.kotlin.ir.generator.elementTransformerType
|
||||||
|
import org.jetbrains.kotlin.ir.generator.elementTransformerVoidType
|
||||||
|
import org.jetbrains.kotlin.ir.generator.model.Element
|
||||||
|
import org.jetbrains.kotlin.ir.generator.model.Field
|
||||||
|
import org.jetbrains.kotlin.ir.generator.model.Model
|
||||||
|
import org.jetbrains.kotlin.utils.SmartPrinter
|
||||||
|
import org.jetbrains.kotlin.utils.withIndent
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
private class TransformerVoidPrinter(
|
||||||
|
printer: SmartPrinter,
|
||||||
|
override val visitorType: ClassRef<*>,
|
||||||
|
) : AbstractVisitorPrinter<Element, Field>(printer) {
|
||||||
|
|
||||||
|
override val visitorTypeParameters: List<TypeVariable>
|
||||||
|
get() = emptyList()
|
||||||
|
|
||||||
|
override val visitorSuperType: ClassRef<PositionTypeParameterRef>
|
||||||
|
get() = elementTransformerType.withArgs(visitorDataType)
|
||||||
|
|
||||||
|
override val visitorDataType: TypeRef
|
||||||
|
get() = StandardTypes.nothing.copy(nullable = true)
|
||||||
|
|
||||||
|
// IrPackageFragment is treated as transformByChildren in IrElementTransformerVoid for historical reasons.
|
||||||
|
private val Element.isPackageFragment: Boolean
|
||||||
|
get() = this == IrTree.packageFragment
|
||||||
|
|
||||||
|
// Despite IrFile and IrExternalPackageFragment being transformByChildren, we treat them differently in IrElementTransformerVoid
|
||||||
|
// than in IrElementTransformer for historical reasons. We want to preserve the historical semantics here.
|
||||||
|
private val Element.isPackageFragmentChild: Boolean
|
||||||
|
get() = elementParents.any { it.element.isPackageFragment }
|
||||||
|
|
||||||
|
private val Element.transformByChildrenVoid: Boolean
|
||||||
|
get() = element.transformByChildren || isPackageFragment
|
||||||
|
|
||||||
|
override fun visitMethodReturnType(element: Element): Element =
|
||||||
|
when {
|
||||||
|
element.isPackageFragment -> element
|
||||||
|
element.transformByChildren -> element.getTransformExplicitType()
|
||||||
|
else -> element.parentInVisitor?.let(this::visitMethodReturnType) ?: element
|
||||||
|
}
|
||||||
|
|
||||||
|
override val allowTypeParametersInVisitorMethods: Boolean
|
||||||
|
get() = false
|
||||||
|
|
||||||
|
context(ImportCollector)
|
||||||
|
override fun SmartPrinter.printAdditionalMethods() {
|
||||||
|
println()
|
||||||
|
val typeParameter = TypeVariable("T", listOf(IrTree.rootElement))
|
||||||
|
printFunctionWithBlockBody(
|
||||||
|
name = "transformPostfix",
|
||||||
|
parameters = listOf(FunctionParameter("body", Lambda(receiver = typeParameter, returnType = StandardTypes.unit))),
|
||||||
|
returnType = typeParameter,
|
||||||
|
typeParameters = listOf(typeParameter),
|
||||||
|
extensionReceiver = typeParameter,
|
||||||
|
visibility = Visibility.PROTECTED,
|
||||||
|
isInline = true,
|
||||||
|
) {
|
||||||
|
println("transformChildrenVoid()")
|
||||||
|
println("this.body()")
|
||||||
|
println("return this")
|
||||||
|
}
|
||||||
|
println()
|
||||||
|
printFunctionWithBlockBody(
|
||||||
|
name = "transformChildrenVoid",
|
||||||
|
parameters = emptyList(),
|
||||||
|
returnType = StandardTypes.unit,
|
||||||
|
extensionReceiver = IrTree.rootElement,
|
||||||
|
visibility = Visibility.PROTECTED,
|
||||||
|
) {
|
||||||
|
println("transformChildrenVoid(this@", visitorType.simpleName, ")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context(ImportCollector)
|
||||||
|
override fun printMethodsForElement(element: Element) {
|
||||||
|
val parent = element.parentInVisitor
|
||||||
|
if (!element.transformByChildrenVoid && parent == null) return
|
||||||
|
printer.run {
|
||||||
|
println()
|
||||||
|
printVisitMethodDeclaration(element, hasDataParameter = false, modality = Modality.OPEN)
|
||||||
|
if (element.transformByChildrenVoid && !element.isPackageFragmentChild) {
|
||||||
|
printBlock {
|
||||||
|
println(element.visitorParameterName, ".transformChildren(this, null)")
|
||||||
|
println("return ", element.visitorParameterName)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println(" =")
|
||||||
|
withIndent {
|
||||||
|
print(parent!!.visitFunctionName, "(", element.visitorParameterName, ")")
|
||||||
|
if (element.isPackageFragmentChild) {
|
||||||
|
print(" as ", element.render())
|
||||||
|
}
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println()
|
||||||
|
printVisitMethodDeclaration(
|
||||||
|
element = element,
|
||||||
|
modality = Modality.FINAL,
|
||||||
|
override = true,
|
||||||
|
returnType = element.getTransformExplicitType(),
|
||||||
|
)
|
||||||
|
println(" =")
|
||||||
|
withIndent {
|
||||||
|
println(element.visitFunctionName, "(", element.visitorParameterName, ")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun printTransformerVoid(generationPath: File, model: Model): GeneratedFile =
|
||||||
|
printGeneratedType(
|
||||||
|
generationPath,
|
||||||
|
TREE_GENERATOR_README,
|
||||||
|
elementTransformerVoidType.packageName,
|
||||||
|
elementTransformerVoidType.simpleName,
|
||||||
|
) {
|
||||||
|
TransformerVoidPrinter(this, elementTransformerVoidType).printVisitor(model.elements)
|
||||||
|
println()
|
||||||
|
val transformerParameter = FunctionParameter("transformer", elementTransformerVoidType)
|
||||||
|
printFunctionWithBlockBody(
|
||||||
|
name = "transformChildrenVoid",
|
||||||
|
parameters = listOf(transformerParameter),
|
||||||
|
returnType = StandardTypes.unit,
|
||||||
|
extensionReceiver = IrTree.rootElement,
|
||||||
|
) {
|
||||||
|
println("transformChildren(", transformerParameter.name, ", null)")
|
||||||
|
}
|
||||||
|
}
|
||||||
+162
@@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 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.ir.generator.print
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.generators.tree.*
|
||||||
|
import org.jetbrains.kotlin.generators.tree.printer.FunctionParameter
|
||||||
|
import org.jetbrains.kotlin.generators.tree.printer.GeneratedFile
|
||||||
|
import org.jetbrains.kotlin.generators.tree.printer.printBlock
|
||||||
|
import org.jetbrains.kotlin.generators.tree.printer.printFunctionDeclaration
|
||||||
|
import org.jetbrains.kotlin.ir.generator.IrTree
|
||||||
|
import org.jetbrains.kotlin.ir.generator.elementTransformerType
|
||||||
|
import org.jetbrains.kotlin.ir.generator.irTypeType
|
||||||
|
import org.jetbrains.kotlin.ir.generator.model.Element
|
||||||
|
import org.jetbrains.kotlin.ir.generator.model.Field
|
||||||
|
import org.jetbrains.kotlin.ir.generator.model.ListField
|
||||||
|
import org.jetbrains.kotlin.ir.generator.model.Model
|
||||||
|
import org.jetbrains.kotlin.ir.generator.model.SingleField
|
||||||
|
import org.jetbrains.kotlin.ir.generator.typeTransformerType
|
||||||
|
import org.jetbrains.kotlin.utils.SmartPrinter
|
||||||
|
import org.jetbrains.kotlin.utils.withIndent
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
private class TypeTransformerPrinter(
|
||||||
|
printer: SmartPrinter,
|
||||||
|
override val visitorType: ClassRef<*>,
|
||||||
|
val rootElement: Element,
|
||||||
|
) : AbstractVisitorPrinter<Element, Field>(printer) {
|
||||||
|
|
||||||
|
override val visitorSuperType: ClassRef<PositionTypeParameterRef>
|
||||||
|
get() = elementTransformerType.withArgs(dataTypeVariable)
|
||||||
|
|
||||||
|
override val visitorTypeParameters: List<TypeVariable>
|
||||||
|
get() = listOf(dataTypeVariable)
|
||||||
|
|
||||||
|
override val visitorDataType: TypeRef
|
||||||
|
get() = dataTypeVariable
|
||||||
|
|
||||||
|
override fun visitMethodReturnType(element: Element) = element.getTransformExplicitType()
|
||||||
|
|
||||||
|
override val allowTypeParametersInVisitorMethods: Boolean
|
||||||
|
get() = false
|
||||||
|
|
||||||
|
private fun Element.getFieldsWithIrTypeType(insideParent: Boolean = false): List<Field> {
|
||||||
|
val parentsFields = elementParents.flatMap { it.element.getFieldsWithIrTypeType(insideParent = true) }
|
||||||
|
if (insideParent && this.parentInVisitor != null) {
|
||||||
|
return parentsFields
|
||||||
|
}
|
||||||
|
|
||||||
|
val irTypeFields = this.fields
|
||||||
|
.filter {
|
||||||
|
val type = when (it) {
|
||||||
|
is SingleField -> it.typeRef
|
||||||
|
is ListField -> it.baseType
|
||||||
|
}
|
||||||
|
type.toString() == irTypeType.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
return irTypeFields + parentsFields
|
||||||
|
}
|
||||||
|
|
||||||
|
context(ImportCollector)
|
||||||
|
override fun SmartPrinter.printAdditionalMethods() {
|
||||||
|
val typeTP = TypeVariable("Type", listOf(irTypeType.copy(nullable = true)))
|
||||||
|
printFunctionDeclaration(
|
||||||
|
name = "transformType",
|
||||||
|
parameters = listOf(
|
||||||
|
FunctionParameter("container", rootElement),
|
||||||
|
FunctionParameter("type", typeTP),
|
||||||
|
FunctionParameter("data", visitorDataType)
|
||||||
|
),
|
||||||
|
returnType = typeTP,
|
||||||
|
typeParameters = listOf(typeTP),
|
||||||
|
)
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
|
||||||
|
context(ImportCollector)
|
||||||
|
override fun printMethodsForElement(element: Element) {
|
||||||
|
val irTypeFields = element.getFieldsWithIrTypeType()
|
||||||
|
if (irTypeFields.isEmpty()) return
|
||||||
|
if (element.parentInVisitor == null) return
|
||||||
|
printer.run {
|
||||||
|
println()
|
||||||
|
val visitorParam = element.visitorParameterName
|
||||||
|
printVisitMethodDeclaration(
|
||||||
|
element = element,
|
||||||
|
override = true,
|
||||||
|
)
|
||||||
|
|
||||||
|
fun addVisitTypeStatement(field: Field) {
|
||||||
|
val access = "$visitorParam.${field.name}"
|
||||||
|
when (field) {
|
||||||
|
is SingleField -> println(access, " = ", "transformType(", visitorParam, ", ", access, ", data)")
|
||||||
|
is ListField -> {
|
||||||
|
if (field.isMutable) {
|
||||||
|
println(access, " = ", access, ".map { transformType(", visitorParam, ", it, data) }")
|
||||||
|
} else {
|
||||||
|
println("for (i in 0 until ", access, ".size) {")
|
||||||
|
withIndent {
|
||||||
|
println(access, "[i] = transformType(", visitorParam, ", ", access, "[i], data)")
|
||||||
|
}
|
||||||
|
println("}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printBlock {
|
||||||
|
when (element) {
|
||||||
|
IrTree.memberAccessExpression -> {
|
||||||
|
if (irTypeFields.singleOrNull()?.name != "typeArguments") {
|
||||||
|
error(
|
||||||
|
"""`${IrTree.memberAccessExpression.typeName}` has unexpected fields with `IrType` type.
|
||||||
|
|Please adjust logic of `${visitorType.simpleName}`'s generation.""".trimMargin()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
println("(0 until ", visitorParam, ".typeArgumentsCount).forEach {")
|
||||||
|
withIndent {
|
||||||
|
println(visitorParam, ".getTypeArgument(it)?.let { type ->")
|
||||||
|
withIndent {
|
||||||
|
println(
|
||||||
|
visitorParam,
|
||||||
|
".putTypeArgument(it, transformType(",
|
||||||
|
visitorParam,
|
||||||
|
", type, data))"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
println("}")
|
||||||
|
}
|
||||||
|
println("}")
|
||||||
|
}
|
||||||
|
IrTree.`class` -> {
|
||||||
|
println(visitorParam, ".valueClassRepresentation?.mapUnderlyingType {")
|
||||||
|
withIndent {
|
||||||
|
println("transformType(", visitorParam, ", it, data)")
|
||||||
|
}
|
||||||
|
println("}")
|
||||||
|
irTypeFields.forEach(::addVisitTypeStatement)
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
irTypeFields.forEach(::addVisitTypeStatement)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println(
|
||||||
|
"return super.",
|
||||||
|
element.visitFunctionName,
|
||||||
|
"(",
|
||||||
|
visitorParam,
|
||||||
|
", data)"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun printTypeVisitor(generationPath: File, model: Model): GeneratedFile =
|
||||||
|
printVisitorCommon(generationPath, model, typeTransformerType) { printer, visitorType ->
|
||||||
|
TypeTransformerPrinter(printer, visitorType, model.rootElement)
|
||||||
|
}
|
||||||
-355
@@ -5,27 +5,13 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.generator.print
|
package org.jetbrains.kotlin.ir.generator.print
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.Modality
|
|
||||||
import org.jetbrains.kotlin.generators.tree.*
|
import org.jetbrains.kotlin.generators.tree.*
|
||||||
import org.jetbrains.kotlin.generators.tree.printer.*
|
|
||||||
import org.jetbrains.kotlin.ir.generator.*
|
import org.jetbrains.kotlin.ir.generator.*
|
||||||
import org.jetbrains.kotlin.ir.generator.model.*
|
import org.jetbrains.kotlin.ir.generator.model.*
|
||||||
import org.jetbrains.kotlin.ir.generator.model.ListField
|
|
||||||
import org.jetbrains.kotlin.ir.generator.model.Model
|
import org.jetbrains.kotlin.ir.generator.model.Model
|
||||||
import org.jetbrains.kotlin.utils.SmartPrinter
|
import org.jetbrains.kotlin.utils.SmartPrinter
|
||||||
import org.jetbrains.kotlin.utils.withIndent
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
private fun printVisitorCommon(
|
|
||||||
generationPath: File,
|
|
||||||
model: Model,
|
|
||||||
visitorType: ClassRef<*>,
|
|
||||||
makePrinter: (SmartPrinter, ClassRef<*>) -> AbstractVisitorPrinter<Element, Field>,
|
|
||||||
): GeneratedFile =
|
|
||||||
printGeneratedType(generationPath, TREE_GENERATOR_README, visitorType.packageName, visitorType.simpleName) {
|
|
||||||
makePrinter(this, visitorType).printVisitor(model.elements)
|
|
||||||
}
|
|
||||||
|
|
||||||
private open class VisitorPrinter(printer: SmartPrinter, override val visitorType: ClassRef<*>) :
|
private open class VisitorPrinter(printer: SmartPrinter, override val visitorType: ClassRef<*>) :
|
||||||
AbstractVisitorPrinter<Element, Field>(printer) {
|
AbstractVisitorPrinter<Element, Field>(printer) {
|
||||||
|
|
||||||
@@ -46,344 +32,3 @@ private open class VisitorPrinter(printer: SmartPrinter, override val visitorTyp
|
|||||||
|
|
||||||
fun printVisitor(generationPath: File, model: Model) = printVisitorCommon(generationPath, model, elementVisitorType, ::VisitorPrinter)
|
fun printVisitor(generationPath: File, model: Model) = printVisitorCommon(generationPath, model, elementVisitorType, ::VisitorPrinter)
|
||||||
|
|
||||||
private class VisitorVoidPrinter(
|
|
||||||
printer: SmartPrinter,
|
|
||||||
override val visitorType: ClassRef<*>,
|
|
||||||
) : AbstractVisitorVoidPrinter<Element, Field>(printer) {
|
|
||||||
|
|
||||||
override val visitorSuperClass: ClassRef<PositionTypeParameterRef>
|
|
||||||
get() = elementVisitorType
|
|
||||||
|
|
||||||
override val allowTypeParametersInVisitorMethods: Boolean
|
|
||||||
get() = false
|
|
||||||
|
|
||||||
override val useAbstractMethodForRootElement: Boolean
|
|
||||||
get() = false
|
|
||||||
|
|
||||||
override val overriddenVisitMethodsAreFinal: Boolean
|
|
||||||
get() = false
|
|
||||||
}
|
|
||||||
|
|
||||||
fun printVisitorVoid(generationPath: File, model: Model) =
|
|
||||||
printVisitorCommon(generationPath, model, elementVisitorVoidType, ::VisitorVoidPrinter)
|
|
||||||
|
|
||||||
private class TransformerPrinter(
|
|
||||||
printer: SmartPrinter,
|
|
||||||
override val visitorType: ClassRef<*>,
|
|
||||||
val rootElement: Element,
|
|
||||||
) : AbstractVisitorPrinter<Element, Field>(printer) {
|
|
||||||
|
|
||||||
override val visitorSuperType: ClassRef<PositionTypeParameterRef>
|
|
||||||
get() = elementVisitorType.withArgs(rootElement, dataTypeVariable)
|
|
||||||
|
|
||||||
override val visitorTypeParameters: List<TypeVariable>
|
|
||||||
get() = listOf(dataTypeVariable)
|
|
||||||
|
|
||||||
override val visitorDataType: TypeRef
|
|
||||||
get() = dataTypeVariable
|
|
||||||
|
|
||||||
override fun visitMethodReturnType(element: Element) = element.getTransformExplicitType()
|
|
||||||
|
|
||||||
override val allowTypeParametersInVisitorMethods: Boolean
|
|
||||||
get() = false
|
|
||||||
|
|
||||||
context(ImportCollector)
|
|
||||||
override fun printMethodsForElement(element: Element) {
|
|
||||||
printer.run {
|
|
||||||
val parent = element.parentInVisitor
|
|
||||||
if (element.transformByChildren || parent != null) {
|
|
||||||
println()
|
|
||||||
printVisitMethodDeclaration(
|
|
||||||
element = element,
|
|
||||||
override = true,
|
|
||||||
)
|
|
||||||
if (element.transformByChildren) {
|
|
||||||
printBlock {
|
|
||||||
println(element.visitorParameterName, ".transformChildren(this, data)")
|
|
||||||
println("return ", element.visitorParameterName)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println(" =")
|
|
||||||
withIndent {
|
|
||||||
println(parent!!.visitFunctionName, "(", element.visitorParameterName, ", data)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun printTransformer(generationPath: File, model: Model): GeneratedFile =
|
|
||||||
printVisitorCommon(generationPath, model, elementTransformerType) { printer, visitorType ->
|
|
||||||
TransformerPrinter(printer, visitorType, model.rootElement)
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TransformerVoidPrinter(
|
|
||||||
printer: SmartPrinter,
|
|
||||||
override val visitorType: ClassRef<*>,
|
|
||||||
) : AbstractVisitorPrinter<Element, Field>(printer) {
|
|
||||||
|
|
||||||
override val visitorTypeParameters: List<TypeVariable>
|
|
||||||
get() = emptyList()
|
|
||||||
|
|
||||||
override val visitorSuperType: ClassRef<PositionTypeParameterRef>
|
|
||||||
get() = elementTransformerType.withArgs(visitorDataType)
|
|
||||||
|
|
||||||
override val visitorDataType: TypeRef
|
|
||||||
get() = StandardTypes.nothing.copy(nullable = true)
|
|
||||||
|
|
||||||
// IrPackageFragment is treated as transformByChildren in IrElementTransformerVoid for historical reasons.
|
|
||||||
private val Element.isPackageFragment: Boolean
|
|
||||||
get() = this == IrTree.packageFragment
|
|
||||||
|
|
||||||
// Despite IrFile and IrExternalPackageFragment being transformByChildren, we treat them differently in IrElementTransformerVoid
|
|
||||||
// than in IrElementTransformer for historical reasons. We want to preserve the historical semantics here.
|
|
||||||
private val Element.isPackageFragmentChild: Boolean
|
|
||||||
get() = elementParents.any { it.element.isPackageFragment }
|
|
||||||
|
|
||||||
private val Element.transformByChildrenVoid: Boolean
|
|
||||||
get() = element.transformByChildren || isPackageFragment
|
|
||||||
|
|
||||||
override fun visitMethodReturnType(element: Element): Element =
|
|
||||||
when {
|
|
||||||
element.isPackageFragment -> element
|
|
||||||
element.transformByChildren -> element.getTransformExplicitType()
|
|
||||||
else -> element.parentInVisitor?.let(this::visitMethodReturnType) ?: element
|
|
||||||
}
|
|
||||||
|
|
||||||
override val allowTypeParametersInVisitorMethods: Boolean
|
|
||||||
get() = false
|
|
||||||
|
|
||||||
context(ImportCollector)
|
|
||||||
override fun SmartPrinter.printAdditionalMethods() {
|
|
||||||
println()
|
|
||||||
val typeParameter = TypeVariable("T", listOf(IrTree.rootElement))
|
|
||||||
printFunctionWithBlockBody(
|
|
||||||
name = "transformPostfix",
|
|
||||||
parameters = listOf(FunctionParameter("body", Lambda(receiver = typeParameter, returnType = StandardTypes.unit))),
|
|
||||||
returnType = typeParameter,
|
|
||||||
typeParameters = listOf(typeParameter),
|
|
||||||
extensionReceiver = typeParameter,
|
|
||||||
visibility = Visibility.PROTECTED,
|
|
||||||
isInline = true,
|
|
||||||
) {
|
|
||||||
println("transformChildrenVoid()")
|
|
||||||
println("this.body()")
|
|
||||||
println("return this")
|
|
||||||
}
|
|
||||||
println()
|
|
||||||
printFunctionWithBlockBody(
|
|
||||||
name = "transformChildrenVoid",
|
|
||||||
parameters = emptyList(),
|
|
||||||
returnType = StandardTypes.unit,
|
|
||||||
extensionReceiver = IrTree.rootElement,
|
|
||||||
visibility = Visibility.PROTECTED,
|
|
||||||
) {
|
|
||||||
println("transformChildrenVoid(this@", visitorType.simpleName, ")")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
context(ImportCollector)
|
|
||||||
override fun printMethodsForElement(element: Element) {
|
|
||||||
val parent = element.parentInVisitor
|
|
||||||
if (!element.transformByChildrenVoid && parent == null) return
|
|
||||||
printer.run {
|
|
||||||
println()
|
|
||||||
printVisitMethodDeclaration(element, hasDataParameter = false, modality = Modality.OPEN)
|
|
||||||
if (element.transformByChildrenVoid && !element.isPackageFragmentChild) {
|
|
||||||
printBlock {
|
|
||||||
println(element.visitorParameterName, ".transformChildren(this, null)")
|
|
||||||
println("return ", element.visitorParameterName)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
println(" =")
|
|
||||||
withIndent {
|
|
||||||
print(parent!!.visitFunctionName, "(", element.visitorParameterName, ")")
|
|
||||||
if (element.isPackageFragmentChild) {
|
|
||||||
print(" as ", element.render())
|
|
||||||
}
|
|
||||||
println()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println()
|
|
||||||
printVisitMethodDeclaration(
|
|
||||||
element = element,
|
|
||||||
modality = Modality.FINAL,
|
|
||||||
override = true,
|
|
||||||
returnType = element.getTransformExplicitType(),
|
|
||||||
)
|
|
||||||
println(" =")
|
|
||||||
withIndent {
|
|
||||||
println(element.visitFunctionName, "(", element.visitorParameterName, ")")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun printTransformerVoid(generationPath: File, model: Model): GeneratedFile =
|
|
||||||
printGeneratedType(
|
|
||||||
generationPath,
|
|
||||||
TREE_GENERATOR_README,
|
|
||||||
elementTransformerVoidType.packageName,
|
|
||||||
elementTransformerVoidType.simpleName,
|
|
||||||
) {
|
|
||||||
TransformerVoidPrinter(this, elementTransformerVoidType).printVisitor(model.elements)
|
|
||||||
println()
|
|
||||||
val transformerParameter = FunctionParameter("transformer", elementTransformerVoidType)
|
|
||||||
printFunctionWithBlockBody(
|
|
||||||
name = "transformChildrenVoid",
|
|
||||||
parameters = listOf(transformerParameter),
|
|
||||||
returnType = StandardTypes.unit,
|
|
||||||
extensionReceiver = IrTree.rootElement,
|
|
||||||
) {
|
|
||||||
println("transformChildren(", transformerParameter.name, ", null)")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class TypeTransformerPrinter(
|
|
||||||
printer: SmartPrinter,
|
|
||||||
override val visitorType: ClassRef<*>,
|
|
||||||
val rootElement: Element,
|
|
||||||
) : AbstractVisitorPrinter<Element, Field>(printer) {
|
|
||||||
|
|
||||||
override val visitorSuperType: ClassRef<PositionTypeParameterRef>
|
|
||||||
get() = elementTransformerType.withArgs(dataTypeVariable)
|
|
||||||
|
|
||||||
override val visitorTypeParameters: List<TypeVariable>
|
|
||||||
get() = listOf(dataTypeVariable)
|
|
||||||
|
|
||||||
override val visitorDataType: TypeRef
|
|
||||||
get() = dataTypeVariable
|
|
||||||
|
|
||||||
override fun visitMethodReturnType(element: Element) = element.getTransformExplicitType()
|
|
||||||
|
|
||||||
override val allowTypeParametersInVisitorMethods: Boolean
|
|
||||||
get() = false
|
|
||||||
|
|
||||||
private fun Element.getFieldsWithIrTypeType(insideParent: Boolean = false): List<Field> {
|
|
||||||
val parentsFields = elementParents.flatMap { it.element.getFieldsWithIrTypeType(insideParent = true) }
|
|
||||||
if (insideParent && this.parentInVisitor != null) {
|
|
||||||
return parentsFields
|
|
||||||
}
|
|
||||||
|
|
||||||
val irTypeFields = this.fields
|
|
||||||
.filter {
|
|
||||||
val type = when (it) {
|
|
||||||
is SingleField -> it.typeRef
|
|
||||||
is ListField -> it.baseType
|
|
||||||
}
|
|
||||||
type.toString() == irTypeType.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
return irTypeFields + parentsFields
|
|
||||||
}
|
|
||||||
|
|
||||||
context(ImportCollector)
|
|
||||||
override fun SmartPrinter.printAdditionalMethods() {
|
|
||||||
val typeTP = TypeVariable("Type", listOf(irTypeType.copy(nullable = true)))
|
|
||||||
printFunctionDeclaration(
|
|
||||||
name = "transformType",
|
|
||||||
parameters = listOf(
|
|
||||||
FunctionParameter("container", rootElement),
|
|
||||||
FunctionParameter("type", typeTP),
|
|
||||||
FunctionParameter("data", visitorDataType)
|
|
||||||
),
|
|
||||||
returnType = typeTP,
|
|
||||||
typeParameters = listOf(typeTP),
|
|
||||||
)
|
|
||||||
println()
|
|
||||||
}
|
|
||||||
|
|
||||||
context(ImportCollector)
|
|
||||||
override fun printMethodsForElement(element: Element) {
|
|
||||||
val irTypeFields = element.getFieldsWithIrTypeType()
|
|
||||||
if (irTypeFields.isEmpty()) return
|
|
||||||
if (element.parentInVisitor == null) return
|
|
||||||
printer.run {
|
|
||||||
println()
|
|
||||||
val visitorParam = element.visitorParameterName
|
|
||||||
printVisitMethodDeclaration(
|
|
||||||
element = element,
|
|
||||||
override = true,
|
|
||||||
)
|
|
||||||
|
|
||||||
fun addVisitTypeStatement(field: Field) {
|
|
||||||
val access = "$visitorParam.${field.name}"
|
|
||||||
when (field) {
|
|
||||||
is SingleField -> println(access, " = ", "transformType(", visitorParam, ", ", access, ", data)")
|
|
||||||
is ListField -> {
|
|
||||||
if (field.isMutable) {
|
|
||||||
println(access, " = ", access, ".map { transformType(", visitorParam, ", it, data) }")
|
|
||||||
} else {
|
|
||||||
println("for (i in 0 until ", access, ".size) {")
|
|
||||||
withIndent {
|
|
||||||
println(access, "[i] = transformType(", visitorParam, ", ", access, "[i], data)")
|
|
||||||
}
|
|
||||||
println("}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printBlock {
|
|
||||||
when (element) {
|
|
||||||
IrTree.memberAccessExpression -> {
|
|
||||||
if (irTypeFields.singleOrNull()?.name != "typeArguments") {
|
|
||||||
error(
|
|
||||||
"""`${IrTree.memberAccessExpression.typeName}` has unexpected fields with `IrType` type.
|
|
||||||
|Please adjust logic of `${visitorType.simpleName}`'s generation.""".trimMargin()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
println("(0 until ", visitorParam, ".typeArgumentsCount).forEach {")
|
|
||||||
withIndent {
|
|
||||||
println(visitorParam, ".getTypeArgument(it)?.let { type ->")
|
|
||||||
withIndent {
|
|
||||||
println(
|
|
||||||
visitorParam,
|
|
||||||
".putTypeArgument(it, transformType(",
|
|
||||||
visitorParam,
|
|
||||||
", type, data))"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
println("}")
|
|
||||||
}
|
|
||||||
println("}")
|
|
||||||
}
|
|
||||||
IrTree.`class` -> {
|
|
||||||
println(visitorParam, ".valueClassRepresentation?.mapUnderlyingType {")
|
|
||||||
withIndent {
|
|
||||||
println("transformType(", visitorParam, ", it, data)")
|
|
||||||
}
|
|
||||||
println("}")
|
|
||||||
irTypeFields.forEach(::addVisitTypeStatement)
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
irTypeFields.forEach(::addVisitTypeStatement)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println(
|
|
||||||
"return super.",
|
|
||||||
element.visitFunctionName,
|
|
||||||
"(",
|
|
||||||
visitorParam,
|
|
||||||
", data)"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun printTypeVisitor(generationPath: File, model: Model): GeneratedFile =
|
|
||||||
printVisitorCommon(generationPath, model, typeTransformerType) { printer, visitorType ->
|
|
||||||
TypeTransformerPrinter(printer, visitorType, model.rootElement)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Element.getTransformExplicitType(): Element {
|
|
||||||
return generateSequence(this) { it.parentInVisitor }
|
|
||||||
.firstNotNullOfOrNull {
|
|
||||||
when {
|
|
||||||
it.transformByChildren -> it.transformerReturnType ?: it
|
|
||||||
else -> it.transformerReturnType
|
|
||||||
}
|
|
||||||
} ?: this
|
|
||||||
}
|
|
||||||
|
|||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 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.ir.generator.print
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.generators.tree.AbstractVisitorVoidPrinter
|
||||||
|
import org.jetbrains.kotlin.generators.tree.ClassRef
|
||||||
|
import org.jetbrains.kotlin.generators.tree.PositionTypeParameterRef
|
||||||
|
import org.jetbrains.kotlin.ir.generator.elementVisitorType
|
||||||
|
import org.jetbrains.kotlin.ir.generator.elementVisitorVoidType
|
||||||
|
import org.jetbrains.kotlin.ir.generator.model.Element
|
||||||
|
import org.jetbrains.kotlin.ir.generator.model.Field
|
||||||
|
import org.jetbrains.kotlin.ir.generator.model.Model
|
||||||
|
import org.jetbrains.kotlin.utils.SmartPrinter
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
private class VisitorVoidPrinter(
|
||||||
|
printer: SmartPrinter,
|
||||||
|
override val visitorType: ClassRef<*>,
|
||||||
|
) : AbstractVisitorVoidPrinter<Element, Field>(printer) {
|
||||||
|
|
||||||
|
override val visitorSuperClass: ClassRef<PositionTypeParameterRef>
|
||||||
|
get() = elementVisitorType
|
||||||
|
|
||||||
|
override val allowTypeParametersInVisitorMethods: Boolean
|
||||||
|
get() = false
|
||||||
|
|
||||||
|
override val useAbstractMethodForRootElement: Boolean
|
||||||
|
get() = false
|
||||||
|
|
||||||
|
override val overriddenVisitMethodsAreFinal: Boolean
|
||||||
|
get() = false
|
||||||
|
}
|
||||||
|
|
||||||
|
fun printVisitorVoid(generationPath: File, model: Model) =
|
||||||
|
printVisitorCommon(generationPath, model, elementVisitorVoidType, ::VisitorVoidPrinter)
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 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.ir.generator.print
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.generators.tree.AbstractVisitorPrinter
|
||||||
|
import org.jetbrains.kotlin.generators.tree.ClassRef
|
||||||
|
import org.jetbrains.kotlin.generators.tree.printer.GeneratedFile
|
||||||
|
import org.jetbrains.kotlin.generators.tree.printer.printGeneratedType
|
||||||
|
import org.jetbrains.kotlin.ir.generator.TREE_GENERATOR_README
|
||||||
|
import org.jetbrains.kotlin.ir.generator.model.Element
|
||||||
|
import org.jetbrains.kotlin.ir.generator.model.Field
|
||||||
|
import org.jetbrains.kotlin.ir.generator.model.Model
|
||||||
|
import org.jetbrains.kotlin.utils.SmartPrinter
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
internal fun printVisitorCommon(
|
||||||
|
generationPath: File,
|
||||||
|
model: Model,
|
||||||
|
visitorType: ClassRef<*>,
|
||||||
|
makePrinter: (SmartPrinter, ClassRef<*>) -> AbstractVisitorPrinter<Element, Field>,
|
||||||
|
): GeneratedFile =
|
||||||
|
printGeneratedType(generationPath, TREE_GENERATOR_README, visitorType.packageName, visitorType.simpleName) {
|
||||||
|
makePrinter(this, visitorType).printVisitor(model.elements)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun Element.getTransformExplicitType(): Element {
|
||||||
|
return generateSequence(this) { it.parentInVisitor }
|
||||||
|
.firstNotNullOfOrNull {
|
||||||
|
when {
|
||||||
|
it.transformByChildren -> it.transformerReturnType ?: it
|
||||||
|
else -> it.transformerReturnType
|
||||||
|
}
|
||||||
|
} ?: this
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user