diff --git a/compiler/fir/tree/visitors-generator/src/AbstractVisitorGenerator.kt b/compiler/fir/tree/visitors-generator/src/AbstractVisitorGenerator.kt new file mode 100644 index 00000000000..3029d5fe7e9 --- /dev/null +++ b/compiler/fir/tree/visitors-generator/src/AbstractVisitorGenerator.kt @@ -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, + 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) { + printWithNoIndent(name, "(") + separatedOneLine(args, ", ") + printWithNoIndent(")") + } + + protected fun Printer.separatedOneLine(iterable: Iterable, 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() + +} \ No newline at end of file diff --git a/compiler/fir/tree/visitors-generator/src/DataCollector.kt b/compiler/fir/tree/visitors-generator/src/DataCollector.kt index 2520f3aeb60..c5a6acd51d9 100644 --- a/compiler/fir/tree/visitors-generator/src/DataCollector.kt +++ b/compiler/fir/tree/visitors-generator/src/DataCollector.kt @@ -59,6 +59,9 @@ class DataCollector { return result } + private fun Map>.sorted(): Map> { + 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() } ) } diff --git a/compiler/fir/tree/visitors-generator/src/SimpleVisitorGenerator.kt b/compiler/fir/tree/visitors-generator/src/SimpleVisitorGenerator.kt new file mode 100644 index 00000000000..6d4c7d20742 --- /dev/null +++ b/compiler/fir/tree/visitors-generator/src/SimpleVisitorGenerator.kt @@ -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 {") + 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() + } + } +} \ No newline at end of file diff --git a/compiler/fir/tree/visitors-generator/src/UnitVisitorGenerator.kt b/compiler/fir/tree/visitors-generator/src/UnitVisitorGenerator.kt new file mode 100644 index 00000000000..d53265edae7 --- /dev/null +++ b/compiler/fir/tree/visitors-generator/src/UnitVisitorGenerator.kt @@ -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() {") + 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() + } + } +} \ No newline at end of file diff --git a/compiler/fir/tree/visitors-generator/src/VisitorsGenerator.kt b/compiler/fir/tree/visitors-generator/src/VisitorsGenerator.kt index 2780586d5aa..9e51c52a0ad 100644 --- a/compiler/fir/tree/visitors-generator/src/VisitorsGenerator.kt +++ b/compiler/fir/tree/visitors-generator/src/VisitorsGenerator.kt @@ -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) { 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, - 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) { - printWithNoIndent(name, "(") - separatedOneLine(args, ", ") - printWithNoIndent(")") - } - - protected fun Printer.separatedOneLine(iterable: Iterable, 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 {") - 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() {") - 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() - } - } -} \ No newline at end of file