diff --git a/.idea/modules.xml b/.idea/modules.xml
index 57d3de81d84..eb77c89fb96 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -19,6 +19,7 @@
+
diff --git a/compiler/conditional-preprocessor/conditional-preprocessor.iml b/compiler/conditional-preprocessor/conditional-preprocessor.iml
new file mode 100644
index 00000000000..07111c35a27
--- /dev/null
+++ b/compiler/conditional-preprocessor/conditional-preprocessor.iml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/Conditional.kt b/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/Conditional.kt
new file mode 100644
index 00000000000..ba0bb38e624
--- /dev/null
+++ b/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/Conditional.kt
@@ -0,0 +1,61 @@
+/*
+ * 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 org.jetbrains.kotlin.psi.*
+import org.jetbrains.kotlin.psi.psiUtil.getChildOfType
+
+interface Conditional {
+
+ interface PlatformVersion : Conditional
+
+ abstract class Parser(val name: String, val parse: (arguments: SplitArguments) -> Conditional)
+
+ data class JvmVersion(val minimum: Int, val maximum: Int): PlatformVersion {
+ val versionRange: IntRange = minimum..maximum
+ companion object : Parser("JvmVersion", parse = { arguments ->
+ val minimum = arguments[0, "minimum"]?.parseIntegerValue()
+ val maximum = arguments[1, "maximum"]?.parseIntegerValue()
+
+ JvmVersion(minimum ?: 6, maximum ?: 100)
+ })
+ }
+
+ data class JsVersion(): PlatformVersion {
+ companion object : Parser("JsVersion", parse = { JsVersion() })
+ }
+
+ data class TargetName(val name: String): Conditional {
+ companion object : Parser("RenameOnTargetPlatform", parse = { arguments ->
+ val name = arguments[0, "name"]!!.parseStringValue()
+ TargetName(name)
+ })
+ }
+
+
+ companion object {
+ val ANNOTATIONS: Map = listOf(JvmVersion, JsVersion, TargetName).toMap { it.name }
+ }
+}
+
+fun JetAnnotated.parseConditionalAnnotations(): List =
+ annotationEntries.map {
+ val parser = Conditional.ANNOTATIONS.get(it.typeReferenceName)
+ parser?.parse?.invoke(it.valueArguments.splitToPositionalAndNamed())
+ }.filterNotNull()
+
+
diff --git a/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/Evaluator.kt b/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/Evaluator.kt
new file mode 100644
index 00000000000..766612e7853
--- /dev/null
+++ b/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/Evaluator.kt
@@ -0,0 +1,40 @@
+/*
+ * 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
+
+interface Evaluator : Function1, Boolean>
+
+abstract class PlatformEvaluator : Evaluator {
+ final override fun invoke(conditions: List): Boolean = evaluate(conditions.filterIsInstance())
+
+ open fun evaluate(conditions: List): Boolean
+ = conditions.isEmpty() || conditions.any { match(it) }
+
+ abstract fun match(platformCondition: Conditional.PlatformVersion): Boolean
+}
+
+data class JvmPlatformEvaluator(val version: Int): PlatformEvaluator() {
+ override fun match(platformCondition: Conditional.PlatformVersion)
+ = platformCondition is Conditional.JvmVersion && version in platformCondition.versionRange
+ override fun toString() = "platform: JVM$version"
+}
+
+data class JsPlatformEvaluator(val ecmaScriptVersion: Int = 5): PlatformEvaluator() {
+ override fun match(platformCondition: Conditional.PlatformVersion)
+ = platformCondition is Conditional.JsVersion
+ override fun toString() = "platform: JS"
+}
\ 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
new file mode 100644
index 00000000000..f7d6809913f
--- /dev/null
+++ b/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/Preprocessor.kt
@@ -0,0 +1,114 @@
+/*
+ * 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.Disposable
+import com.intellij.openapi.util.TextRange
+import com.intellij.openapi.util.text.StringUtil
+import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
+import org.jetbrains.kotlin.config.CompilerConfiguration
+import org.jetbrains.kotlin.idea.JetFileType
+import org.jetbrains.kotlin.psi.*
+import java.io.File
+
+
+fun main(args: Array) {
+ require(args.size() == 1, "Please specify path to sources")
+
+ val sourcePath = File(args.first())
+
+ val configuration = CompilerConfiguration()
+ val environment = KotlinCoreEnvironment.createForProduction(Disposable { }, configuration, emptyList())
+
+ val project = environment.project
+ val jetPsiFactory = JetPsiFactory(project)
+ val fileType = JetFileType.INSTANCE
+
+ val evaluator = JvmPlatformEvaluator(version = 7)
+ //val evaluator = JsPlatformEvaluator()
+
+
+ println("Using condition evaluator: $evaluator")
+
+ (FileTreeWalk(sourcePath) as Sequence)
+ .filter { it.isFile && it.extension == fileType.defaultExtension }
+ .forEach { sourceFile ->
+ val sourceText = sourceFile.readText().convertLineSeparators()
+ val psiFile = jetPsiFactory.createFile(sourceFile.name, sourceText)
+ println("$psiFile")
+
+ val visitor = EvaluatorVisitor(evaluator)
+ psiFile.accept(visitor)
+
+ var prevIndex = 0
+ val resultText = StringBuilder()
+ for ((range, selector) in visitor.elementModifications) {
+ resultText.append(sourceText, prevIndex, range.startOffset)
+ val rangeText = range.substring(sourceText)
+ val newValue = selector(rangeText)
+ if (newValue.isEmpty()) {
+ resultText.append("/* Not available on ${visitor.evaluator} */")
+ repeat(StringUtil.getLineBreakCount(rangeText)) {
+ resultText.append("\n")
+ }
+ }
+ else {
+ resultText.append(newValue)
+ }
+ prevIndex = range.endOffset
+ }
+ resultText.append(sourceText, prevIndex, sourceText.length())
+
+ println(resultText.toString())
+ //processDeclaration("/", psiFile, evaluator)
+ }
+}
+
+
+class EvaluatorVisitor(val evaluator: Evaluator) : JetTreeVisitorVoid() {
+
+ val elementModifications: MutableList String>> = arrayListOf()
+
+
+ override fun visitDeclaration(declaration: JetDeclaration) {
+ super.visitDeclaration(declaration)
+
+ val annotations = declaration.parseConditionalAnnotations()
+ val name = (declaration as? JetNamedDeclaration)?.nameAsSafeName ?: declaration.name
+ val conditionalResult = evaluator(annotations)
+ println("declaration: ${declaration.javaClass.simpleName} $name, annotations: ${annotations.joinToString { it.toString() }}, evaluation result: $conditionalResult")
+ if (!conditionalResult)
+ elementModifications.add(declaration.textRange to {it -> ""})
+ else {
+ val targetName = annotations.filterIsInstance().singleOrNull()
+ if (targetName != null) {
+ val placeholderName = (declaration as JetNamedDeclaration).nameAsName!!.asString()
+ val realName = targetName.name
+ elementModifications.add(declaration.textRange to { it -> it.replace(placeholderName, realName) })
+ }
+ }
+ }
+}
+
+
+val JetAnnotationEntry.typeReferenceName: String? get() =
+ (typeReference?.typeElement as? JetUserType)?.referencedName
+
+fun String.convertLineSeparators(): String = StringUtil.convertLineSeparators(this)
+
+
+
diff --git a/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/SplitArguments.kt b/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/SplitArguments.kt
new file mode 100644
index 00000000000..031df9f3339
--- /dev/null
+++ b/compiler/conditional-preprocessor/src/org.jetbrains.kotlin.preprocessor/SplitArguments.kt
@@ -0,0 +1,36 @@
+/*
+ * 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 org.jetbrains.kotlin.psi.JetStringTemplateEntry
+import org.jetbrains.kotlin.psi.ValueArgument
+import org.jetbrains.kotlin.psi.psiUtil.getChildOfType
+import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
+
+data class SplitArguments(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 {
+ val (positional, named) = partition { !it.isNamed() }
+ return SplitArguments(positional, named)
+}
+
+fun ValueArgument.parseIntegerValue(): Int = getArgumentExpression()!!.text.toInt()
+fun ValueArgument.parseStringValue(): String = getArgumentExpression()!!.getChildrenOfType().joinToString("") { it.text }
\ No newline at end of file