diff --git a/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/Conditional.kt b/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/Conditional.kt index d0af9a3bd9e..ae2fdea4568 100644 --- a/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/Conditional.kt +++ b/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/Conditional.kt @@ -22,7 +22,7 @@ interface Conditional { interface PlatformVersion : Conditional - abstract class Parser(val name: String, val parse: (arguments: SplitArguments) -> Conditional) + abstract class Parser(val name: String, val parse: (arguments: PositionalAndNamedArguments) -> Conditional) data class JvmVersion(val minimum: Int, val maximum: Int): PlatformVersion { val versionRange: IntRange = minimum..maximum diff --git a/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/Modifications.kt b/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/Modifications.kt new file mode 100644 index 00000000000..fe29fa1a4da --- /dev/null +++ b/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/Modifications.kt @@ -0,0 +1,72 @@ +/* + * Copyright 2010-2015 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.preprocessor + +import com.intellij.openapi.util.TextRange +import com.intellij.openapi.util.text.StringUtil +import org.jetbrains.kotlin.psi.* + +data class Modification(val range: TextRange, val apply: (String) -> String) + +class CollectModificationsVisitor(evaluators: List) : JetTreeVisitorVoid() { + + val elementModifications: Map> = + evaluators.toMap(selector = { it }, transform = { arrayListOf() }) + + override fun visitDeclaration(declaration: JetDeclaration) { + super.visitDeclaration(declaration) + + val annotations = declaration.parseConditionalAnnotations() + val name = (declaration as? JetNamedDeclaration)?.nameAsSafeName ?: declaration.name + + val declResults = arrayListOf>() + for ((evaluator, modifications) in elementModifications) { + val conditionalResult = evaluator(annotations) + declResults.add(evaluator to conditionalResult) + + if (!conditionalResult) + modifications.add(Modification(declaration.textRange) { rangeText -> + StringBuilder { + append("/* Not available on $evaluator */") + repeat(StringUtil.getLineBreakCount(rangeText)) { append("\n") } + }.toString() + }) + else { + val targetName = annotations.filterIsInstance().singleOrNull() + if (targetName != null) { + val placeholderName = (declaration as JetNamedDeclaration).nameAsName!!.asString() + val realName = targetName.name + modifications.add(Modification(declaration.textRange) { it.replace(placeholderName, realName) }) + } + } + + } + //println("declaration: ${declaration.javaClass.simpleName} $name${if (annotations.isNotEmpty()) ", annotations: ${annotations.joinToString { it.toString() }}, evaluation result: $declResults" else ""}") + } +} + +fun List.applyTo(sourceText: String): String { + return StringBuilder { + var prevIndex = 0 + for ((range, transform) in this@applyTo) { + append(sourceText, prevIndex, range.startOffset) + append(transform(range.substring(sourceText))) + prevIndex = range.endOffset + } + append(sourceText, prevIndex, sourceText.length()) + }.toString() +} \ No newline at end of file diff --git a/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/Preprocessor.kt b/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/Preprocessor.kt index f6f674042af..d17ff1363b5 100644 --- a/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/Preprocessor.kt +++ b/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/Preprocessor.kt @@ -26,66 +26,8 @@ import org.jetbrains.kotlin.idea.JetFileType import org.jetbrains.kotlin.psi.* import java.io.File import java.io.IOException -import java.util.concurrent.Executors -import java.util.concurrent.TimeUnit -fun main(args: Array) { - require(args.size() == 1, "Please specify path to sources") - - val sourcePath = File(args.first()) - -// val evaluators = listOf(JvmPlatformEvaluator(version = 7), JsPlatformEvaluator()) - - //println("Using condition evaluator: $evaluators") - - val targetPath = File("libraries/stdlib/target") - - - val profiles = listOf(6, 7, 8).map { Preprocessor(createJvmProfile(targetPath, version = it)) } - - val pool = Executors.newFixedThreadPool(4) - - profiles.forEach { pool.submit { it.processSources(sourcePath) } } - - pool.shutdown() - pool.awaitTermination(1, TimeUnit.MINUTES) -} - - -data class Modification(val range: TextRange, val selector: (String) -> String) - -class CollectModificationsVisitor(evaluators: List) : JetTreeVisitorVoid() { - - val elementModifications: Map> = - evaluators.toMap(selector = { it }, transform = { arrayListOf() }) - - override fun visitDeclaration(declaration: JetDeclaration) { - super.visitDeclaration(declaration) - - val annotations = declaration.parseConditionalAnnotations() - val name = (declaration as? JetNamedDeclaration)?.nameAsSafeName ?: declaration.name - - val declResults = arrayListOf>() - for ((evaluator, modifications) in elementModifications) { - val conditionalResult = evaluator(annotations) - declResults.add(evaluator to conditionalResult) - - if (!conditionalResult) - modifications.add(Modification(declaration.textRange) {""}) - else { - val targetName = annotations.filterIsInstance().singleOrNull() - if (targetName != null) { - val placeholderName = (declaration as JetNamedDeclaration).nameAsName!!.asString() - val realName = targetName.name - modifications.add(Modification(declaration.textRange) { it.replace(placeholderName, realName) }) - } - } - - } - //println("declaration: ${declaration.javaClass.simpleName} $name${if (annotations.isNotEmpty()) ", annotations: ${annotations.joinToString { it.toString() }}, evaluation result: $declResults" else ""}") - } -} data class Profile(val name: String, val evaluator: Evaluator, val targetRoot: File) @@ -111,7 +53,9 @@ public class Preprocessor(val profile: Profile) { object Skip : FileProcessingResult() object Copy : FileProcessingResult() - class Modify(val sourceText: String, val modifications: List) : FileProcessingResult() + class Modify(val sourceText: String, val modifications: List) : FileProcessingResult() { + fun getModifiedText(): String = modifications.applyTo(sourceText) + } } public fun processSources(sourceRoot: File) { @@ -162,7 +106,7 @@ public class Preprocessor(val profile: Profile) { if (result is FileProcessingResult.Copy) { FileUtil.copy(sourceFile, destFile) } else if (result is FileProcessingResult.Modify) { - val resultText = applyModifications(result.modifications, result.sourceText, evaluator) + val resultText = result.getModifiedText() if (destFile.exists() && destFile.isTextEqualTo(resultText)) continue destFile.writeText(resultText) @@ -228,27 +172,6 @@ public class Preprocessor(val profile: Profile) { } - private fun applyModifications(modifications: List, sourceText: String, evaluator: Evaluator): String { - var prevIndex = 0 - val result = StringBuilder() - for ((range, selector) in modifications) { - result.append(sourceText, prevIndex, range.startOffset) - val rangeText = range.substring(sourceText) - val newValue = selector(rangeText) - if (newValue.isEmpty()) { - result.append("/* Not available on $evaluator */") - repeat(StringUtil.getLineBreakCount(rangeText)) { - result.append("\n") - } - } - else { - result.append(newValue) - } - prevIndex = range.endOffset - } - result.append(sourceText, prevIndex, sourceText.length()) - return result.toString() - } } diff --git a/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/SplitArguments.kt b/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/ValueArguments.kt similarity index 83% rename from compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/SplitArguments.kt rename to compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/ValueArguments.kt index f6ad2614b49..62905e30ad6 100644 --- a/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/SplitArguments.kt +++ b/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/ValueArguments.kt @@ -20,15 +20,15 @@ import org.jetbrains.kotlin.psi.JetStringTemplateEntry import org.jetbrains.kotlin.psi.ValueArgument import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType -data class SplitArguments(val positional: List, val named: List) +data class PositionalAndNamedArguments(val positional: List, val named: List) { fun get(position: Int, name: String): ValueArgument? = positional.getOrNull(position) ?: named.find { it.getArgumentName()!!.asName.asString() == name } } -fun List.splitToPositionalAndNamed(): SplitArguments { +fun List.splitToPositionalAndNamed(): PositionalAndNamedArguments { val (positional, named) = partition { !it.isNamed() } - return SplitArguments(positional, named) + return PositionalAndNamedArguments(positional, named) } fun ValueArgument.parseIntegerValue(): Int = getArgumentExpression()!!.text.toInt() diff --git a/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/cli.kt b/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/cli.kt new file mode 100644 index 00000000000..8383585c379 --- /dev/null +++ b/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/cli.kt @@ -0,0 +1,39 @@ +/* + * Copyright 2010-2015 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.preprocessor + +import java.io.File +import java.util.concurrent.Executors +import java.util.concurrent.TimeUnit + +fun main(args: Array) { + require(args.size() == 1, "Please specify path to sources") + + val sourcePath = File(args.first()) + + val targetPath = File("libraries/stdlib/target") + + + val profiles = listOf(6, 7, 8).map { Preprocessor(createJvmProfile(targetPath, version = it)) } + + val pool = Executors.newCachedThreadPool() + + profiles.forEach { pool.submit { it.processSources(sourcePath) } } + + pool.shutdown() + pool.awaitTermination(1, TimeUnit.MINUTES) +}