New J2K: Add basic tree structure and visitor generation script

This commit is contained in:
Simon Ogorodnik
2017-10-12 00:07:50 +03:00
committed by Ilya Kirillov
parent 9d9dbb4c25
commit 5fd3a78dbe
16 changed files with 429 additions and 3 deletions
+113
View File
@@ -0,0 +1,113 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.File
val JK_ROOT = File("./j2k/newSrc/org/jetbrains/kotlin/j2k/tree")
val JK_KT_FILE = File(JK_ROOT, "k.kt")
val JK_JAVA_FILE = File(JK_ROOT, "j.kt")
val JK_COMMON_FILE = File(JK_ROOT, "jk.kt")
val interfaceRegex = "interface (JK[a-zA-Z]+)".toRegex()
fun File.interfaceNames() =
sequenceOf(this)
.map { it.readText() }
.flatMap { interfaceRegex.findAll(it) }
.map { match -> match.groupValues[1] }
.toList()
fun String.safeVarName() = when (this) {
"class" -> "klass"
else -> this
}
fun genVisitors(interfaceNames: List<String>, visitorName: String, extends: String = "") {
val outFile = File(JK_ROOT, "$visitorName.kt")
outFile.writeText(buildString {
appendln("package org.jetbrains.kotlin.j2k.tree")
appendln()
val extends = if (extends.isNotBlank()) ": $extends<R, D>" else ""
appendln("interface $visitorName<R, D> $extends {")
interfaceNames.joinTo(this, separator = "\n") { name ->
val nameWithoutPrefix = name.removePrefix("JK")
"""
| fun visit$nameWithoutPrefix(${nameWithoutPrefix.decapitalize().safeVarName()}: $name, data: D): R
""".trimMargin()
}
appendln()
appendln("}")
})
val outVoidFile = File(JK_ROOT, "${visitorName}Void.kt")
outVoidFile.writeText(buildString {
appendln("package org.jetbrains.kotlin.j2k.tree")
appendln()
val extends = if (extends.isNotBlank()) ", ${extends}Void" else ""
appendln("interface ${visitorName}Void : $visitorName<Unit, Nothing?>$extends {")
interfaceNames.joinTo(this, separator = "\n") { name ->
val nameWithoutPrefix = name.removePrefix("JK")
val argName = nameWithoutPrefix.decapitalize().safeVarName()
val arg = "$argName: $name"
"""
| fun visit$nameWithoutPrefix($arg)
| override fun visit$nameWithoutPrefix($arg, data: Nothing?) = visit$nameWithoutPrefix($argName)
""".trimMargin()
}
appendln()
appendln("}")
})
}
// JKVisitor<R,D> + Void
genVisitors(JK_COMMON_FILE.interfaceNames(), "JKVisitor")
genVisitors(JK_JAVA_FILE.interfaceNames(), "JKJavaVisitor", "JKVisitor")
genVisitors(JK_KT_FILE.interfaceNames(), "JKKtVisitor", "JKVisitor")
genVisitors(JK_JAVA_FILE.interfaceNames() + JK_KT_FILE.interfaceNames(), "JKJavaKtVisitor", "JKVisitor")
/* JKKtVisitor<R,D> : JKVisitor<R,D> + Void
JKJavaVisitor<R,D> : JKVisitor<R,D> + Void
JKJavaKtVisitor<R, D> : JKVisitor<R,D> + Void
*/
//val visitNames =
@@ -18,16 +18,37 @@ package org.jetbrains.kotlin.j2k
import com.intellij.lang.java.JavaLanguage
import com.intellij.psi.JavaElementVisitor
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiField
import org.jetbrains.kotlin.j2k.tree.JKClass
import org.jetbrains.kotlin.j2k.tree.JKElement
import org.jetbrains.kotlin.j2k.tree.impl.JKClassImpl
import org.jetbrains.kotlin.j2k.tree.impl.JKJavaFieldImpl
class JavaToJKTreeBuilder {
private class ElementVisitor : JavaElementVisitor()
fun buildTree(psi: PsiElement): Nothing {
private class ElementVisitor : JavaElementVisitor() {
var currentClass: JKClass? = null
override fun visitClass(aClass: PsiClass) {
currentClass = JKClassImpl()
super.visitClass(aClass)
}
override fun visitField(field: PsiField) {
currentClass!!.declarations.add(JKJavaFieldImpl(field.name!!))
super.visitField(field)
}
}
fun buildTree(psi: PsiElement): JKElement? {
assert(psi.language.`is`(JavaLanguage.INSTANCE)) { "Unable to build JK Tree using Java Visitor for language ${psi.language}" }
val elementVisitor = ElementVisitor()
psi.accept(elementVisitor)
TODO("Tree output type")
return elementVisitor.currentClass
}
}
@@ -0,0 +1,12 @@
package org.jetbrains.kotlin.j2k.tree
interface JKJavaKtVisitor<R, D> : JKVisitor<R, D> {
fun visitJavaElement(javaElement: JKJavaElement, data: D): R
fun visitJavaField(javaField: JKJavaField, data: D): R
fun visitJavaMethod(javaMethod: JKJavaMethod, data: D): R
fun visitJavaForLoop(javaForLoop: JKJavaForLoop, data: D): R
fun visitKtElement(ktElement: JKKtElement, data: D): R
fun visitKtFun(ktFun: JKKtFun, data: D): R
fun visitKtConstructor(ktConstructor: JKKtConstructor, data: D): R
fun visitKtPrimaryConstructor(ktPrimaryConstructor: JKKtPrimaryConstructor, data: D): R
}
@@ -0,0 +1,20 @@
package org.jetbrains.kotlin.j2k.tree
interface JKJavaKtVisitorVoid : JKJavaKtVisitor<Unit, Nothing?>, JKVisitorVoid {
fun visitJavaElement(javaElement: JKJavaElement)
override fun visitJavaElement(javaElement: JKJavaElement, data: Nothing?) = visitJavaElement(javaElement)
fun visitJavaField(javaField: JKJavaField)
override fun visitJavaField(javaField: JKJavaField, data: Nothing?) = visitJavaField(javaField)
fun visitJavaMethod(javaMethod: JKJavaMethod)
override fun visitJavaMethod(javaMethod: JKJavaMethod, data: Nothing?) = visitJavaMethod(javaMethod)
fun visitJavaForLoop(javaForLoop: JKJavaForLoop)
override fun visitJavaForLoop(javaForLoop: JKJavaForLoop, data: Nothing?) = visitJavaForLoop(javaForLoop)
fun visitKtElement(ktElement: JKKtElement)
override fun visitKtElement(ktElement: JKKtElement, data: Nothing?) = visitKtElement(ktElement)
fun visitKtFun(ktFun: JKKtFun)
override fun visitKtFun(ktFun: JKKtFun, data: Nothing?) = visitKtFun(ktFun)
fun visitKtConstructor(ktConstructor: JKKtConstructor)
override fun visitKtConstructor(ktConstructor: JKKtConstructor, data: Nothing?) = visitKtConstructor(ktConstructor)
fun visitKtPrimaryConstructor(ktPrimaryConstructor: JKKtPrimaryConstructor)
override fun visitKtPrimaryConstructor(ktPrimaryConstructor: JKKtPrimaryConstructor, data: Nothing?) = visitKtPrimaryConstructor(ktPrimaryConstructor)
}
@@ -0,0 +1,8 @@
package org.jetbrains.kotlin.j2k.tree
interface JKJavaVisitor<R, D> : JKVisitor<R, D> {
fun visitJavaElement(javaElement: JKJavaElement, data: D): R
fun visitJavaField(javaField: JKJavaField, data: D): R
fun visitJavaMethod(javaMethod: JKJavaMethod, data: D): R
fun visitJavaForLoop(javaForLoop: JKJavaForLoop, data: D): R
}
@@ -0,0 +1,12 @@
package org.jetbrains.kotlin.j2k.tree
interface JKJavaVisitorVoid : JKJavaVisitor<Unit, Nothing?>, JKVisitorVoid {
fun visitJavaElement(javaElement: JKJavaElement)
override fun visitJavaElement(javaElement: JKJavaElement, data: Nothing?) = visitJavaElement(javaElement)
fun visitJavaField(javaField: JKJavaField)
override fun visitJavaField(javaField: JKJavaField, data: Nothing?) = visitJavaField(javaField)
fun visitJavaMethod(javaMethod: JKJavaMethod)
override fun visitJavaMethod(javaMethod: JKJavaMethod, data: Nothing?) = visitJavaMethod(javaMethod)
fun visitJavaForLoop(javaForLoop: JKJavaForLoop)
override fun visitJavaForLoop(javaForLoop: JKJavaForLoop, data: Nothing?) = visitJavaForLoop(javaForLoop)
}
@@ -0,0 +1,8 @@
package org.jetbrains.kotlin.j2k.tree
interface JKKtVisitor<R, D> : JKVisitor<R, D> {
fun visitKtElement(ktElement: JKKtElement, data: D): R
fun visitKtFun(ktFun: JKKtFun, data: D): R
fun visitKtConstructor(ktConstructor: JKKtConstructor, data: D): R
fun visitKtPrimaryConstructor(ktPrimaryConstructor: JKKtPrimaryConstructor, data: D): R
}
@@ -0,0 +1,12 @@
package org.jetbrains.kotlin.j2k.tree
interface JKKtVisitorVoid : JKKtVisitor<Unit, Nothing?>, JKVisitorVoid {
fun visitKtElement(ktElement: JKKtElement)
override fun visitKtElement(ktElement: JKKtElement, data: Nothing?) = visitKtElement(ktElement)
fun visitKtFun(ktFun: JKKtFun)
override fun visitKtFun(ktFun: JKKtFun, data: Nothing?) = visitKtFun(ktFun)
fun visitKtConstructor(ktConstructor: JKKtConstructor)
override fun visitKtConstructor(ktConstructor: JKKtConstructor, data: Nothing?) = visitKtConstructor(ktConstructor)
fun visitKtPrimaryConstructor(ktPrimaryConstructor: JKKtPrimaryConstructor)
override fun visitKtPrimaryConstructor(ktPrimaryConstructor: JKKtPrimaryConstructor, data: Nothing?) = visitKtPrimaryConstructor(ktPrimaryConstructor)
}
@@ -0,0 +1,11 @@
package org.jetbrains.kotlin.j2k.tree
interface JKVisitor<R, D> {
fun visitElement(element: JKElement, data: D): R
fun visitClass(klass: JKClass, data: D): R
fun visitMember(member: JKMember, data: D): R
fun visitExpression(expression: JKExpression, data: D): R
fun visitStatement(statement: JKStatement, data: D): R
fun visitLoop(loop: JKLoop, data: D): R
fun visitDeclaration(declaration: JKDeclaration, data: D): R
}
@@ -0,0 +1,18 @@
package org.jetbrains.kotlin.j2k.tree
interface JKVisitorVoid : JKVisitor<Unit, Nothing?> {
fun visitElement(element: JKElement)
override fun visitElement(element: JKElement, data: Nothing?) = visitElement(element)
fun visitClass(klass: JKClass)
override fun visitClass(klass: JKClass, data: Nothing?) = visitClass(klass)
fun visitMember(member: JKMember)
override fun visitMember(member: JKMember, data: Nothing?) = visitMember(member)
fun visitExpression(expression: JKExpression)
override fun visitExpression(expression: JKExpression, data: Nothing?) = visitExpression(expression)
fun visitStatement(statement: JKStatement)
override fun visitStatement(statement: JKStatement, data: Nothing?) = visitStatement(statement)
fun visitLoop(loop: JKLoop)
override fun visitLoop(loop: JKLoop, data: Nothing?) = visitLoop(loop)
fun visitDeclaration(declaration: JKDeclaration)
override fun visitDeclaration(declaration: JKDeclaration, data: Nothing?) = visitDeclaration(declaration)
}
@@ -0,0 +1,47 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.j2k.tree.impl
import org.jetbrains.kotlin.j2k.tree.JKJavaElement
import org.jetbrains.kotlin.j2k.tree.JKJavaField
import org.jetbrains.kotlin.j2k.tree.JKJavaVisitor
import org.jetbrains.kotlin.j2k.tree.JKVisitor
abstract class JKJavaElementBase : JKJavaElement {
override fun <R, D> accept(visitor: JKVisitor<R, D>, data: D): R {
return if (visitor is JKJavaVisitor) {
visitor.visitJavaElement(this, data)
}
else {
visitor.visitElement(this, data)
}
}
override fun <D> acceptChildren(visitor: JKVisitor<Unit, D>, data: D) {}
}
class JKJavaFieldImpl(val name: String) : JKJavaField, JKJavaElementBase() {
override fun <R, D> accept(visitor: JKVisitor<R, D>, data: D): R {
return if (visitor is JKJavaVisitor) {
visitor.visitJavaField(this, data)
}
else {
visitor.visitDeclaration(this, data)
}
}
}
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.j2k.tree.impl
import org.jetbrains.kotlin.j2k.tree.JKClass
import org.jetbrains.kotlin.j2k.tree.JKDeclaration
import org.jetbrains.kotlin.j2k.tree.JKElement
import org.jetbrains.kotlin.j2k.tree.JKVisitor
abstract class JKElementBase : JKElement {
override fun <R, D> accept(visitor: JKVisitor<R, D>, data: D): R = visitor.visitElement(this, data)
override fun <D> acceptChildren(visitor: JKVisitor<Unit, D>, data: D) {}
}
class JKClassImpl : JKClass, JKElementBase() {
override fun <R, D> accept(visitor: JKVisitor<R, D>, data: D): R = visitor.visitClass(this, data)
override fun <D> acceptChildren(visitor: JKVisitor<Unit, D>, data: D) {
declarations.forEach { it.accept(visitor, data) }
}
override val declarations = mutableListOf<JKDeclaration>()
}
@@ -0,0 +1,18 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.j2k.tree.impl
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.j2k.tree
interface JKJavaElement : JKElement
interface JKJavaField : JKJavaElement, JKDeclaration, JKMember
interface JKJavaMethod : JKJavaElement, JKDeclaration, JKMember
interface JKJavaForLoop : JKJavaElement, JKLoop
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.j2k.tree
interface JKElement {
fun <R, D> accept(visitor: JKVisitor<R, D>, data: D): R
fun <D> acceptChildren(visitor: JKVisitor<Unit, D>, data: D)
}
interface JKClass : JKElement {
val declarations: MutableList<JKDeclaration>
}
interface JKMember : JKElement
interface JKExpression : JKElement
interface JKStatement : JKElement
interface JKLoop : JKStatement
interface JKDeclaration : JKElement
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.j2k.tree
interface JKKtElement: JKElement
interface JKKtFun: JKKtElement, JKDeclaration
interface JKKtConstructor: JKKtElement, JKDeclaration
interface JKKtPrimaryConstructor: JKKtElement, JKKtConstructor