diff --git a/j2k/src/org/jetbrains/jet/j2k/Converter.kt b/j2k/src/org/jetbrains/jet/j2k/Converter.kt index 557e08ab792..6ca52816057 100644 --- a/j2k/src/org/jetbrains/jet/j2k/Converter.kt +++ b/j2k/src/org/jetbrains/jet/j2k/Converter.kt @@ -84,12 +84,15 @@ public class Converter(val project: Project, val settings: ConverterSettings) { } public fun convertAnonymousClass(anonymousClass: PsiAnonymousClass): AnonymousClass { - return AnonymousClass(this, getMembers(anonymousClass)) + return AnonymousClass(this, convertMembers(anonymousClass)) } - private fun getMembers(psiClass: PsiClass): List { - val members = ArrayList() + private fun convertMembers(psiClass: PsiClass): List { + val members = ArrayList() for (e in psiClass.getChildren()) { + if (psiClass is PsiAnonymousClass && psiClass.getBaseClassReference() == e) { + continue + } val converted = convertMember(e, psiClass) if (converted != null) members.add(converted) } @@ -101,14 +104,13 @@ public class Converter(val project: Project, val settings: ConverterSettings) { return if (psiDocComment != null) Comment(psiDocComment.getText()!!) else null } - private fun convertMember(e: PsiElement?, containingClass: PsiClass): Node? = when(e) { + private fun convertMember(e: PsiElement?, containingClass: PsiClass): Element? = when(e) { is PsiMethod -> convertMethod(e, true) is PsiField -> convertField(e, containingClass) is PsiClass -> convertClass(e) is PsiClassInitializer -> convertInitializer(e) is PsiDocComment -> null - is PsiComment -> Comment(e.getText()!!) - else -> null + else -> convertElement(e) } private fun convertClass(psiClass: PsiClass): Class { @@ -119,7 +121,7 @@ public class Converter(val project: Project, val settings: ConverterSettings) { val extendsTypes = convertToNotNullableTypes(psiClass.getExtendsListTypes()) val name: Identifier = Identifier(psiClass.getName()!!) val baseClassParams = ArrayList() - val members = ArrayList(getMembers(psiClass)) + val members = ArrayList(convertMembers(psiClass)) val visitor = SuperVisitor() psiClass.accept(visitor) val resolvedSuperCallParameters = visitor.resolvedSuperCallParameters diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClass.kt b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClass.kt index 8a201bd2257..8c2e0d97590 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClass.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/AnonymousClass.kt @@ -20,7 +20,7 @@ import org.jetbrains.jet.j2k.Converter import org.jetbrains.jet.j2k.ast.types.Type import java.util.Collections -public class AnonymousClass(converter: Converter, members: List) +public class AnonymousClass(converter: Converter, members: List) : Class(converter, Identifier("anonClass"), null, diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt index d8a4dfc299c..4c3e99027ea 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Class.kt @@ -30,32 +30,27 @@ public open class Class(val converter: Converter, val extendsTypes: List, val baseClassParams: List, val implementsTypes: List, - val members: List) : Member(docComment, modifiers) { + val members: List) : Member(docComment, modifiers) { open val TYPE: String get() = "class" - private fun getPrimaryConstructor(): Constructor? { - return members.find { it is Constructor && it.isPrimary } as Constructor? - } + val classMembers = parseClassMembers(members) open fun primaryConstructorSignatureToKotlin(): String { - val maybeConstructor: Constructor? = getPrimaryConstructor() - return if (maybeConstructor != null) maybeConstructor.primarySignatureToKotlin() else "()" + val constructor = classMembers.primaryConstructor + return if (constructor != null) constructor.primarySignatureToKotlin() else "()" } fun primaryConstructorBodyToKotlin(): String? { - val maybeConstructor = getPrimaryConstructor() + val maybeConstructor = classMembers.primaryConstructor if (maybeConstructor != null && !(maybeConstructor.block?.isEmpty() ?: true)) { - return maybeConstructor.primaryBodyToKotlin() + "\n" + return "\n" + maybeConstructor.primaryBodyToKotlin() + "\n" } - return "" } - fun membersExceptConstructors(): List = members.filterNot { it is Constructor } - - fun secondaryConstructorsAsStaticInitFunction(): List { - return members.filter { it is Constructor && !it.isPrimary }.map { constructorToInit(it as Function) } + fun secondaryConstructorsAsStaticInitFunction(): MemberList { + return MemberList(classMembers.secondaryConstructors.elements.map { if (it is Constructor) constructorToInit(it) else it }) } private fun constructorToInit(f: Function): Function { @@ -110,14 +105,16 @@ public open class Class(val converter: Converter, open fun needsOpenModifier() = !isDefinitelyFinal() && converter.settings.openByDefault fun bodyToKotlin(): String { - return " {\n" + getNonStatic(membersExceptConstructors()).toKotlin("\n", "", "\n") + primaryConstructorBodyToKotlin() + classObjectToKotlin() + "}" + return " {" + classMembers.nonStaticMembers.toKotlin() + primaryConstructorBodyToKotlin() + classObjectToKotlin() + "}" } fun classObjectToKotlin(): String { - val staticMembers = ArrayList() - staticMembers.addAll(secondaryConstructorsAsStaticInitFunction()) - staticMembers.addAll(getStatic(membersExceptConstructors())) - return staticMembers.toKotlin("\n", "class object {\n", "\n}") + val secondaryConstructorsAsStaticInitFunction = secondaryConstructorsAsStaticInitFunction() + val staticMembers = classMembers.staticMembers + if (secondaryConstructorsAsStaticInitFunction.isEmpty() && staticMembers.isEmpty()) { + return "" + } + return "\nclass object {${secondaryConstructorsAsStaticInitFunction.toKotlin()}${staticMembers.toKotlin()}}" } override fun toKotlin(): String = diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt index f1442f9a227..f2e9d9111c4 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Enum.kt @@ -27,7 +27,7 @@ public class Enum(converter: Converter, extendsTypes: List, baseClassParams: List, implementsTypes: List, - members: List) : Class(converter, name, docComments, modifiers, typeParameterList, + members: List) : Class(converter, name, docComments, modifiers, typeParameterList, extendsTypes, baseClassParams, implementsTypes, members) { override fun primaryConstructorSignatureToKotlin(): String { @@ -44,8 +44,9 @@ public class Enum(converter: Converter, primaryConstructorSignatureToKotlin() + typeParameterList.toKotlin() + implementTypesToKotlin() + - " {\n" + membersExceptConstructors().toKotlin("\n", "", "\n") + - (if (primaryConstructorBody.isEmpty()) "" else primaryConstructorBody) + + " {" + + classMembers.allMembers.toKotlin() + + ( if (primaryConstructorBody.isEmpty()) "" else primaryConstructorBody) + "}" } -} +} \ No newline at end of file diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.kt b/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.kt index 33f09671601..771754297e2 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/ExpressionList.kt @@ -18,4 +18,5 @@ package org.jetbrains.jet.j2k.ast public open class ExpressionList(val expressions: List) : Expression() { public override fun toKotlin(): String = expressions.map { it.toKotlin() }.makeString(", ") + override fun isEmpty(): Boolean = expressions.isEmpty() } diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Member.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Member.kt deleted file mode 100644 index ff5770be714..00000000000 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Member.kt +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2010-2013 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.jet.j2k.ast - -public abstract class Member(val docComment: Comment?, val modifiers: Set) : Node { - fun accessModifier(): Modifier? { - return modifiers.find { m -> m == Modifier.PUBLIC || m == Modifier.PROTECTED || m == Modifier.PRIVATE } - } - - public fun isAbstract(): Boolean = modifiers.contains(Modifier.ABSTRACT) - public fun isStatic(): Boolean = modifiers.contains(Modifier.STATIC) - public fun docCommentToKotlin(): String = if (docComment != null) docComment.toKotlin() + "\n" else "" -} diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt new file mode 100644 index 00000000000..77ff733eea6 --- /dev/null +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Members.kt @@ -0,0 +1,79 @@ +/* + * Copyright 2010-2013 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.jet.j2k.ast + +import java.util.ArrayList + +public abstract class Member(val docComment: Comment?, val modifiers: Set) : Element { + fun accessModifier(): Modifier? { + return modifiers.find { m -> m == Modifier.PUBLIC || m == Modifier.PROTECTED || m == Modifier.PRIVATE } + } + + public fun isAbstract(): Boolean = modifiers.contains(Modifier.ABSTRACT) + public fun isStatic(): Boolean = modifiers.contains(Modifier.STATIC) + public fun docCommentToKotlin(): String = if (docComment != null) docComment.toKotlin() + "\n" else "" +} + +//member itself and all the elements before it in the code (comments, whitespaces) +class MemberHolder(val member: Member, val elements: List) + +public class MemberList(elements: List) : WhiteSpaceSeparatedElementList(elements, WhiteSpace.NewLine) { + val members: List + get() = elements.filter { it is Member }.map { it as Member } +} + +public class ClassMembers( + val primaryConstructor: Constructor?, + val secondaryConstructors: MemberList, + val allMembers: MemberList, + val staticMembers: MemberList, + val nonStaticMembers: MemberList +) { +} + +fun parseClassMembers(elements: List): ClassMembers { + val groups = splitInGroups(elements) + val constructors = groups.filter { it.member is Constructor } + val primaryConstructor = constructors.map { it.member }.find { (it as Constructor).isPrimary } + val secondaryConstructors = constructors.filter { !(it.member as Constructor).isPrimary } + val nonConstructors = groups.filter { it.member !is Constructor } + val staticMembers = nonConstructors.filter { it.member.isStatic() } + val nonStaticMembers = nonConstructors.filter { !it.member.isStatic() } + return ClassMembers(primaryConstructor as Constructor?, + secondaryConstructors.toMemberList(), + nonConstructors.toMemberList(), + staticMembers.toMemberList(), + nonStaticMembers.toMemberList()) +} + +private fun List.toMemberList() = MemberList(flatMap { it.elements }) + +private fun splitInGroups(elements: List): List { + val result = ArrayList>>() + var currentGroup = ArrayList() + for (element in elements) { + currentGroup.add(element) + if (element is Member) { + result.add(Pair(element, currentGroup)) + currentGroup = ArrayList() + } + } + if (result.isNotEmpty()) { + result.last!!.second.addAll(currentGroup) + } + return result map { MemberHolder(it.first, it.second) } +} \ No newline at end of file diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt index 65fabcfe234..9074e53b4e6 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Trait.kt @@ -27,8 +27,8 @@ public class Trait(converter: Converter, extendsTypes: List, baseClassParams: List, implementsTypes: List, - members: List) : Class(converter, name, docComment, modifiers, typeParameterList, - extendsTypes, baseClassParams, implementsTypes, members) { + members: List) : Class(converter, name, docComment, modifiers, typeParameterList, + extendsTypes, baseClassParams, implementsTypes, members) { override val TYPE: String get() = "trait" diff --git a/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt b/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt index cde74bdf8e1..dba3f3817a9 100644 --- a/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt +++ b/j2k/src/org/jetbrains/jet/j2k/ast/Util.kt @@ -52,8 +52,10 @@ open class WhiteSpaceSeparatedElementList( ) { val nonEmptyElements = elements.filterNot { it.isEmpty() } + fun isEmpty() = nonEmptyElements.all { it is WhiteSpace } + fun toKotlin(): String { - if (nonEmptyElements.isEmpty()) { + if (isEmpty()) { return "" } return nonEmptyElements.surroundWithWhiteSpaces().insertAndMergeWhiteSpaces().map { it.toKotlin() }.makeString("")