[FIR] Automatically generated abstract classes instead of interfaces if possible
This commit is contained in:
@@ -81,3 +81,9 @@ elementName.configure {
|
||||
- `defaultNull(fieldName, [withGetter: Boolean])`
|
||||
- If some fields should be `lateinit` you describe them in call `lateinit(vararg fields: String)`
|
||||
- If you use some types that shoub be imported list them in method `useTypes(vararg types: Type/Element)`
|
||||
|
||||
# Notes
|
||||
|
||||
- There is algorithm that automatically makes as most abstract classes instead of interfaces as possible. If you want to some `Element` or `Implementation` should be always an interface you should:
|
||||
- call `shouldBeAnInterface` when configuring a `Element` in `NodeConfigurator.kt`
|
||||
- specify `kind = Interface` when configuring an `Implementation` in `ImplementationConfigurator.kt`
|
||||
+8
-27
@@ -19,20 +19,13 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
||||
}
|
||||
|
||||
private fun configure() = with(FirTreeBuilder) {
|
||||
val callWithArgumentList = impl(call, "FirCallWithArgumentList") {
|
||||
kind = Interface
|
||||
}
|
||||
val callWithArgumentList = impl(call, "FirCallWithArgumentList")
|
||||
|
||||
abstractAnnotatedElement = impl(annotationContainer, "FirAbstractAnnotatedElement") {
|
||||
kind = Interface
|
||||
}
|
||||
abstractAnnotatedElement = impl(annotationContainer, "FirAbstractAnnotatedElement")
|
||||
|
||||
val modifiableTypeParametersOwner = impl(typeParametersOwner, "FirModifiableTypeParametersOwner") {
|
||||
kind = Interface
|
||||
}
|
||||
val modifiableTypeParametersOwner = impl(typeParametersOwner, "FirModifiableTypeParametersOwner")
|
||||
|
||||
val modifiableConstructor = impl(constructor, "FirModifiableConstructor") {
|
||||
kind = Interface
|
||||
parents += modifiableTypeParametersOwner
|
||||
}
|
||||
|
||||
@@ -57,14 +50,11 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
||||
noImpl(resolvedDeclarationStatus)
|
||||
noImpl(field)
|
||||
|
||||
val modifiableClass = impl(klass, "FirModifiableClass") {
|
||||
kind = Interface
|
||||
}
|
||||
val modifiableClass = impl(klass, "FirModifiableClass")
|
||||
|
||||
val modifiableRegularClass = impl(regularClass, "FirModifiableRegularClass") {
|
||||
parents += modifiableClass
|
||||
parents += modifiableTypeParametersOwner
|
||||
kind = Interface
|
||||
}
|
||||
|
||||
val regularClassConfig: ImplementationContext.() -> Unit = {
|
||||
@@ -153,7 +143,6 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
||||
}
|
||||
|
||||
val modifiableQualifiedAccess = impl(qualifiedAccessWithoutCallee, "FirModifiableQualifiedAccess") {
|
||||
kind = Interface
|
||||
isMutable("safe")
|
||||
}
|
||||
|
||||
@@ -196,9 +185,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
||||
useTypes(simpleNamedReferenceType, nameType, noReceiverExpressionType)
|
||||
}
|
||||
|
||||
val abstractLoop = impl(loop, "FirAbstractLoop") {
|
||||
kind = Interface
|
||||
}
|
||||
val abstractLoop = impl(loop, "FirAbstractLoop")
|
||||
|
||||
impl(whileLoop) {
|
||||
parents += abstractLoop
|
||||
@@ -230,8 +217,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
||||
useTypes(implicitBooleanTypeRefType)
|
||||
}
|
||||
|
||||
impl(block) {
|
||||
}
|
||||
impl(block)
|
||||
|
||||
val emptyExpressionBlock = impl(block, "FirEmptyExpressionBlock") {
|
||||
// TODO: make statements immutable
|
||||
@@ -274,9 +260,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
||||
}
|
||||
}
|
||||
|
||||
val modifiableVariable = impl(variable, "FirModifiableVariable") {
|
||||
kind = Interface
|
||||
}
|
||||
val modifiableVariable = impl(variable, "FirModifiableVariable")
|
||||
|
||||
impl(property) {
|
||||
parents += modifiableVariable.withArg(property)
|
||||
@@ -398,9 +382,7 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
||||
}
|
||||
}
|
||||
|
||||
val modifiableFunction = impl(function, "FirModifiableFunction") {
|
||||
kind = Interface
|
||||
}
|
||||
val modifiableFunction = impl(function, "FirModifiableFunction")
|
||||
|
||||
impl(anonymousFunction) {
|
||||
parents += modifiableFunction.withArg(anonymousFunction)
|
||||
@@ -534,7 +516,6 @@ object ImplementationConfigurator : AbstractFirTreeImplementationConfigurator()
|
||||
}
|
||||
|
||||
val abstractLoopJump = impl(loopJump, "FirAbstractLoopJump") {
|
||||
kind = Interface
|
||||
lateinit("target")
|
||||
}
|
||||
|
||||
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 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.tree.generator
|
||||
|
||||
import org.jetbrains.kotlin.fir.tree.generator.context.AbstractFirTreeBuilder
|
||||
import org.jetbrains.kotlin.fir.tree.generator.model.Element
|
||||
import org.jetbrains.kotlin.fir.tree.generator.model.Implementation
|
||||
import org.jetbrains.kotlin.fir.tree.generator.model.ImplementationWithArg
|
||||
import org.jetbrains.kotlin.fir.tree.generator.model.KindOwner
|
||||
|
||||
fun configureInterfacesAndAbstractClasses(builder: AbstractFirTreeBuilder) {
|
||||
val elements = collectElements(builder)
|
||||
val elementMapping = ElementMapping(elements)
|
||||
|
||||
val solution = solve2sat(elements, elementMapping)
|
||||
processRequirementsFromConfig(solution, elementMapping)
|
||||
updateKinds(solution, elementMapping)
|
||||
}
|
||||
|
||||
private class ElementMapping(elements: Collection<KindOwner>) {
|
||||
private val varToElements: Map<Int, KindOwner> = elements.mapIndexed { index, element -> 2 * index to element.origin }.toMap() +
|
||||
elements.mapIndexed { index, element -> 2 * index + 1 to element }.toMap()
|
||||
private val elementsToVar: Map<KindOwner, Int> = elements.mapIndexed { index, element -> element.origin to index }.toMap()
|
||||
private val hasInheritors = elements.map { it to false }.toMap(mutableMapOf()).also {
|
||||
for (element in elements) {
|
||||
for (parent in element.allParents) {
|
||||
it[parent.origin] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
operator fun get(element: KindOwner): Int = elementsToVar.getValue(element)
|
||||
operator fun get(index: Int): KindOwner = varToElements.getValue(index)
|
||||
|
||||
fun hasInheritors(element: KindOwner): Boolean {
|
||||
return hasInheritors[element]!!
|
||||
}
|
||||
|
||||
val size: Int = elements.size
|
||||
}
|
||||
|
||||
private fun collectElements(builder: AbstractFirTreeBuilder): List<KindOwner> {
|
||||
return (builder.elements + builder.elements.flatMap { it.allImplementations }).map { it.origin }
|
||||
}
|
||||
|
||||
private fun updateKinds(solution: List<Boolean>, elementMapping: ElementMapping) {
|
||||
for (index in solution.indices) {
|
||||
val isClass = solution[index]
|
||||
val element = elementMapping[index * 2].origin
|
||||
val existingKind = element.kind
|
||||
if (isClass) {
|
||||
when (existingKind) {
|
||||
Implementation.Kind.Interface -> throw IllegalStateException(element.toString())
|
||||
null -> element.kind = when (element) {
|
||||
is Implementation -> {
|
||||
if (elementMapping.hasInheritors(element))
|
||||
Implementation.Kind.AbstractClass
|
||||
else
|
||||
Implementation.Kind.FinalClass
|
||||
}
|
||||
is Element -> Implementation.Kind.AbstractClass
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
element.kind = Implementation.Kind.Interface
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun processRequirementsFromConfig(solution: MutableList<Boolean>, elementMapping: ElementMapping) {
|
||||
fun processParents(element: KindOwner) {
|
||||
val origin = element.origin
|
||||
solution[elementMapping[origin]] = false
|
||||
origin.allParents.forEach { processParents(it) }
|
||||
}
|
||||
|
||||
for (index in solution.indices) {
|
||||
val element = elementMapping[index * 2]
|
||||
if (element.kind != Implementation.Kind.Interface) continue
|
||||
if (!solution[index]) continue
|
||||
processParents(element)
|
||||
}
|
||||
}
|
||||
|
||||
private fun solve2sat(elements: Collection<KindOwner>, elementsToVar: ElementMapping): MutableList<Boolean> {
|
||||
val (g, gt) = buildGraphs(elements, elementsToVar)
|
||||
|
||||
val used = g.indices.mapTo(mutableListOf()) { false }
|
||||
val order = mutableListOf<Int>()
|
||||
val comp = g.indices.mapTo(mutableListOf()) { -1 }
|
||||
val n = g.size
|
||||
|
||||
fun dfs1(v: Int) {
|
||||
used[v] = true
|
||||
for (to in g[v]) {
|
||||
if (!used[to]) {
|
||||
dfs1(to)
|
||||
}
|
||||
}
|
||||
order += v
|
||||
}
|
||||
|
||||
fun dfs2(v: Int, cl: Int) {
|
||||
comp[v] = cl
|
||||
for (to in gt[v]) {
|
||||
if (comp[to] == -1) {
|
||||
dfs2(to, cl)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i in g.indices) {
|
||||
if (!used[i]) {
|
||||
dfs1(i)
|
||||
}
|
||||
}
|
||||
|
||||
var j = 0
|
||||
for (i in g.indices) {
|
||||
val v = order[n - i - 1]
|
||||
if (comp[v] == -1) {
|
||||
dfs2(v, j++)
|
||||
}
|
||||
}
|
||||
|
||||
val res = (1..elements.size).mapTo(mutableListOf()) { false }
|
||||
|
||||
for (i in 0 until n step 2) {
|
||||
if (comp[i] == comp[i + 1]) {
|
||||
throw IllegalStateException("Somehow there is no solution. Please contact with @dmitriy.novozhilov")
|
||||
}
|
||||
res[i / 2] = comp[i] > comp[i + 1]
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
private fun buildGraphs(elements: Collection<KindOwner>, elementMapping: ElementMapping): Pair<List<List<Int>>, List<List<Int>>> {
|
||||
val g = (1..elementMapping.size * 2).map { mutableListOf<Int>() }
|
||||
val gt = (1..elementMapping.size * 2).map { mutableListOf<Int>() }
|
||||
|
||||
fun Int.direct(): Int = this
|
||||
fun Int.invert(): Int = this + 1
|
||||
|
||||
fun extractIndex(element: KindOwner) = elementMapping[element] * 2
|
||||
|
||||
for (element in elements) {
|
||||
val elementVar = extractIndex(element)
|
||||
for (parent in element.allParents) {
|
||||
val parentVar = extractIndex(parent.origin)
|
||||
// parent -> element
|
||||
g[parentVar.direct()] += elementVar.direct()
|
||||
g[elementVar.invert()] += parentVar.invert()
|
||||
}
|
||||
for (i in 0 until element.allParents.size) {
|
||||
for (j in i + 1 until element.allParents.size) {
|
||||
val firstParentVar = extractIndex(element.allParents[i].origin)
|
||||
val secondParentVar = extractIndex(element.allParents[j].origin)
|
||||
// firstParent -> !secondParent
|
||||
g[firstParentVar.direct()] += secondParentVar.invert()
|
||||
g[secondParentVar.direct()] += firstParentVar.invert()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (from in g.indices) {
|
||||
for (to in g[from]) {
|
||||
gt[to] += from
|
||||
}
|
||||
}
|
||||
return g to gt
|
||||
}
|
||||
|
||||
private val KindOwner.origin: KindOwner get() = if (this is ImplementationWithArg) implementation else this
|
||||
@@ -20,9 +20,11 @@ fun main(args: Array<String>) {
|
||||
NodeConfigurator.configureFields()
|
||||
detectBaseTransformerTypes(FirTreeBuilder)
|
||||
ImplementationConfigurator.configureImplementations()
|
||||
configureInterfacesAndAbstractClasses(FirTreeBuilder)
|
||||
removePreviousGeneratedFiles(generationPath)
|
||||
printElements(FirTreeBuilder, generationPath)
|
||||
// printTable(FirTreeBuilder)
|
||||
// printInterfaceClassGraph(FirTreeBuilder)
|
||||
}
|
||||
|
||||
fun Element.traverseParents(block: (Element) -> Unit) {
|
||||
@@ -30,6 +32,30 @@ fun Element.traverseParents(block: (Element) -> Unit) {
|
||||
parents.forEach { it.traverseParents(block) }
|
||||
}
|
||||
|
||||
private fun printInterfaceClassGraph(builder: AbstractFirTreeBuilder) {
|
||||
fun Implementation.Kind.toColor(): String = when (this) {
|
||||
Implementation.Kind.Interface -> "green"
|
||||
else -> "red"
|
||||
}
|
||||
val elements = builder.elements + builder.elements.flatMap { it.allParents }
|
||||
|
||||
File("FirTree.dot").printWriter().use { printer ->
|
||||
with(printer) {
|
||||
println("digraph FirTree {")
|
||||
elements.forEach {
|
||||
println(" ${it.type} [color=${it.kind!!.toColor()}]")
|
||||
}
|
||||
println()
|
||||
elements.forEach { element ->
|
||||
element.allParents.forEach { parent ->
|
||||
println(" ${parent.type} -> ${element.type}")
|
||||
}
|
||||
}
|
||||
println("}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun detectBaseTransformerTypes(builder: AbstractFirTreeBuilder) {
|
||||
val usedAsFieldType = mutableMapOf<AbstractElement, Boolean>().withDefault { false }
|
||||
for (element in builder.elements) {
|
||||
|
||||
+4
@@ -294,6 +294,10 @@ object NodeConfigurator : AbstractFieldConfigurator() {
|
||||
)
|
||||
}
|
||||
|
||||
resolvedDeclarationStatus.configure {
|
||||
shouldBeAnInterface()
|
||||
}
|
||||
|
||||
constructor.configure {
|
||||
parentArg(memberFunction, "F", constructor)
|
||||
+symbol("FirConstructorSymbol")
|
||||
|
||||
+87
-38
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.tree.generator.model.*
|
||||
import java.io.File
|
||||
import java.io.PrintWriter
|
||||
import java.util.*
|
||||
import kotlin.math.abs
|
||||
|
||||
val COPYRIGHT = """
|
||||
/*
|
||||
@@ -167,10 +168,15 @@ fun Implementation.generateCode(generationPath: String) {
|
||||
}
|
||||
}
|
||||
|
||||
val KindOwner.needPureAbstractElement: Boolean get() = (kind != Implementation.Kind.Interface) && !allParents.any { it.kind == Implementation.Kind.AbstractClass }
|
||||
|
||||
fun Implementation.collectImports(): List<String> {
|
||||
return element.collectImportsInternal(
|
||||
listOf(element.fullQualifiedName) + usedTypes.mapNotNull { it.fullQualifiedName } + parents.mapNotNull { it.fullQualifiedName }
|
||||
+ listOfNotNull(pureAbstractElementType.fullQualifiedName?.takeIf { kind != Implementation.Kind.Interface }),
|
||||
listOf(
|
||||
element.fullQualifiedName)
|
||||
+ usedTypes.mapNotNull { it.fullQualifiedName } + parents.mapNotNull { it.fullQualifiedName }
|
||||
+ listOfNotNull(pureAbstractElementType.fullQualifiedName?.takeIf { needPureAbstractElement }
|
||||
),
|
||||
isImpl = true
|
||||
)
|
||||
}
|
||||
@@ -182,6 +188,9 @@ fun Element.collectImports(): List<String> {
|
||||
if (isBaseFirElement) {
|
||||
baseTypes += compositeTransformResultType.fullQualifiedName!!
|
||||
}
|
||||
if (needPureAbstractElement) {
|
||||
baseTypes += pureAbstractElementType.fullQualifiedName!!
|
||||
}
|
||||
return collectImportsInternal(
|
||||
baseTypes,
|
||||
isImpl = false
|
||||
@@ -257,34 +266,43 @@ fun PrintWriter.printImplementation(implementation: Implementation) {
|
||||
}
|
||||
|
||||
with(implementation) {
|
||||
print("${kind.title} $type")
|
||||
print("${kind!!.title} $type")
|
||||
print(element.typeParameters)
|
||||
val fieldsWithoutDefault = allFields.filter { it.defaultValue == null && !it.isLateinit }
|
||||
val fieldsWithDefault = allFields.filter { it.defaultValue != null || it.isLateinit }
|
||||
|
||||
val isInterface = kind == Implementation.Kind.Interface
|
||||
val isAbstract = kind == Implementation.Kind.AbstractClass
|
||||
|
||||
if (!isInterface && fieldsWithoutDefault.isNotEmpty()) {
|
||||
fun abstract() {
|
||||
if (isAbstract) {
|
||||
print("abstract ")
|
||||
}
|
||||
}
|
||||
|
||||
if (!isInterface && !isAbstract && fieldsWithoutDefault.isNotEmpty()) {
|
||||
println("(")
|
||||
fieldsWithoutDefault.forEachIndexed { i, field ->
|
||||
val end = if (i == fieldsWithoutDefault.size - 1) "" else ","
|
||||
printField(field, isImplementation = true, override = true, end = end)
|
||||
printField(field, isImplementation = true, override = true, end = end, withIndent = true)
|
||||
}
|
||||
print(")")
|
||||
}
|
||||
|
||||
print(" : ")
|
||||
if (!isInterface) {
|
||||
if (!isInterface && !allParents.any { it.kind == Implementation.Kind.AbstractClass }) {
|
||||
print("${pureAbstractElementType.type}(), ")
|
||||
}
|
||||
print(element.typeWithArguments)
|
||||
parents.forEach {
|
||||
print(", ${it.typeWithArguments}")
|
||||
}
|
||||
// print(element.typeWithArguments)
|
||||
print(allParents.joinToString { "${it.typeWithArguments}${it.kind.braces()}" })
|
||||
println(" {")
|
||||
|
||||
if (isInterface) {
|
||||
allFields.forEach { printField(it, isImplementation = true, override = true, end = "") }
|
||||
if (isInterface || isAbstract) {
|
||||
allFields.forEach {
|
||||
indent()
|
||||
abstract()
|
||||
printField(it, isImplementation = true, override = true, end = "", withIndent = false)
|
||||
}
|
||||
} else {
|
||||
fieldsWithDefault.forEach {
|
||||
printFieldWithDefaultInImplementation(it)
|
||||
@@ -295,7 +313,7 @@ fun PrintWriter.printImplementation(implementation: Implementation) {
|
||||
}
|
||||
|
||||
element.allFields.filter { it.type.contains("Symbol") && it !is FieldList }
|
||||
.takeIf { it.isNotEmpty() && !isInterface && !element.type.contains("Reference")}
|
||||
.takeIf { it.isNotEmpty() && !isInterface && !isAbstract && !element.type.contains("Reference")}
|
||||
?.let { symbolFields ->
|
||||
indent(1)
|
||||
println("init {")
|
||||
@@ -309,7 +327,7 @@ fun PrintWriter.printImplementation(implementation: Implementation) {
|
||||
}
|
||||
|
||||
fun Field.acceptString(): String = "${name}${call()}accept(visitor, data)"
|
||||
if (!isInterface) {
|
||||
if (!isInterface && !isAbstract) {
|
||||
|
||||
indent(1)
|
||||
print("override fun <R, D> acceptChildren(visitor: FirVisitor<R, D>, data: D) {")
|
||||
@@ -382,8 +400,9 @@ fun PrintWriter.printImplementation(implementation: Implementation) {
|
||||
}
|
||||
|
||||
indent()
|
||||
abstract()
|
||||
print("override fun <D> transformChildren(transformer: FirTransformer<D>, data: D): $typeWithArguments")
|
||||
if (!isInterface) {
|
||||
if (!isInterface && !isAbstract) {
|
||||
println(" {")
|
||||
for (field in allFields) {
|
||||
when {
|
||||
@@ -456,8 +475,9 @@ fun PrintWriter.printImplementation(implementation: Implementation) {
|
||||
if (!field.needsSeparateTransform) continue
|
||||
println()
|
||||
indent()
|
||||
abstract()
|
||||
print("override ${field.transformFunctionDeclaration(typeWithArguments)}")
|
||||
if (isInterface) {
|
||||
if (isInterface || isAbstract) {
|
||||
println()
|
||||
continue
|
||||
}
|
||||
@@ -486,8 +506,9 @@ fun PrintWriter.printImplementation(implementation: Implementation) {
|
||||
if (element.needTransformOtherChildren) {
|
||||
println()
|
||||
indent()
|
||||
abstract()
|
||||
print("override fun <D> transformOtherChildren(transformer: FirTransformer<D>, data: D): $typeWithArguments")
|
||||
if (isInterface) {
|
||||
if (isInterface || isAbstract) {
|
||||
println()
|
||||
} else {
|
||||
println(" {")
|
||||
@@ -508,8 +529,9 @@ fun PrintWriter.printImplementation(implementation: Implementation) {
|
||||
for (field in allFields.filter { it.withReplace }) {
|
||||
println()
|
||||
indent()
|
||||
abstract()
|
||||
print("override ${field.replaceFunctionDeclaration()}")
|
||||
if (isInterface) {
|
||||
if (isInterface || isAbstract) {
|
||||
println()
|
||||
continue
|
||||
}
|
||||
@@ -606,8 +628,10 @@ fun printTransformer(elements: List<Element>, generationPath: String) {
|
||||
}
|
||||
}
|
||||
|
||||
fun PrintWriter.printField(field: Field, isImplementation: Boolean, override: Boolean, end: String) {
|
||||
indent()
|
||||
fun PrintWriter.printField(field: Field, isImplementation: Boolean, override: Boolean, end: String, withIndent: Boolean) {
|
||||
if (withIndent) {
|
||||
indent()
|
||||
}
|
||||
if (override) {
|
||||
print("override ")
|
||||
}
|
||||
@@ -621,10 +645,10 @@ fun PrintWriter.printField(field: Field, isImplementation: Boolean, override: Bo
|
||||
}
|
||||
|
||||
val Field.mutableType: String get() = when (this) {
|
||||
is FieldList -> if (isMutable) "Mutable$typeWithArguments" else typeWithArguments
|
||||
is FieldWithDefault -> if (isMutable) origin.mutableType else typeWithArguments
|
||||
else -> typeWithArguments
|
||||
}
|
||||
is FieldList -> if (isMutable) "Mutable$typeWithArguments" else typeWithArguments
|
||||
is FieldWithDefault -> if (isMutable) origin.mutableType else typeWithArguments
|
||||
else -> typeWithArguments
|
||||
}
|
||||
|
||||
fun Field.call(): String = if (nullable) "?." else "."
|
||||
|
||||
@@ -637,44 +661,68 @@ fun Element.multipleUpperBoundsList(): String {
|
||||
} ?: " "
|
||||
}
|
||||
|
||||
fun PrintWriter.printElement(element: Element) {
|
||||
fun Element.override() {
|
||||
indent()
|
||||
if (this != AbstractFirTreeBuilder.baseFirElement) {
|
||||
print("override ")
|
||||
}
|
||||
}
|
||||
fun Implementation.Kind?.braces(): String = when (this) {
|
||||
Implementation.Kind.Interface -> ""
|
||||
Implementation.Kind.OpenClass, Implementation.Kind.AbstractClass -> "()"
|
||||
else -> throw IllegalStateException(this.toString())
|
||||
}
|
||||
|
||||
fun PrintWriter.printElement(element: Element) {
|
||||
with(element) {
|
||||
print("interface $type")
|
||||
val isInterface = kind == Implementation.Kind.Interface
|
||||
|
||||
fun abstract() {
|
||||
indent()
|
||||
if (!isInterface) {
|
||||
print("abstract ")
|
||||
}
|
||||
}
|
||||
|
||||
fun override() {
|
||||
if (this != AbstractFirTreeBuilder.baseFirElement) {
|
||||
print("override ")
|
||||
}
|
||||
}
|
||||
|
||||
print("${kind!!.title} $type")
|
||||
if (typeArguments.isNotEmpty()) {
|
||||
print(typeArguments.joinToString(", ", "<", ">") { it.toString() })
|
||||
}
|
||||
if (parents.isNotEmpty()) {
|
||||
val needPureAbstractElement = !isInterface && !allParents.any { it.kind == Implementation.Kind.AbstractClass }
|
||||
|
||||
if (parents.isNotEmpty() || needPureAbstractElement) {
|
||||
print(" : ")
|
||||
if (needPureAbstractElement) {
|
||||
print("${pureAbstractElementType.type}()")
|
||||
if (parents.isNotEmpty()) {
|
||||
print(", ")
|
||||
}
|
||||
}
|
||||
print(parents.joinToString(", ") {
|
||||
var result = it.type
|
||||
parentsArguments[it]?.let { arguments ->
|
||||
result += arguments.values.joinToString(", ", "<", ">") { it.typeWithArguments }
|
||||
}
|
||||
result
|
||||
result + it.kind.braces()
|
||||
})
|
||||
}
|
||||
print(multipleUpperBoundsList())
|
||||
println("{")
|
||||
allFields.forEach {
|
||||
printField(it, isImplementation = false, override = it.fromParent, end = "")
|
||||
abstract()
|
||||
printField(it, isImplementation = false, override = it.fromParent, end = "", withIndent = false)
|
||||
}
|
||||
if (allFields.isNotEmpty()) {
|
||||
println()
|
||||
}
|
||||
|
||||
indent()
|
||||
override()
|
||||
println("fun <R, D> accept(visitor: FirVisitor<R, D>, data: D): R = visitor.visit$name(this, data)")
|
||||
|
||||
fields.filter { it.withReplace }.forEach {
|
||||
println()
|
||||
indent()
|
||||
abstract()
|
||||
if (it.fromParent) print("override ")
|
||||
println(it.replaceFunctionDeclaration())
|
||||
}
|
||||
@@ -682,7 +730,7 @@ fun PrintWriter.printElement(element: Element) {
|
||||
for (field in allFields) {
|
||||
if (!field.needsSeparateTransform) continue
|
||||
println()
|
||||
indent()
|
||||
abstract()
|
||||
if (field.fromParent) {
|
||||
print("override ")
|
||||
}
|
||||
@@ -690,7 +738,7 @@ fun PrintWriter.printElement(element: Element) {
|
||||
}
|
||||
if (needTransformOtherChildren) {
|
||||
println()
|
||||
indent()
|
||||
abstract()
|
||||
if (element.parents.any { it.needTransformOtherChildren }) {
|
||||
print("override ")
|
||||
}
|
||||
@@ -698,6 +746,7 @@ fun PrintWriter.printElement(element: Element) {
|
||||
}
|
||||
|
||||
if (element == AbstractFirTreeBuilder.baseFirElement) {
|
||||
require(isInterface)
|
||||
println()
|
||||
indent()
|
||||
println("fun accept(visitor: FirVisitorVoid) = accept(visitor, null)")
|
||||
|
||||
+4
@@ -72,6 +72,10 @@ abstract class AbstractFieldConfigurator {
|
||||
fun needTransformOtherChildren() {
|
||||
element._needTransformOtherChildren = true
|
||||
}
|
||||
|
||||
fun shouldBeAnInterface() {
|
||||
element.kind = Implementation.Kind.Interface
|
||||
}
|
||||
}
|
||||
|
||||
inline fun Element.configure(block: ConfigureContext.() -> Unit) {
|
||||
|
||||
+1
-1
@@ -180,7 +180,7 @@ abstract class AbstractFirTreeImplementationConfigurator {
|
||||
}
|
||||
}
|
||||
|
||||
var kind: Implementation.Kind
|
||||
var kind: Implementation.Kind?
|
||||
get() = implementation.kind
|
||||
set(value) {
|
||||
implementation.kind = value
|
||||
|
||||
+15
-1
@@ -8,12 +8,17 @@ package org.jetbrains.kotlin.fir.tree.generator.model
|
||||
import org.jetbrains.kotlin.fir.tree.generator.BASE_PACKAGE
|
||||
import org.jetbrains.kotlin.fir.tree.generator.typeWithArguments
|
||||
|
||||
interface KindOwner : Importable {
|
||||
var kind: Implementation.Kind?
|
||||
val allParents: List<KindOwner>
|
||||
}
|
||||
|
||||
interface FieldContainer {
|
||||
val allFields: List<Field>
|
||||
operator fun get(fieldName: String): Field?
|
||||
}
|
||||
|
||||
interface AbstractElement : FieldContainer, Importable {
|
||||
interface AbstractElement : FieldContainer, KindOwner {
|
||||
val fields: Set<Field>
|
||||
val parents: List<AbstractElement>
|
||||
val typeArguments: List<TypeArgument>
|
||||
@@ -26,6 +31,8 @@ interface AbstractElement : FieldContainer, Importable {
|
||||
val allFirFields: List<Field>
|
||||
val defaultImplementation: Implementation?
|
||||
val customImplementations: List<Implementation>
|
||||
|
||||
override val allParents: List<KindOwner> get() = parents
|
||||
}
|
||||
|
||||
class Element(val name: String, kind: Kind) : AbstractElement {
|
||||
@@ -38,6 +45,13 @@ class Element(val name: String, kind: Kind) : AbstractElement {
|
||||
override val customImplementations = mutableListOf<Implementation>()
|
||||
override val typeArguments = mutableListOf<TypeArgument>()
|
||||
override val parentsArguments = mutableMapOf<AbstractElement, MutableMap<Importable, Importable>>()
|
||||
override var kind: Implementation.Kind? = null
|
||||
set(value) {
|
||||
if (value != Implementation.Kind.Interface && value != Implementation.Kind.AbstractClass) {
|
||||
throw IllegalArgumentException(value.toString())
|
||||
}
|
||||
field = value
|
||||
}
|
||||
var _needTransformOtherChildren: Boolean = false
|
||||
|
||||
override var baseTransformerType: Element? = null
|
||||
|
||||
+4
-3
@@ -8,20 +8,21 @@ package org.jetbrains.kotlin.fir.tree.generator.model
|
||||
class ImplementationWithArg(
|
||||
val implementation: Implementation,
|
||||
val argument: Importable?
|
||||
) : Importable by implementation, FieldContainer by implementation {
|
||||
) : FieldContainer by implementation, KindOwner by implementation {
|
||||
val element: Element get() = implementation.element
|
||||
}
|
||||
|
||||
class Implementation(val element: Element, val name: String?) : Importable, FieldContainer {
|
||||
class Implementation(val element: Element, val name: String?) : FieldContainer, KindOwner {
|
||||
private val _parents = mutableListOf<ImplementationWithArg>()
|
||||
val parents: List<ImplementationWithArg> get() = _parents
|
||||
|
||||
override val allParents: List<KindOwner> get() = listOf(element) + parents
|
||||
val isDefault = name == null
|
||||
override val type = name ?: element.type + "Impl"
|
||||
override val allFields = element.allFields.toMutableList().mapTo(mutableListOf()) {
|
||||
FieldWithDefault(it)
|
||||
}
|
||||
var kind: Kind = Kind.FinalClass
|
||||
override var kind: Kind? = null
|
||||
|
||||
override val packageName = element.packageName + ".impl"
|
||||
val usedTypes = mutableListOf<Importable>()
|
||||
|
||||
Reference in New Issue
Block a user