[kotlin j2k] Fix conversion of escaped dollar sign in string literals
[idea/community.git] / plugins / kotlin / j2k / new / GenerateJKTreeVisitorAndTransformer.kt
1 /*
2  * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
3  * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
4  */
5
6 import java.io.File
7
8
9 private val JK_ROOT = File("./nj2k/src/org/jetbrains/kotlin/nj2k/tree")
10
11 private val JK_OUT_ROOT = File(JK_ROOT, "visitors")
12
13 private val JK_TREE_FILES = listOf(
14     "declarations.kt",
15     "elements.kt",
16     "expressions.kt",
17     "modifiers.kt",
18     "statements.kt"
19 ).map { File(JK_ROOT, it) }
20
21
22 val elementRegex = """(class|object)\s+(JK[\w]+)(\([\w\s:,<>=\(\)\\]+\))?\s*:\s*(JK[a-zA-Z]+)""".toRegex()
23
24
25 data class InterfaceData(val name: String, val extends: String?)
26
27 fun File.interfaceNames() =
28     sequenceOf(this)
29         .map { it.readText() }
30         .flatMap { elementRegex.findAll(it) }
31         .map { match ->
32             InterfaceData(
33                 match.groupValues[2],
34                 match.groupValues[4].let { if (it == "JKAnnotationMemberValue") "JKTreeElement" else it }
35             )
36         }.toList()
37
38
39 fun String.safeVarName() = when (this) {
40     "class" -> "klass"
41     else -> this
42 }
43
44 fun genVisitors(
45     interfaceData: List<InterfaceData>,
46     visitorName: String
47 ) {
48     val pkg = "package org.jetbrains.kotlin.nj2k.tree.visitors"
49
50     File(JK_OUT_ROOT, "$visitorName.kt").writeText(buildString {
51         appendln(pkg)
52         appendln()
53         appendln("import org.jetbrains.kotlin.nj2k.tree.*")
54         appendln()
55         appendln("abstract class $visitorName {")
56         interfaceData.joinTo(this, separator = "\n") { (name, ext) ->
57             val nameWithoutPrefix = name.removePrefix("JK")
58             val argName = nameWithoutPrefix.decapitalize().safeVarName()
59             val generifyCall = if (name != "JKTreeElement") "= visit${ext?.removePrefix("JK") ?: error(name)}($argName)" else ""
60             val modifier = if (name == "JKTreeElement") "abstract" else "open"
61             """
62             |    $modifier fun visit$nameWithoutPrefix($argName: $name) $generifyCall
63             """.trimMargin()
64         }
65         appendln()
66         appendln("}")
67     })
68
69
70     File(JK_OUT_ROOT, "${visitorName}WithCommentsPrinting.kt").writeText(buildString {
71         appendln(pkg)
72         appendln()
73         appendln("import org.jetbrains.kotlin.nj2k.tree.*")
74         appendln()
75
76         appendln("abstract class ${visitorName}WithCommentsPrinting : $visitorName() {")
77         appendln(
78             """
79         |    abstract fun printLeftNonCodeElements(element: JKNonCodeElementsListOwner)
80         |    abstract fun printRightNonCodeElements(element: JKNonCodeElementsListOwner)
81         |
82         """.trimMargin()
83         )
84
85         interfaceData.joinTo(this, separator = "\n\n") { (name, ext) ->
86             val nameWithoutPrefix = name.removePrefix("JK")
87             val argName = nameWithoutPrefix.decapitalize().safeVarName()
88             val arg = "$argName: $name"
89             val rawVisitSuffix = "Raw"
90             val generifyCall = if (name != "JKTreeElement") "= visit${ext!!.removePrefix("JK")}$rawVisitSuffix($argName)" else ""
91             val modifier = if (name == "JKTreeElement") "abstract" else "open"
92             """
93             |    final override fun visit$nameWithoutPrefix($arg) {
94             |        printLeftNonCodeElements($argName)
95             |        visit$nameWithoutPrefix$rawVisitSuffix($argName)
96             |        printRightNonCodeElements($argName)
97             |    }
98             |
99             |    $modifier fun visit$nameWithoutPrefix$rawVisitSuffix($arg) $generifyCall
100             """.trimMargin()
101         }
102         appendln()
103         appendln("}")
104     })
105 }
106
107 fun main() {
108     genVisitors(JK_TREE_FILES.flatMap { it.interfaceNames() }, "JKVisitor")
109 }
110