/* * 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. */ import java.io.File private val JK_ROOT = File("./nj2k/src/org/jetbrains/kotlin/nj2k/tree") private val JK_OUT_ROOT = File(JK_ROOT, "visitors") private val JK_TREE_FILES = listOf( "declarations.kt", "elements.kt", "expressions.kt", "modifiers.kt", "statements.kt" ).map { File(JK_ROOT, it) } val elementRegex = """(class|object)\s+(JK[\w]+)(\([\w\s:,<>=\(\)\\]+\))?\s*:\s*(JK[a-zA-Z]+)""".toRegex() data class InterfaceData(val name: String, val extends: String?) fun File.interfaceNames() = sequenceOf(this) .map { it.readText() } .flatMap { elementRegex.findAll(it) } .map { match -> InterfaceData( match.groupValues[2], match.groupValues[4].let { if (it == "JKAnnotationMemberValue") "JKTreeElement" else it } ) }.toList() fun String.safeVarName() = when (this) { "class" -> "klass" else -> this } fun genVisitors( interfaceData: List, visitorName: String ) { val pkg = "package org.jetbrains.kotlin.nj2k.tree.visitors" File(JK_OUT_ROOT, "$visitorName.kt").writeText(buildString { appendln(pkg) appendln() appendln("import org.jetbrains.kotlin.nj2k.tree.*") appendln() appendln("abstract class $visitorName {") interfaceData.joinTo(this, separator = "\n") { (name, ext) -> val nameWithoutPrefix = name.removePrefix("JK") val argName = nameWithoutPrefix.decapitalize().safeVarName() val generifyCall = if (name != "JKTreeElement") "= visit${ext?.removePrefix("JK") ?: error(name)}($argName)" else "" val modifier = if (name == "JKTreeElement") "abstract" else "open" """ | $modifier fun visit$nameWithoutPrefix($argName: $name) $generifyCall """.trimMargin() } appendln() appendln("}") }) File(JK_OUT_ROOT, "${visitorName}WithCommentsPrinting.kt").writeText(buildString { appendln(pkg) appendln() appendln("import org.jetbrains.kotlin.nj2k.tree.*") appendln() appendln("abstract class ${visitorName}WithCommentsPrinting : $visitorName() {") appendln( """ | abstract fun printLeftNonCodeElements(element: JKNonCodeElementsListOwner) | abstract fun printRightNonCodeElements(element: JKNonCodeElementsListOwner) | """.trimMargin() ) interfaceData.joinTo(this, separator = "\n\n") { (name, ext) -> val nameWithoutPrefix = name.removePrefix("JK") val argName = nameWithoutPrefix.decapitalize().safeVarName() val arg = "$argName: $name" val rawVisitSuffix = "Raw" val generifyCall = if (name != "JKTreeElement") "= visit${ext!!.removePrefix("JK")}$rawVisitSuffix($argName)" else "" val modifier = if (name == "JKTreeElement") "abstract" else "open" """ | final override fun visit$nameWithoutPrefix($arg) { | printLeftNonCodeElements($argName) | visit$nameWithoutPrefix$rawVisitSuffix($argName) | printRightNonCodeElements($argName) | } | | $modifier fun visit$nameWithoutPrefix$rawVisitSuffix($arg) $generifyCall """.trimMargin() } appendln() appendln("}") }) } fun main() { genVisitors(JK_TREE_FILES.flatMap { it.interfaceNames() }, "JKVisitor") }