Fix various inconsistencies in visitor generator output
This commit is contained in:
committed by
Mikhail Glukhikh
parent
2c626d6c5d
commit
f33c16a7db
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2000-2018 JetBrains s.r.o. 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, String>,
|
||||||
|
returnType: String,
|
||||||
|
override: Boolean = false,
|
||||||
|
final: Boolean = false,
|
||||||
|
body: (Printer.() -> Unit)?
|
||||||
|
) {
|
||||||
|
|
||||||
|
if (body == null) {
|
||||||
|
print("abstract ")
|
||||||
|
} else {
|
||||||
|
printIndent()
|
||||||
|
if (!final) {
|
||||||
|
printWithNoIndent("open ")
|
||||||
|
}
|
||||||
|
if (override) {
|
||||||
|
if (final) {
|
||||||
|
printWithNoIndent("final ")
|
||||||
|
}
|
||||||
|
printWithNoIndent("override ")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printWithNoIndent("fun ", name, "(")
|
||||||
|
parameters
|
||||||
|
.flatMap { (a, b) ->
|
||||||
|
listOf(a, ": ", b, ", ")
|
||||||
|
}.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(")")
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun Printer.separatedOneLine(iterable: Iterable<Any>, separator: Any) {
|
||||||
|
var first = true
|
||||||
|
for (element in iterable) {
|
||||||
|
if (!first) {
|
||||||
|
printWithNoIndent(separator)
|
||||||
|
} else {
|
||||||
|
first = false
|
||||||
|
}
|
||||||
|
printWithNoIndent(element)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected 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()
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract fun Printer.generateContent()
|
||||||
|
|
||||||
|
}
|
||||||
@@ -59,6 +59,9 @@ class DataCollector {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Map<String, List<String>>.sorted(): Map<String, List<String>> {
|
||||||
|
return this.toSortedMap().mapValues { (_, v) -> v.sorted() }
|
||||||
|
}
|
||||||
|
|
||||||
fun computeResult(): ReferencesData {
|
fun computeResult(): ReferencesData {
|
||||||
val back = references.computeBackReferences()
|
val back = references.computeBackReferences()
|
||||||
@@ -70,9 +73,9 @@ class DataCollector {
|
|||||||
|
|
||||||
val cleanBack = back.filterKeys { it in keysToKeep }
|
val cleanBack = back.filterKeys { it in keysToKeep }
|
||||||
return ReferencesData(
|
return ReferencesData(
|
||||||
cleanBack.computeBackReferences(),
|
cleanBack.computeBackReferences().sorted(),
|
||||||
cleanBack,
|
cleanBack.sorted(),
|
||||||
packagePerClass.filterKeys { it in keysToKeep }.values.distinct()
|
packagePerClass.filterKeys { it in keysToKeep }.values.distinct().sortedBy { it.asString() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2000-2018 JetBrains s.r.o. 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
|
||||||
|
|
||||||
|
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 "D"
|
||||||
|
),
|
||||||
|
returnType = "R",
|
||||||
|
body = null
|
||||||
|
)
|
||||||
|
referencesData.walkHierarchyTopDown(from = FIR_ELEMENT_CLASS_NAME) { parent, element ->
|
||||||
|
generateVisit(element, parent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println("}")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Printer.generateVisit(className: String, parent: String) {
|
||||||
|
val shortcutName = className.classNameWithoutFir
|
||||||
|
val parameterName = shortcutName.decapitalize().safeName
|
||||||
|
generateFunction(
|
||||||
|
name = "visit$shortcutName",
|
||||||
|
parameters = mapOf(
|
||||||
|
parameterName to className,
|
||||||
|
"data" to "D"
|
||||||
|
),
|
||||||
|
returnType = "R"
|
||||||
|
) {
|
||||||
|
print("return ")
|
||||||
|
generateCall("visit${parent.classNameWithoutFir}", listOf(parameterName, "data"))
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2000-2018 JetBrains s.r.o. 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
|
||||||
|
|
||||||
|
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(FIR_ELEMENT_CLASS_NAME) { parent, klass ->
|
||||||
|
generateVisit(klass, parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
val trampolines = referencesData.back.let {
|
||||||
|
it.keys + it.values.flatten()
|
||||||
|
}.distinct()
|
||||||
|
trampolines.forEach {
|
||||||
|
generateTrampolineVisit(it)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
println("}")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun Printer.generateVisit(className: String, parent: String) {
|
||||||
|
val shortcutName = className.classNameWithoutFir
|
||||||
|
val parameterName = shortcutName.decapitalize().safeName
|
||||||
|
generateFunction(
|
||||||
|
name = "visit$shortcutName",
|
||||||
|
parameters = mapOf(
|
||||||
|
parameterName to className
|
||||||
|
),
|
||||||
|
returnType = "Unit"
|
||||||
|
) {
|
||||||
|
printIndent()
|
||||||
|
generateCall("visit${parent.classNameWithoutFir}", listOf(parameterName, "null"))
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Printer.generateTrampolineVisit(className: String) {
|
||||||
|
val shortcutName = className.classNameWithoutFir
|
||||||
|
val parameterName = shortcutName.decapitalize().safeName
|
||||||
|
generateFunction(
|
||||||
|
name = "visit$shortcutName",
|
||||||
|
parameters = mapOf(
|
||||||
|
parameterName to className,
|
||||||
|
"data" to "Nothing?"
|
||||||
|
),
|
||||||
|
returnType = "Unit",
|
||||||
|
override = true,
|
||||||
|
final = true
|
||||||
|
) {
|
||||||
|
printIndent()
|
||||||
|
generateCall("visit$shortcutName", listOf(parameterName))
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,13 +4,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.jetbrains.kotlin.fir.visitors.generator
|
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.StandardFileSystems
|
||||||
import com.intellij.openapi.vfs.VirtualFileManager
|
import com.intellij.openapi.vfs.VirtualFileManager
|
||||||
import com.intellij.openapi.vfs.local.CoreLocalFileSystem
|
import com.intellij.openapi.vfs.local.CoreLocalFileSystem
|
||||||
import com.intellij.psi.PsiManager
|
import com.intellij.psi.PsiManager
|
||||||
import com.intellij.psi.SingleRootFileViewProvider
|
import com.intellij.psi.SingleRootFileViewProvider
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.utils.Printer
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
|
||||||
@@ -53,20 +53,15 @@ fun main(args: Array<String>) {
|
|||||||
val data = dataCollector.computeResult()
|
val data = dataCollector.computeResult()
|
||||||
|
|
||||||
|
|
||||||
packageDirectory
|
SimpleVisitorGenerator(data).runGenerator(packageDirectory.resolve("${SIMPLE_VISITOR_NAME}Generated.kt"))
|
||||||
.resolve("${SIMPLE_VISITOR_NAME}Generated.kt")
|
UnitVisitorGenerator(data).runGenerator(packageDirectory.resolve("${UNIT_VISITOR_NAME}Generated.kt"))
|
||||||
.writeText(
|
|
||||||
SimpleVisitorGenerator(data).generate()
|
|
||||||
)
|
|
||||||
|
|
||||||
packageDirectory
|
|
||||||
.resolve("${UNIT_VISITOR_NAME}Generated.kt")
|
|
||||||
.writeText(
|
|
||||||
UnitVisitorGenerator(data).generate()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun AbstractVisitorGenerator.runGenerator(file: File) {
|
||||||
|
file.writeText(StringUtil.convertLineSeparators(this.generate(), System.lineSeparator()))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
val String.classNameWithoutFir get() = this.removePrefix("Fir")
|
val String.classNameWithoutFir get() = this.removePrefix("Fir")
|
||||||
|
|
||||||
@@ -79,213 +74,4 @@ fun DataCollector.ReferencesData.walkHierarchyTopDown(from: String, l: (p: Strin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class AbstractVisitorGenerator(val referencesData: DataCollector.ReferencesData) {
|
|
||||||
fun Printer.generateFunction(
|
|
||||||
name: String,
|
|
||||||
parameters: Map<String, String>,
|
|
||||||
returnType: String,
|
|
||||||
override: Boolean = false,
|
|
||||||
final: Boolean = false,
|
|
||||||
body: (Printer.() -> Unit)?
|
|
||||||
) {
|
|
||||||
|
|
||||||
if (body == null) {
|
|
||||||
print("abstract ")
|
|
||||||
} else {
|
|
||||||
printIndent()
|
|
||||||
if (!final) {
|
|
||||||
printWithNoIndent("open ")
|
|
||||||
}
|
|
||||||
if (override) {
|
|
||||||
if (final) {
|
|
||||||
printWithNoIndent("final ")
|
|
||||||
}
|
|
||||||
printWithNoIndent("override ")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printWithNoIndent("fun ", name, "(")
|
|
||||||
parameters
|
|
||||||
.flatMap { (a, b) ->
|
|
||||||
listOf(a, ": ", b, ", ")
|
|
||||||
}.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(")")
|
|
||||||
}
|
|
||||||
|
|
||||||
protected fun Printer.separatedOneLine(iterable: Iterable<Any>, separator: Any) {
|
|
||||||
var first = true
|
|
||||||
for (element in iterable) {
|
|
||||||
if (!first) {
|
|
||||||
printWithNoIndent(separator)
|
|
||||||
} else {
|
|
||||||
first = false
|
|
||||||
}
|
|
||||||
printWithNoIndent(element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected 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()
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract fun Printer.generateContent()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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 "D"
|
|
||||||
),
|
|
||||||
returnType = "R",
|
|
||||||
body = null
|
|
||||||
)
|
|
||||||
referencesData.walkHierarchyTopDown(from = FIR_ELEMENT_CLASS_NAME) { parent, element ->
|
|
||||||
generateVisit(element, parent)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
println("}")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Printer.generateVisit(className: String, parent: String) {
|
|
||||||
val shortcutName = className.classNameWithoutFir
|
|
||||||
val parameterName = shortcutName.decapitalize().safeName
|
|
||||||
generateFunction(
|
|
||||||
name = "visit$shortcutName",
|
|
||||||
parameters = mapOf(
|
|
||||||
parameterName to className,
|
|
||||||
"data" to "D"
|
|
||||||
),
|
|
||||||
returnType = "R"
|
|
||||||
) {
|
|
||||||
print("return ")
|
|
||||||
generateCall("visit${parent.classNameWithoutFir}", listOf(parameterName, "data"))
|
|
||||||
println()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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(FIR_ELEMENT_CLASS_NAME) { parent, klass ->
|
|
||||||
generateVisit(klass, parent)
|
|
||||||
}
|
|
||||||
|
|
||||||
val trampolines = referencesData.back.let {
|
|
||||||
it.keys + it.values.flatten()
|
|
||||||
}.distinct()
|
|
||||||
trampolines.forEach {
|
|
||||||
generateTrampolineVisit(it)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
println("}")
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private fun Printer.generateVisit(className: String, parent: String) {
|
|
||||||
val shortcutName = className.classNameWithoutFir
|
|
||||||
val parameterName = shortcutName.decapitalize().safeName
|
|
||||||
generateFunction(
|
|
||||||
name = "visit$shortcutName",
|
|
||||||
parameters = mapOf(
|
|
||||||
parameterName to className
|
|
||||||
),
|
|
||||||
returnType = "Unit"
|
|
||||||
) {
|
|
||||||
printIndent()
|
|
||||||
generateCall("visit${parent.classNameWithoutFir}", listOf(parameterName, "null"))
|
|
||||||
println()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Printer.generateTrampolineVisit(className: String) {
|
|
||||||
val shortcutName = className.classNameWithoutFir
|
|
||||||
val parameterName = shortcutName.decapitalize().safeName
|
|
||||||
generateFunction(
|
|
||||||
name = "visit$shortcutName",
|
|
||||||
parameters = mapOf(
|
|
||||||
parameterName to className,
|
|
||||||
"data" to "Nothing?"
|
|
||||||
),
|
|
||||||
returnType = "Unit",
|
|
||||||
override = true,
|
|
||||||
final = true
|
|
||||||
) {
|
|
||||||
printIndent()
|
|
||||||
generateCall("visit$shortcutName", listOf(parameterName))
|
|
||||||
println()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user