Converter:

Preserve white spaces inside code blocks
Introduce WhiteSpaceSeparatedElementList which keeps track of whitespaces
Introduce StatementList
Change old test data accordingly
This commit is contained in:
Pavel Talanov
2013-12-02 17:40:39 +04:00
committed by Pavel V. Talanov
parent fabfcb4271
commit 8577d3ca55
34 changed files with 183 additions and 30 deletions
+10 -14
View File
@@ -139,7 +139,7 @@ public class Converter(val project: Project, val settings: ConverterSettings) {
val init = getDefaultInitializer(fo)
initializers.put(fo.identifier.toKotlin(), init)
}
val newStatements = ArrayList<Element>()
val newStatements = ArrayList<Statement>()
for (s in m.block!!.statements) {
var isRemoved: Boolean = false
if (s is AssignmentExpression) {
@@ -262,7 +262,7 @@ public class Converter(val project: Project, val settings: ConverterSettings) {
for (parameter : PsiParameter? in method.getParameterList().getParameters()) {
result.add(Parameter(Identifier(parameter?.getName()!!),
convertType(parameter?.getType(),
isAnnotatedAsNotNull(parameter?.getModifierList())),
isAnnotatedAsNotNull(parameter?.getModifierList())),
isReadOnly(parameter, method.getBody())))
}
return ParameterList(result)
@@ -272,28 +272,24 @@ public class Converter(val project: Project, val settings: ConverterSettings) {
if (block == null)
return Block.EMPTY_BLOCK
return Block(convertStatements(block.getChildren()), notEmpty)
return Block(convertStatements(block.getChildren().toList()), notEmpty)
}
public fun convertBlock(block: PsiCodeBlock?): Block {
return convertBlock(block, true)
}
public fun convertStatements(statements: Array<PsiElement>): List<Element> {
return statements.filterNot { it is PsiWhiteSpace }.map { convertStatement(it) }
public fun convertStatements(statements: List<PsiElement>): StatementList {
return StatementList(statements.map { if (it is PsiStatement) convertStatement(it) else convertElement(it) })
}
public fun convertStatements(statements: List<PsiElement>): List<Element> {
return statements.filterNot { it is PsiWhiteSpace }.map { convertStatement(it) }
}
public fun convertStatement(s: PsiElement?): Element {
public fun convertStatement(s: PsiStatement?): Statement {
if (s == null)
return Statement.EMPTY_STATEMENT
val statementVisitor: StatementVisitor = StatementVisitor(this)
s.accept(statementVisitor)
return statementVisitor.getResult()
return statementVisitor.getResult() as Statement
}
public fun convertExpressions(expressions: Array<PsiExpression>): List<Expression> {
@@ -373,7 +369,7 @@ public class Converter(val project: Project, val settings: ConverterSettings) {
public fun convertParameter(parameter: PsiParameter, forceNotNull: Boolean = false): Parameter {
return Parameter(Identifier(parameter.getName()!!),
convertType(parameter.getType(),
forceNotNull || isAnnotatedAsNotNull(parameter.getModifierList())), true)
forceNotNull || isAnnotatedAsNotNull(parameter.getModifierList())), true)
}
public fun convertArguments(expression: PsiCallExpression): List<Expression> {
@@ -449,8 +445,8 @@ public class Converter(val project: Project, val settings: ConverterSettings) {
return fields.map { Parameter(Identifier("_" + it.identifier.name), it.`type`, true) }
}
private fun createInitStatementsFromFields(fields: List<Field>): List<Element> {
val result = ArrayList<Element>()
private fun createInitStatementsFromFields(fields: List<Field>): List<Statement> {
val result = ArrayList<Statement>()
for (f : Field in fields) {
val identifierToKotlin: String? = f.identifier.toKotlin()
result.add(DummyStringExpression(identifierToKotlin + " = " + "_" + identifierToKotlin))
+14 -3
View File
@@ -18,20 +18,31 @@ package org.jetbrains.jet.j2k.ast
import java.util.ArrayList
public open class Block(val statements: List<Element>, val notEmpty: Boolean = false) : Statement() {
public fun Block(statements: List<Statement>, notEmpty: Boolean = false): Block {
val elements = ArrayList<Element>()
elements.add(WhiteSpace.NewLine)
elements.addAll(statements)
elements.add(WhiteSpace.NewLine)
return Block(StatementList(elements), notEmpty)
}
public class Block(val statementList: StatementList, val notEmpty: Boolean = false) : Statement() {
public val statements: List<Statement> = statementList.statements
public override fun isEmpty(): Boolean {
return !notEmpty && statements.all { it.isEmpty() }
}
public override fun toKotlin(): String {
if (!isEmpty()) {
return "{\n" + statements .filter { !it.isEmpty() }.toKotlin("\n", "", "\n") + "}"
return "{${statementList.toKotlin()}}"
}
return ""
}
class object {
public val EMPTY_BLOCK: Block = Block(ArrayList())
public val EMPTY_BLOCK: Block = Block(StatementList(ArrayList()))
}
}
+1 -1
View File
@@ -61,7 +61,7 @@ public open class Class(val converter: Converter,
private fun constructorToInit(f: Function): Function {
val modifiers = HashSet<Modifier>(f.modifiers)
modifiers.add(Modifier.STATIC)
val statements = ArrayList<Element>(f.block?.statements ?: listOf())
val statements = ArrayList(f.block?.statements ?: ArrayList())
statements.add(ReturnStatement(Identifier("__")))
val block = Block(statements)
val constructorTypeParameters = ArrayList<TypeParameter>()
@@ -123,7 +123,7 @@ public open class SwitchContainer(val expression: Expression, val caseContainers
public override fun toKotlin() = "when (" + expression.toKotlin() + ") {\n" + caseContainers.toKotlin("\n") + "\n}"
}
public open class CaseContainer(val caseStatement: List<Element>, statements: List<Element>) : Statement() {
public open class CaseContainer(val caseStatement: List<Element>, statements: List<Statement>) : Statement() {
private val myBlock: Block
{
+59
View File
@@ -16,6 +16,8 @@
package org.jetbrains.jet.j2k.ast
import java.util.ArrayList
public fun List<Node>.toKotlin(separator: String, prefix: String = "", suffix: String = ""): String {
val result = StringBuilder()
if (size() > 0) {
@@ -43,3 +45,60 @@ public fun Collection<Modifier>.toKotlin(separator: String = " "): String {
public fun String.withSuffix(suffix: String): String = if (isEmpty()) "" else this + suffix
public fun String.withPrefix(prefix: String): String = if (isEmpty()) "" else prefix + this
public fun Expression.withPrefix(prefix: String): String = if (isEmpty()) "" else prefix + toKotlin()
open class WhiteSpaceSeparatedElementList(
val elements: List<Element>,
val minimalWhiteSpace: WhiteSpace
) {
val nonEmptyElements = elements.filterNot { it.isEmpty() }
fun toKotlin(): String {
if (nonEmptyElements.isEmpty()) {
return ""
}
return nonEmptyElements.surroundWithWhiteSpaces().insertAndMergeWhiteSpaces().map { it.toKotlin() }.makeString("")
}
private fun List<Element>.surroundWithWhiteSpaces(): List<Element> {
val result = ArrayList<Element>()
result.add(minimalWhiteSpace)
result.addAll(this)
result.add(minimalWhiteSpace)
return result
}
// ensure that there is whitespace between non-whitespace elements
// choose maximum among subsequent whitespaces
// all resulting whitespaces are at least minimal whitespace
private fun List<Element>.insertAndMergeWhiteSpaces(): List<Element> {
var currentWhiteSpace: WhiteSpace? = null
val result = ArrayList<Element>()
var isFirst = true
for (element in this) {
if (element is WhiteSpace) {
if (currentWhiteSpace == null || element > currentWhiteSpace!!) {
currentWhiteSpace = if (element > minimalWhiteSpace) element else minimalWhiteSpace
}
}
else {
if (!isFirst) {
//do not insert whitespace before first element
result.add(currentWhiteSpace ?: minimalWhiteSpace)
}
result.add(element)
currentWhiteSpace = null
}
isFirst = false
}
if (currentWhiteSpace != null) {
result.add(currentWhiteSpace!!)
}
return result
}
}
public class StatementList(elements: List<Element>) : WhiteSpaceSeparatedElementList(elements, WhiteSpace.NewLine) {
val statements: List<Statement>
get() = elements.filter { it is Statement }.map { it as Statement }
}
@@ -0,0 +1,43 @@
/*
* 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 class WhiteSpace(val text: String) : Element {
override fun toKotlin() = text
override fun isEmpty() = text.isEmpty()
public fun compareTo(other: WhiteSpace): Int {
fun newLinesCount(w: WhiteSpace) = w.text.count { it == '\n' }
val lineCountDiff = newLinesCount(this) - newLinesCount(other)
if (lineCountDiff != 0) {
return lineCountDiff
}
fun spacesCount(w: WhiteSpace) = w.text.count { it == ' ' }
return spacesCount(this) - spacesCount(other)
}
class object {
public val NewLine: WhiteSpace = WhiteSpace("\n")
}
}
@@ -82,6 +82,10 @@ public open class ElementVisitor(val myConverter: Converter) : JavaElementVisito
}
public override fun visitComment(comment: PsiComment?) {
myResult = Comment(comment?.getText()!!)
myResult = Comment(comment!!.getText()!!)
}
override fun visitWhiteSpace(space: PsiWhiteSpace?) {
myResult = WhiteSpace(space!!.getText()!!)
}
}
@@ -17,7 +17,6 @@
package org.jetbrains.jet.j2k.visitors
import com.intellij.psi.*
import com.intellij.psi.tree.IElementType
import org.jetbrains.jet.j2k.Converter
import org.jetbrains.jet.j2k.ast.*
import org.jetbrains.jet.j2k.countWritingAccesses
@@ -109,16 +108,17 @@ public open class StatementVisitor(converter: Converter) : ElementVisitor(conver
getConverter().convertStatement(body))
}
else {
var forStatements = ArrayList<Element>()
var forStatements = ArrayList<Statement>()
forStatements.add(getConverter().convertStatement(initialization))
val bodyAndUpdate = listOf(getConverter().convertStatement(body),
Block(listOf(getConverter().convertStatement(update))))
forStatements.add(WhileStatement(
if (condition == null)
LiteralExpression("true")
else
getConverter().convertExpression(condition),
Block(arrayListOf(getConverter().convertStatement(body),
Block(arrayListOf(getConverter().convertStatement(update)), false)), false)))
myResult = Block(forStatements, false)
Block(bodyAndUpdate)))
myResult = Block(forStatements)
}
}
@@ -174,21 +174,21 @@ public open class StatementVisitor(converter: Converter) : ElementVisitor(conver
for (ls in cases) {
// TODO assert {(ls?.size()).sure() > 0}
if (ls.size() > 0) {
var label = ls[0]
hasDefaultCase = hasDefaultCase || (label as PsiSwitchLabelStatement).isDefaultCase()
var label = ls[0] as PsiSwitchLabelStatement
hasDefaultCase = hasDefaultCase || label.isDefaultCase()
// TODO assert {(label is PsiSwitchLabelStatement?)}
// TODO assert("not a right index") {allSwitchStatements?.get(i) == label}
if (ls.size() > 1) {
pendingLabels.add(getConverter().convertStatement(label))
val slice: List<PsiElement> = ls.subList(1, (ls.size()))
if (!containsBreak(slice)) {
val statements = ArrayList(getConverter().convertStatements(slice))
statements.addAll(getConverter().convertStatements(getAllToNextBreak(allSwitchStatements, i + ls.size())))
val statements = ArrayList(getConverter().convertStatements(slice).statements)
statements.addAll(getConverter().convertStatements(getAllToNextBreak(allSwitchStatements, i + ls.size())).statements)
result.add(CaseContainer(pendingLabels, statements))
pendingLabels = ArrayList()
}
else {
result.add(CaseContainer(pendingLabels, getConverter().convertStatements(slice)))
result.add(CaseContainer(pendingLabels, getConverter().convertStatements(slice).statements))
pendingLabels = ArrayList()
}
}
@@ -292,4 +292,8 @@ public open class StatementVisitor(converter: Converter) : ElementVisitor(conver
return cases
}
}
override fun visitEmptyStatement(statement: PsiEmptyStatement?) {
myResult = Statement.EMPTY_STATEMENT
}
}
@@ -13,6 +13,7 @@ public class Test(str: String) {
val test = "String2"
sout(test)
sout(dummy(test))
Test(test)
}
{
@@ -13,6 +13,7 @@ public open class Test(str: String) {
var test: String = "String2"
sout(test)
sout(dummy(test))
Test(test)
}
{
@@ -10,6 +10,7 @@ class User() {
val lib = Library()
lib.call()
lib.getString().isEmpty()
Library().call()
Library().getString().isEmpty()
}
@@ -10,6 +10,7 @@ open class User() {
var lib: Library? = Library()
lib?.call()
lib?.getString()?.isEmpty()
Library().call()
Library().getString()?.isEmpty()
}
@@ -18,6 +18,7 @@ class User() {
fun main() {
val m = HashMap(1)
val m2 = HashMap(10)
val t1 = Test.init()
val t2 = Test.init("")
}
+1
View File
@@ -18,6 +18,7 @@ open class User() {
open fun main() {
var m: HashMap<Any?, Any?>? = HashMap(1)
var m2: HashMap<Any?, Any?>? = HashMap(10)
var t1: Test? = Test.init()
var t2: Test? = Test.init("")
}
@@ -6,6 +6,7 @@ class Test() {
fun test() {
val b = 10
putInt(b.toInt())
val b2 = 10
putInt(b2.toInt())
}
@@ -6,6 +6,7 @@ open class Test() {
open fun test() {
var b: Byte = 10
putInt(b.toInt())
var b2: Byte? = 10
putInt(b2?.toInt())
}
@@ -12,12 +12,15 @@ class Test() {
fun test() {
if (One.myContainer.myBoolean)
System.out.println("Ok")
val s = (if (One.myContainer.myBoolean)
"YES"
else
"NO")
while (One.myContainer.myBoolean)
System.out.println("Ok")
do
{
System.out.println("Ok")
+3
View File
@@ -12,12 +12,15 @@ open class Test() {
open fun test() {
if (One.myContainer?.myBoolean!!)
System.out?.println("Ok")
var s: String? = (if (One.myContainer?.myBoolean!!)
"YES"
else
"NO")
while (One.myContainer?.myBoolean!!)
System.out?.println("Ok")
do
{
System.out?.println("Ok")
@@ -8,6 +8,7 @@ class Test() {
System.out.println(true or false)
System.out.println(true xor false)
System.out.println(!true)
System.out.println(true && false)
System.out.println(true || false)
}
+1
View File
@@ -8,6 +8,7 @@ open class Test() {
System.out?.println(true or false)
System.out?.println(true xor false)
System.out?.println(!true)
System.out?.println(true && false)
System.out?.println(true || false)
}
@@ -7,8 +7,10 @@ class Test() {
val s3 = ""
if (s1.isEmpty() && s2.isEmpty())
return "OK"
if (s1.isEmpty() && s2.isEmpty() && s3.isEmpty())
return "OOOK"
return ""
}
}
+2
View File
@@ -7,8 +7,10 @@ open class Test() {
var s3: String? = ""
if (s1?.isEmpty()!! && s2?.isEmpty()!!)
return "OK"
if (s1?.isEmpty()!! && s2?.isEmpty()!! && s3?.isEmpty()!!)
return "OOOK"
return ""
}
}
@@ -4,8 +4,10 @@ class Test() {
fun test() {
val name = "$$$$"
name = name.replaceAll("\\$[0-9]+", "\\$")
val c = '$'
System.out.println(c)
val C = '$'
System.out.println(C)
}
@@ -4,8 +4,10 @@ open class Test() {
open fun test() {
var name: String? = "$$$$"
name = name?.replaceAll("\\$[0-9]+", "\\$")
var c: Char = '$'
System.out?.println(c)
var C: Char? = '$'
System.out?.println(C)
}
@@ -3,6 +3,7 @@ class Test() {
val l1 = 10
val d1 = 10.0
val f1 = 10.0.toFloat()
val l2 = 10
val d2 = 10.0
val f2 = 10.0.toFloat()
@@ -11,6 +12,7 @@ class Test() {
val l1 = 10
val d1 = 10.0
val f1 = 10.0.toFloat()
val l2 = 10
val d2 = 10.0
val f2 = 10.0.toFloat()
@@ -3,6 +3,7 @@ open class Test() {
var l1: Long = 10
var d1: Double = 10.0
var f1: Float = 10.0.toFloat()
var l2: Long = 10
var d2: Double = 10.0
var f2: Float = 10.0.toFloat()
@@ -11,6 +12,7 @@ open class Test() {
var l1: Long? = 10
var d1: Double? = 10.0
var f1: Float? = 10.0.toFloat()
var l2: Long? = 10
var d2: Double? = 10.0
var f2: Float? = 10.0.toFloat()
@@ -2,6 +2,7 @@ class Test() {
fun test() {
val t1 = true
val t2 = true
val f1 = false
val f2 = false
}
@@ -2,6 +2,7 @@ open class Test() {
open fun test() {
var t1: Boolean = true
var t2: Boolean? = true
var f1: Boolean = false
var f2: Boolean? = false
}
@@ -1,6 +1,7 @@
public class NonDefault() {
class object {
public fun main(args: Array<String>) {
val value = 3
val valueString = ""
when (value) {
@@ -1,6 +1,7 @@
public open class NonDefault() {
class object {
public open fun main(args: Array<String?>?) {
var value: Int = 3
var valueString: String? = ""
when (value) {
@@ -3,6 +3,7 @@ package switch_demo
public class SwitchDemo() {
class object {
public fun main(args: Array<String>) {
val month = 8
val monthString: String
when (month) {
+1
View File
@@ -3,6 +3,7 @@ package switch_demo
public open class SwitchDemo() {
class object {
public open fun main(args: Array<String?>?) {
var month: Int = 8
var monthString: String?
when (month) {
@@ -1,6 +1,7 @@
public class NonDefault() {
class object {
public fun main(args: Array<String>) {
val value = 3
val valueString = ""
when (value) {
@@ -1,6 +1,7 @@
public open class NonDefault() {
class object {
public open fun main(args: Array<String?>?) {
var value: Int = 3
var valueString: String? = ""
when (value) {