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
|
||||
}
|
||||
|
||||
private fun Map<String, List<String>>.sorted(): Map<String, List<String>> {
|
||||
return this.toSortedMap().mapValues { (_, v) -> v.sorted() }
|
||||
}
|
||||
|
||||
fun computeResult(): ReferencesData {
|
||||
val back = references.computeBackReferences()
|
||||
@@ -70,9 +73,9 @@ class DataCollector {
|
||||
|
||||
val cleanBack = back.filterKeys { it in keysToKeep }
|
||||
return ReferencesData(
|
||||
cleanBack.computeBackReferences(),
|
||||
cleanBack,
|
||||
packagePerClass.filterKeys { it in keysToKeep }.values.distinct()
|
||||
cleanBack.computeBackReferences().sorted(),
|
||||
cleanBack.sorted(),
|
||||
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
|
||||
|
||||
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 org.jetbrains.kotlin.utils.Printer
|
||||
import java.io.File
|
||||
|
||||
|
||||
@@ -53,20 +53,15 @@ fun main(args: Array<String>) {
|
||||
val data = dataCollector.computeResult()
|
||||
|
||||
|
||||
packageDirectory
|
||||
.resolve("${SIMPLE_VISITOR_NAME}Generated.kt")
|
||||
.writeText(
|
||||
SimpleVisitorGenerator(data).generate()
|
||||
)
|
||||
|
||||
packageDirectory
|
||||
.resolve("${UNIT_VISITOR_NAME}Generated.kt")
|
||||
.writeText(
|
||||
UnitVisitorGenerator(data).generate()
|
||||
)
|
||||
SimpleVisitorGenerator(data).runGenerator(packageDirectory.resolve("${SIMPLE_VISITOR_NAME}Generated.kt"))
|
||||
UnitVisitorGenerator(data).runGenerator(packageDirectory.resolve("${UNIT_VISITOR_NAME}Generated.kt"))
|
||||
}
|
||||
}
|
||||
|
||||
fun AbstractVisitorGenerator.runGenerator(file: File) {
|
||||
file.writeText(StringUtil.convertLineSeparators(this.generate(), System.lineSeparator()))
|
||||
}
|
||||
|
||||
|
||||
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