[FIR] Remove old visitor generator and configure gradle task for tree generator
This commit is contained in:
@@ -27,25 +27,17 @@ sourceSets {
|
|||||||
val generatorClasspath by configurations.creating
|
val generatorClasspath by configurations.creating
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
generatorClasspath(project("visitors-generator"))
|
generatorClasspath(project("tree-generator"))
|
||||||
}
|
}
|
||||||
|
|
||||||
val generateVisitors by tasks.registering(NoDebugJavaExec::class) {
|
val generateTree by tasks.registering(NoDebugJavaExec::class) {
|
||||||
val generationRoot = "$projectDir/src/org/jetbrains/kotlin/fir/"
|
val generationRoot = "$projectDir/src/"
|
||||||
val output = "$projectDir/visitors"
|
|
||||||
|
|
||||||
val allSourceFiles = fileTree(generationRoot) {
|
|
||||||
include("**/*.kt")
|
|
||||||
}
|
|
||||||
|
|
||||||
inputs.files(allSourceFiles)
|
|
||||||
outputs.dirs(output)
|
|
||||||
|
|
||||||
|
args(generationRoot)
|
||||||
classpath = generatorClasspath
|
classpath = generatorClasspath
|
||||||
args(generationRoot, output)
|
main = "org.jetbrains.kotlin.fir.tree.generator.MainKt"
|
||||||
main = "org.jetbrains.kotlin.fir.visitors.generator.VisitorsGeneratorKt"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val compileKotlin by tasks
|
val compileKotlin by tasks
|
||||||
|
|
||||||
compileKotlin.dependsOn(generateVisitors)
|
compileKotlin.dependsOn(generateTree)
|
||||||
|
|||||||
@@ -1,127 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2018 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.visitors.generator
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.utils.Printer
|
|
||||||
|
|
||||||
abstract class AbstractVisitorGenerator(val referencesData: DataCollector.ReferencesData) {
|
|
||||||
fun Printer.generateFunction(
|
|
||||||
name: String,
|
|
||||||
parameters: Map<String, DataCollector.NameWithTypeParameters>,
|
|
||||||
returnType: String,
|
|
||||||
override: Boolean = false,
|
|
||||||
final: Boolean = false,
|
|
||||||
typeParametersWithBounds: List<String> = emptyList(),
|
|
||||||
body: (Printer.() -> Unit)?
|
|
||||||
) {
|
|
||||||
|
|
||||||
if (body == null) {
|
|
||||||
print("abstract ")
|
|
||||||
} else {
|
|
||||||
printIndent()
|
|
||||||
if (!final) {
|
|
||||||
printWithNoIndent("open ")
|
|
||||||
}
|
|
||||||
if (override) {
|
|
||||||
if (final) {
|
|
||||||
printWithNoIndent("final ")
|
|
||||||
}
|
|
||||||
printWithNoIndent("override ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printWithNoIndent("fun ")
|
|
||||||
if (typeParametersWithBounds.isNotEmpty()) {
|
|
||||||
printWithNoIndent("<")
|
|
||||||
separatedOneLine(typeParametersWithBounds, ", ")
|
|
||||||
printWithNoIndent("> ")
|
|
||||||
}
|
|
||||||
printWithNoIndent(name, "(")
|
|
||||||
parameters
|
|
||||||
.flatMap { (parameterName, typeNameWithTypeParameters) ->
|
|
||||||
listOf(parameterName, ": ", typeNameWithTypeParameters.asStringWithoutBounds(), ", ")
|
|
||||||
}.dropLast(1)
|
|
||||||
.forEach {
|
|
||||||
printWithNoIndent(it)
|
|
||||||
}
|
|
||||||
printWithNoIndent(")")
|
|
||||||
if (returnType != "Unit") {
|
|
||||||
printWithNoIndent(": ", returnType)
|
|
||||||
}
|
|
||||||
if (body != null) {
|
|
||||||
printlnWithNoIndent(" {")
|
|
||||||
indented {
|
|
||||||
body()
|
|
||||||
}
|
|
||||||
println("}")
|
|
||||||
} else {
|
|
||||||
printlnWithNoIndent()
|
|
||||||
}
|
|
||||||
println()
|
|
||||||
}
|
|
||||||
|
|
||||||
protected inline fun Printer.indented(l: () -> Unit) {
|
|
||||||
pushIndent()
|
|
||||||
l()
|
|
||||||
popIndent()
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun Printer.generateCall(name: String, args: List<String>) {
|
|
||||||
printWithNoIndent(name, "(")
|
|
||||||
separatedOneLine(args, ", ")
|
|
||||||
printWithNoIndent(")")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Printer.separatedOneLine(iterable: Iterable<Any>, separator: Any) {
|
|
||||||
var first = true
|
|
||||||
for (element in iterable) {
|
|
||||||
if (!first) {
|
|
||||||
printWithNoIndent(separator)
|
|
||||||
} else {
|
|
||||||
first = false
|
|
||||||
}
|
|
||||||
printWithNoIndent(element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Printer.generateDefaultImports() {
|
|
||||||
referencesData.usedPackages.forEach {
|
|
||||||
println("import ", it.asString(), ".*")
|
|
||||||
}
|
|
||||||
println()
|
|
||||||
println()
|
|
||||||
}
|
|
||||||
|
|
||||||
val String.safeName
|
|
||||||
get() = when (this) {
|
|
||||||
"class" -> "klass"
|
|
||||||
else -> this
|
|
||||||
}
|
|
||||||
|
|
||||||
fun generate(): String {
|
|
||||||
val builder = StringBuilder()
|
|
||||||
val printer = Printer(builder, " ")
|
|
||||||
printer.apply {
|
|
||||||
println(javaClass.getResource("/notice.txt").readText())
|
|
||||||
|
|
||||||
println("package $VISITOR_PACKAGE")
|
|
||||||
println()
|
|
||||||
generateDefaultImports()
|
|
||||||
println(WARNING_GENERATED_FILE)
|
|
||||||
|
|
||||||
printer.generateContent()
|
|
||||||
}
|
|
||||||
return builder.toString()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun allElementTypes() =
|
|
||||||
referencesData.direct.let { map ->
|
|
||||||
map.keys + map.values.flatten()
|
|
||||||
}.distinct()
|
|
||||||
|
|
||||||
abstract fun Printer.generateContent()
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,160 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2018 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.visitors.generator
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.lexer.KtTokens
|
|
||||||
import org.jetbrains.kotlin.name.FqName
|
|
||||||
import org.jetbrains.kotlin.psi.*
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType
|
|
||||||
|
|
||||||
class DataCollector {
|
|
||||||
|
|
||||||
class NameWithTypeParameters private constructor(
|
|
||||||
val name: String,
|
|
||||||
val typeParameters: List<String>,
|
|
||||||
private val typeParameterBounds: Map<String, String>
|
|
||||||
) : Comparable<NameWithTypeParameters> {
|
|
||||||
|
|
||||||
override fun compareTo(other: NameWithTypeParameters): Int = name.compareTo(other.name)
|
|
||||||
|
|
||||||
private constructor(name: String, typeParameters: Pair<List<String>, Map<String, String>>) :
|
|
||||||
this(name, typeParameters.first, typeParameters.second)
|
|
||||||
|
|
||||||
constructor(name: String, typeParameterString: String) :
|
|
||||||
this(name, typeParameterString.splitToParametersAndBounds())
|
|
||||||
|
|
||||||
constructor(name: String) : this(name, emptyList(), emptyMap())
|
|
||||||
|
|
||||||
fun typeParametersWithBounds(): List<String> =
|
|
||||||
typeParameters.map { parameter ->
|
|
||||||
parameter + (typeParameterBounds[parameter]?.let { " : $it" } ?: "")
|
|
||||||
}
|
|
||||||
|
|
||||||
fun asStringWithoutBounds(): String =
|
|
||||||
name + if (typeParameters.isEmpty()) "" else typeParameters.joinToString(prefix = "<", postfix = ">", separator = ", ")
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean =
|
|
||||||
other is NameWithTypeParameters && name == other.name
|
|
||||||
|
|
||||||
override fun hashCode(): Int = name.hashCode()
|
|
||||||
|
|
||||||
override fun toString(): String =
|
|
||||||
name + if (typeParameters.isEmpty()) "" else typeParameters.joinToString(prefix = "<", postfix = ">", separator = ", ") {
|
|
||||||
val bound = typeParameterBounds[it]
|
|
||||||
if (bound == null) it else "$it : $bound"
|
|
||||||
}
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private fun String.splitToParametersAndBounds(): Pair<List<String>, Map<String, String>> {
|
|
||||||
val typeParametersWithBounds = drop(1).dropLast(1).split(",").map { it.trim() }.filter { it.isNotBlank() }
|
|
||||||
val typeParameters = mutableListOf<String>()
|
|
||||||
val bounds = mutableMapOf<String, String>()
|
|
||||||
for (parameterWithBounds in typeParametersWithBounds) {
|
|
||||||
val parts = parameterWithBounds.split(":").map { it.trim() }
|
|
||||||
typeParameters += parts[0]
|
|
||||||
if (parts.size > 1) {
|
|
||||||
bounds[parts[0]] = parts[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return typeParameters to bounds
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val references = mutableMapOf<NameWithTypeParameters, List<NameWithTypeParameters>>()
|
|
||||||
private val packagePerClass = mutableMapOf<NameWithTypeParameters, FqName>()
|
|
||||||
private val baseTransformedTypes = mutableListOf<NameWithTypeParameters>()
|
|
||||||
|
|
||||||
private fun KtSuperTypeListEntry.toNameWithTypeParameters(): NameWithTypeParameters? {
|
|
||||||
val type = typeAsUserType ?: return null
|
|
||||||
val name = type.referencedName ?: return null
|
|
||||||
val typeArguments = type.typeArgumentList?.text ?: ""
|
|
||||||
return NameWithTypeParameters(name, typeArguments)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun readFile(file: KtFile) {
|
|
||||||
file.acceptChildren(object : KtVisitorVoid() {
|
|
||||||
|
|
||||||
override fun visitKtElement(element: KtElement) {
|
|
||||||
super.visitKtElement(element)
|
|
||||||
element.acceptChildren(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun visitClass(klass: KtClass) {
|
|
||||||
val className = klass.name ?: run {
|
|
||||||
super.visitClass(klass)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
val classNameWithParameters = NameWithTypeParameters(className, klass.typeParameterList?.text ?: "")
|
|
||||||
if (klass.isInterface() || (klass.hasModifier(KtTokens.ABSTRACT_KEYWORD) && "Abstract" !in (klass.name ?: ""))) {
|
|
||||||
packagePerClass[classNameWithParameters] = file.packageFqName
|
|
||||||
val isBaseTT = klass.annotationEntries.any {
|
|
||||||
it.shortName?.asString() == BASE_TRANSFORMED_TYPE_ANNOTATION_NAME
|
|
||||||
}
|
|
||||||
if (isBaseTT) {
|
|
||||||
baseTransformedTypes += classNameWithParameters
|
|
||||||
}
|
|
||||||
|
|
||||||
val manual = klass.superTypeListEntries.find {
|
|
||||||
it.typeReference?.findDescendantOfType<KtAnnotationEntry> { annotationEntry ->
|
|
||||||
annotationEntry.shortName?.asString() == VISITED_SUPERTYPE_ANNOTATION_NAME
|
|
||||||
} != null
|
|
||||||
}
|
|
||||||
if (manual != null) {
|
|
||||||
references[classNameWithParameters] = listOfNotNull(manual.toNameWithTypeParameters())
|
|
||||||
} else {
|
|
||||||
references[classNameWithParameters] =
|
|
||||||
klass.superTypeListEntries.mapNotNull {
|
|
||||||
it.toNameWithTypeParameters()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
super.visitClass(klass)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun <K> Map<K, List<K>>.computeBackReferences(): Map<K, List<K>> {
|
|
||||||
val result = mutableMapOf<K, List<K>>()
|
|
||||||
|
|
||||||
this.forEach { (k, v) ->
|
|
||||||
v.forEach {
|
|
||||||
result.merge(it, listOf(k)) { a, b -> a + b }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun <K : Comparable<K>> Map<K, List<K>>.sortedMap(): Map<K, List<K>> {
|
|
||||||
return this.toSortedMap().mapValues { (_, v) -> v.sorted() }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun computeResult(): ReferencesData {
|
|
||||||
val back = references.computeBackReferences()
|
|
||||||
|
|
||||||
val keysToKeep =
|
|
||||||
generateSequence(listOf(FIR_ELEMENT_CLASS_NAME)) { firName ->
|
|
||||||
firName.flatMap { back[it].orEmpty() }.takeUnless { it.isEmpty() }
|
|
||||||
}.flatten().toSet()
|
|
||||||
|
|
||||||
val cleanBack = back.filterKeys { it in keysToKeep }
|
|
||||||
return ReferencesData(
|
|
||||||
cleanBack.computeBackReferences().sortedMap(),
|
|
||||||
cleanBack.sortedMap(),
|
|
||||||
packagePerClass.filterKeys { it in keysToKeep }.values.distinct().sortedBy { it.asString() },
|
|
||||||
baseTransformedTypes.sorted()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
data class ReferencesData(
|
|
||||||
val direct: Map<NameWithTypeParameters, List<NameWithTypeParameters>>,
|
|
||||||
val back: Map<NameWithTypeParameters, List<NameWithTypeParameters>>,
|
|
||||||
val usedPackages: List<FqName>,
|
|
||||||
val baseTransformedTypes: List<NameWithTypeParameters>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,114 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2018 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.visitors.generator
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.visitors.generator.DataCollector.NameWithTypeParameters
|
|
||||||
import org.jetbrains.kotlin.utils.Printer
|
|
||||||
|
|
||||||
class ParametricTransformerGenerator(data: DataCollector.ReferencesData) : AbstractVisitorGenerator(data) {
|
|
||||||
override fun Printer.generateContent() {
|
|
||||||
println("abstract class $PARAMETRIC_TRANSFORMER_NAME<in D> : $SIMPLE_VISITOR_NAME<$TRANSFORMER_RESULT_NAME<$FIR_ELEMENT_CLASS_NAME>, D>() {")
|
|
||||||
indented {
|
|
||||||
|
|
||||||
generateFunction(
|
|
||||||
"transformElement",
|
|
||||||
mapOf(
|
|
||||||
"element" to NameWithTypeParameters("E"),
|
|
||||||
"data" to NameWithTypeParameters("D")
|
|
||||||
),
|
|
||||||
constructCompositeBoxType("E"),
|
|
||||||
typeParametersWithBounds = listOf("E : $FIR_ELEMENT_CLASS_NAME"),
|
|
||||||
body = null
|
|
||||||
)
|
|
||||||
|
|
||||||
referencesData.walkHierarchyTopDown(FIR_ELEMENT_CLASS_NAME) { parent, className ->
|
|
||||||
generateTransformMethod(className, parent)
|
|
||||||
}
|
|
||||||
|
|
||||||
allElementTypes().forEach {
|
|
||||||
generateTrampolineVisit(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
println("}")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fun constructCompositeBoxType(type: String): String {
|
|
||||||
return "$TRANSFORMER_RESULT_NAME<$type>"
|
|
||||||
}
|
|
||||||
|
|
||||||
val baseTypes = mutableMapOf<NameWithTypeParameters, NameWithTypeParameters>().also {
|
|
||||||
for (baseTransformedType in referencesData.baseTransformedTypes) {
|
|
||||||
it[baseTransformedType] = baseTransformedType
|
|
||||||
}
|
|
||||||
|
|
||||||
data.walkHierarchyTopDown(FIR_ELEMENT_CLASS_NAME) { parent, element ->
|
|
||||||
it[element] = it[parent] ?: return@walkHierarchyTopDown
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Printer.generateTrampolineVisit(className: NameWithTypeParameters) {
|
|
||||||
val shortcutName = className.name.classNameWithoutFir
|
|
||||||
val parameterName = shortcutName.decapitalize().safeName
|
|
||||||
generateFunction(
|
|
||||||
name = "visit$shortcutName",
|
|
||||||
parameters = mapOf(
|
|
||||||
parameterName to className,
|
|
||||||
"data" to NameWithTypeParameters("D")
|
|
||||||
),
|
|
||||||
returnType = constructCompositeBoxType(FIR_ELEMENT_CLASS_NAME.name),
|
|
||||||
override = true,
|
|
||||||
final = true,
|
|
||||||
typeParametersWithBounds = className.typeParametersWithBounds()
|
|
||||||
) {
|
|
||||||
print("return ")
|
|
||||||
generateCall("transform$shortcutName", listOf(parameterName, "data"))
|
|
||||||
println()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Printer.generateTransformMethod(
|
|
||||||
className: NameWithTypeParameters,
|
|
||||||
parent: NameWithTypeParameters
|
|
||||||
) {
|
|
||||||
val baseType = baseTypes[className]
|
|
||||||
|
|
||||||
val shortcutName = className.name.classNameWithoutFir
|
|
||||||
val parameterName = shortcutName.decapitalize().safeName
|
|
||||||
if (baseType == null) {
|
|
||||||
generateFunction(
|
|
||||||
"transform$shortcutName",
|
|
||||||
mapOf(
|
|
||||||
parameterName to NameWithTypeParameters("E"),
|
|
||||||
"data" to NameWithTypeParameters("D")
|
|
||||||
),
|
|
||||||
constructCompositeBoxType("E"),
|
|
||||||
typeParametersWithBounds = listOf("E : $parent") + className.typeParametersWithBounds()
|
|
||||||
) {
|
|
||||||
print("return ")
|
|
||||||
generateCall("transformElement", listOf(parameterName, "data"))
|
|
||||||
printlnWithNoIndent()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
generateFunction(
|
|
||||||
"transform$shortcutName",
|
|
||||||
mapOf(
|
|
||||||
parameterName to className,
|
|
||||||
"data" to NameWithTypeParameters("D")
|
|
||||||
),
|
|
||||||
constructCompositeBoxType(baseType.name),
|
|
||||||
typeParametersWithBounds = className.typeParametersWithBounds()
|
|
||||||
) {
|
|
||||||
print("return ")
|
|
||||||
generateCall("transformElement", listOf(parameterName, "data"))
|
|
||||||
printlnWithNoIndent()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2018 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.visitors.generator
|
|
||||||
|
|
||||||
import com.intellij.core.CoreApplicationEnvironment
|
|
||||||
import com.intellij.core.CoreProjectEnvironment
|
|
||||||
import com.intellij.lang.MetaLanguage
|
|
||||||
import com.intellij.openapi.Disposable
|
|
||||||
import com.intellij.openapi.extensions.Extensions
|
|
||||||
import com.intellij.openapi.project.Project
|
|
||||||
import com.intellij.openapi.util.Disposer
|
|
||||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
|
||||||
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
|
|
||||||
|
|
||||||
internal data class PsiSetup(
|
|
||||||
val applicationEnvironment: CoreApplicationEnvironment,
|
|
||||||
val projectEnvironment: CoreProjectEnvironment,
|
|
||||||
val project: Project,
|
|
||||||
val disposable: Disposable
|
|
||||||
)
|
|
||||||
|
|
||||||
internal fun setup(): PsiSetup {
|
|
||||||
val disposable = Disposer.newDisposable()
|
|
||||||
|
|
||||||
val applicationEnvironment = CoreApplicationEnvironment(disposable, false)
|
|
||||||
|
|
||||||
val projectEnvironment = CoreProjectEnvironment(disposable, applicationEnvironment)
|
|
||||||
|
|
||||||
CoreApplicationEnvironment.registerExtensionPoint(Extensions.getRootArea(), MetaLanguage.EP_NAME, MetaLanguage::class.java)
|
|
||||||
|
|
||||||
|
|
||||||
applicationEnvironment.registerFileType(KotlinFileType.INSTANCE, "kt")
|
|
||||||
applicationEnvironment.registerParserDefinition(KotlinParserDefinition())
|
|
||||||
|
|
||||||
|
|
||||||
val project = projectEnvironment.project
|
|
||||||
return PsiSetup(applicationEnvironment, projectEnvironment, project, disposable)
|
|
||||||
}
|
|
||||||
|
|
||||||
internal inline fun <T> withPsiSetup(l: PsiSetup.() -> T): T {
|
|
||||||
val setup = setup()
|
|
||||||
val t = setup.l()
|
|
||||||
Disposer.dispose(setup.disposable)
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2018 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.visitors.generator
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.visitors.generator.DataCollector.NameWithTypeParameters
|
|
||||||
import org.jetbrains.kotlin.utils.Printer
|
|
||||||
|
|
||||||
class SimpleVisitorGenerator(referencesData: DataCollector.ReferencesData) : AbstractVisitorGenerator(referencesData) {
|
|
||||||
override fun Printer.generateContent() {
|
|
||||||
println("abstract class $SIMPLE_VISITOR_NAME<out R, in D> {")
|
|
||||||
indented {
|
|
||||||
generateFunction(
|
|
||||||
"visitElement",
|
|
||||||
parameters = mapOf(
|
|
||||||
"element" to FIR_ELEMENT_CLASS_NAME,
|
|
||||||
"data" to NameWithTypeParameters("D")
|
|
||||||
),
|
|
||||||
returnType = "R",
|
|
||||||
body = null
|
|
||||||
)
|
|
||||||
|
|
||||||
referencesData.walkHierarchyTopDown(from = FIR_ELEMENT_CLASS_NAME) { parent, element ->
|
|
||||||
generateVisit(element, parent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println("}")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun Printer.generateVisit(
|
|
||||||
className: NameWithTypeParameters,
|
|
||||||
parent: NameWithTypeParameters
|
|
||||||
) {
|
|
||||||
val shortcutName = className.name.classNameWithoutFir
|
|
||||||
val parameterName = shortcutName.decapitalize().safeName
|
|
||||||
generateFunction(
|
|
||||||
name = "visit$shortcutName",
|
|
||||||
parameters = mapOf(
|
|
||||||
parameterName to className,
|
|
||||||
"data" to NameWithTypeParameters("D")
|
|
||||||
),
|
|
||||||
returnType = "R",
|
|
||||||
typeParametersWithBounds = className.typeParametersWithBounds()
|
|
||||||
) {
|
|
||||||
print("return ")
|
|
||||||
generateCall("visitElement", listOf(parameterName, "data"))
|
|
||||||
println()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2018 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.visitors.generator
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.fir.visitors.generator.DataCollector.NameWithTypeParameters
|
|
||||||
import org.jetbrains.kotlin.utils.Printer
|
|
||||||
|
|
||||||
class UnitVisitorGenerator(referencesData: DataCollector.ReferencesData) : AbstractVisitorGenerator(referencesData) {
|
|
||||||
override fun Printer.generateContent() {
|
|
||||||
println("abstract class $UNIT_VISITOR_NAME : $SIMPLE_VISITOR_NAME<Unit, Nothing?>() {")
|
|
||||||
indented {
|
|
||||||
generateFunction(
|
|
||||||
"visitElement",
|
|
||||||
parameters = mapOf(
|
|
||||||
"element" to FIR_ELEMENT_CLASS_NAME
|
|
||||||
),
|
|
||||||
returnType = "Unit",
|
|
||||||
body = null
|
|
||||||
)
|
|
||||||
|
|
||||||
referencesData.walkHierarchyTopDown(from = FIR_ELEMENT_CLASS_NAME) { parent, element ->
|
|
||||||
generateVisit(element, parent)
|
|
||||||
}
|
|
||||||
|
|
||||||
allElementTypes().forEach {
|
|
||||||
generateTrampolineVisit(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
println("}")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun Printer.generateVisit(
|
|
||||||
className: NameWithTypeParameters,
|
|
||||||
parent: NameWithTypeParameters
|
|
||||||
) {
|
|
||||||
val shortcutName = className.name.classNameWithoutFir
|
|
||||||
val parameterName = shortcutName.decapitalize().safeName
|
|
||||||
generateFunction(
|
|
||||||
name = "visit$shortcutName",
|
|
||||||
parameters = mapOf(
|
|
||||||
parameterName to className
|
|
||||||
),
|
|
||||||
returnType = "Unit",
|
|
||||||
typeParametersWithBounds = className.typeParametersWithBounds()
|
|
||||||
) {
|
|
||||||
printIndent()
|
|
||||||
generateCall("visitElement", listOf(parameterName, "null"))
|
|
||||||
println()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Printer.generateTrampolineVisit(className: NameWithTypeParameters) {
|
|
||||||
val shortcutName = className.name.classNameWithoutFir
|
|
||||||
val parameterName = shortcutName.decapitalize().safeName
|
|
||||||
generateFunction(
|
|
||||||
name = "visit$shortcutName",
|
|
||||||
parameters = mapOf(
|
|
||||||
parameterName to className,
|
|
||||||
"data" to NameWithTypeParameters("Nothing?")
|
|
||||||
),
|
|
||||||
returnType = "Unit",
|
|
||||||
override = true,
|
|
||||||
final = true,
|
|
||||||
typeParametersWithBounds = className.typeParametersWithBounds()
|
|
||||||
) {
|
|
||||||
printIndent()
|
|
||||||
generateCall("visit$shortcutName", listOf(parameterName))
|
|
||||||
println()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,85 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2000-2018 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.visitors.generator
|
|
||||||
|
|
||||||
import com.intellij.openapi.util.text.StringUtil
|
|
||||||
import com.intellij.openapi.vfs.StandardFileSystems
|
|
||||||
import com.intellij.openapi.vfs.VirtualFileManager
|
|
||||||
import com.intellij.openapi.vfs.local.CoreLocalFileSystem
|
|
||||||
import com.intellij.psi.PsiManager
|
|
||||||
import com.intellij.psi.SingleRootFileViewProvider
|
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
|
|
||||||
val FIR_ELEMENT_CLASS_NAME = DataCollector.NameWithTypeParameters("FirElement")
|
|
||||||
const val VISITOR_PACKAGE = "org.jetbrains.kotlin.fir.visitors"
|
|
||||||
const val SIMPLE_VISITOR_NAME = "FirVisitor"
|
|
||||||
const val UNIT_VISITOR_NAME = "FirVisitorVoid"
|
|
||||||
const val PARAMETRIC_TRANSFORMER_NAME = "FirTransformer"
|
|
||||||
const val TRANSFORMER_RESULT_NAME = "CompositeTransformResult"
|
|
||||||
|
|
||||||
const val BASE_TRANSFORMED_TYPE_ANNOTATION_NAME = "BaseTransformedType"
|
|
||||||
const val VISITED_SUPERTYPE_ANNOTATION_NAME = "VisitedSupertype"
|
|
||||||
|
|
||||||
const val WARNING_GENERATED_FILE =
|
|
||||||
"""/** This file generated by :compiler:fir:tree:generateVisitors. DO NOT MODIFY MANUALLY! */"""
|
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
|
||||||
|
|
||||||
// val rootPath = File(args[0])
|
|
||||||
// val output = File(args[1])
|
|
||||||
//
|
|
||||||
// val packageDirectory = output.resolve(VISITOR_PACKAGE.replace('.', '/'))
|
|
||||||
// packageDirectory.mkdirs()
|
|
||||||
//
|
|
||||||
// withPsiSetup {
|
|
||||||
// val psiManager = PsiManager.getInstance(project)
|
|
||||||
// val vfm = VirtualFileManager.getInstance()
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// val dataCollector = DataCollector()
|
|
||||||
//
|
|
||||||
// rootPath.walkTopDown()
|
|
||||||
// .filter {
|
|
||||||
// it.extension == "kt"
|
|
||||||
// }.map {
|
|
||||||
// (vfm.getFileSystem(StandardFileSystems.FILE_PROTOCOL) as CoreLocalFileSystem).findFileByIoFile(it)
|
|
||||||
// }.flatMap {
|
|
||||||
// SingleRootFileViewProvider(psiManager, it!!).allFiles.asSequence()
|
|
||||||
// }
|
|
||||||
// .filterIsInstance<KtFile>()
|
|
||||||
// .forEach(dataCollector::readFile)
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// val data = dataCollector.computeResult()
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// SimpleVisitorGenerator(data).runGenerator(packageDirectory.resolve("${SIMPLE_VISITOR_NAME}Generated.kt"))
|
|
||||||
// UnitVisitorGenerator(data).runGenerator(packageDirectory.resolve("${UNIT_VISITOR_NAME}Generated.kt"))
|
|
||||||
// ParametricTransformerGenerator(data).runGenerator(packageDirectory.resolve("${PARAMETRIC_TRANSFORMER_NAME}Generated.kt"))
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
fun AbstractVisitorGenerator.runGenerator(file: File) {
|
|
||||||
file.writeText(StringUtil.convertLineSeparators(this.generate(), System.lineSeparator()))
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
val String.classNameWithoutFir get() = this.removePrefix("Fir")
|
|
||||||
|
|
||||||
|
|
||||||
fun DataCollector.ReferencesData.walkHierarchyTopDown(
|
|
||||||
from: DataCollector.NameWithTypeParameters,
|
|
||||||
l: (p: DataCollector.NameWithTypeParameters, e: DataCollector.NameWithTypeParameters) -> Unit
|
|
||||||
) {
|
|
||||||
val referents = back[from] ?: return
|
|
||||||
for (referent in referents) {
|
|
||||||
l(from, referent)
|
|
||||||
walkHierarchyTopDown(referent, l)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
+1
-1
@@ -43,7 +43,7 @@ include ":kotlin-build-common",
|
|||||||
":compiler:visualizer:render-psi",
|
":compiler:visualizer:render-psi",
|
||||||
":compiler:fir:cones",
|
":compiler:fir:cones",
|
||||||
":compiler:fir:tree",
|
":compiler:fir:tree",
|
||||||
":compiler:fir:tree:visitors-generator",
|
":compiler:fir:tree:tree-generator",
|
||||||
":compiler:fir:psi2fir",
|
":compiler:fir:psi2fir",
|
||||||
":compiler:fir:lightTree",
|
":compiler:fir:lightTree",
|
||||||
":compiler:fir:fir2ir",
|
":compiler:fir:fir2ir",
|
||||||
|
|||||||
Reference in New Issue
Block a user