Remove conditional-preprocessor compiler module

This commit is contained in:
Ilya Gorbunov
2018-04-13 22:25:09 +03:00
parent 2c74b91de4
commit 6b800c4230
11 changed files with 0 additions and 489 deletions
-1
View File
@@ -178,7 +178,6 @@ extra["nativePlatformVariants"] =
extra["compilerModules"] = arrayOf(
":compiler:util",
":compiler:container",
":compiler:conditional-preprocessor",
":compiler:resolution",
":compiler:serialization",
":compiler:psi",
-1
View File
@@ -177,7 +177,6 @@ extra["nativePlatformVariants"] =
extra["compilerModules"] = arrayOf(
":compiler:util",
":compiler:container",
":compiler:conditional-preprocessor",
":compiler:resolution",
":compiler:serialization",
":compiler:psi",
@@ -1,24 +0,0 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
jvmTarget = "1.6"
dependencies {
val compile by configurations
compile(project(":compiler:cli"))
compile(project(":compiler:daemon-common"))
compile(project(":compiler:incremental-compilation-impl"))
compile(project(":kotlin-build-common"))
compile(commonDep("org.fusesource.jansi", "jansi"))
compile(commonDep("org.jline", "jline"))
compileOnly(intellijCoreDep()) { includeJars("intellij-core") }
compileOnly(intellijDep()) { includeIntellijCoreJarDependencies(project) }
}
sourceSets {
"main" { projectDefault() }
"test" {}
}
@@ -1,65 +0,0 @@
/*
* 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.KtAnnotated
import org.jetbrains.kotlin.psi.KtAnnotationEntry
import org.jetbrains.kotlin.psi.KtUserType
interface Conditional {
interface PlatformVersion : 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
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(val version: Int = 5): 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<String, Parser> = listOf<Parser>(JvmVersion, JsVersion, TargetName).associateBy { it.name }
}
}
fun KtAnnotated.parseConditionalAnnotations(): List<Conditional> =
annotationEntries.mapNotNull {
val parser = Conditional.ANNOTATIONS.get(it.typeReferenceName)
parser?.parse?.invoke(it.valueArguments.splitToPositionalAndNamed())
}
val KtAnnotationEntry.typeReferenceName: String? get() =
(typeReference?.typeElement as? KtUserType)?.referencedName
@@ -1,40 +0,0 @@
/*
* 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 : (List<Conditional>) -> Boolean
interface PlatformEvaluator : Evaluator {
override fun invoke(conditions: List<Conditional>): Boolean = evaluate(conditions.filterIsInstance<Conditional.PlatformVersion>())
fun evaluate(conditions: List<Conditional.PlatformVersion>): Boolean
= conditions.isEmpty() || conditions.any { match(it) }
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"
}
@@ -1,72 +0,0 @@
/*
* 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<Evaluator>) : KtTreeVisitorVoid() {
val elementModifications: Map<Evaluator, MutableList<Modification>> =
evaluators.associateBy(keySelector = { it }, valueTransform = { arrayListOf<Modification>() })
override fun visitDeclaration(declaration: KtDeclaration) {
super.visitDeclaration(declaration)
val annotations = declaration.parseConditionalAnnotations()
val name = (declaration as? KtNamedDeclaration)?.nameAsSafeName ?: declaration.name
val declResults = arrayListOf<Pair<Evaluator, Boolean>>()
for ((evaluator, modifications) in elementModifications) {
val conditionalResult = evaluator(annotations)
declResults.add(evaluator to conditionalResult)
if (!conditionalResult)
modifications.add(Modification(declaration.textRange) { rangeText ->
buildString {
append("/* Not available on $evaluator */")
repeat(StringUtil.getLineBreakCount(rangeText)) { append("\n") }
}
})
else {
val targetName = annotations.filterIsInstance<Conditional.TargetName>().singleOrNull()
if (targetName != null) {
val placeholderName = (declaration as KtNamedDeclaration).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<Modification>.applyTo(sourceText: String): String {
return buildString {
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)
}
}
@@ -1,163 +0,0 @@
/*
* 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.io.FileUtil
import com.intellij.openapi.util.text.StringUtil
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.psi.*
import java.io.File
import java.io.IOException
data class Profile(val name: String, val evaluator: Evaluator, val targetRoot: File)
fun createJvmProfile(targetRoot: File, version: Int): Profile = Profile("JVM$version", JvmPlatformEvaluator(version), File(targetRoot, "jvm$version"))
fun createJsProfile(targetRoot: File): Profile = Profile("JS", JsPlatformEvaluator(), File(targetRoot, "js"))
val profileEvaluators: Map<String, () -> Evaluator> =
listOf(6, 7, 8)
.associateBy({ version -> "JVM$version" }, { version -> { JvmPlatformEvaluator(version) } })
.plus<String, () -> PlatformEvaluator>(("JS" to { JsPlatformEvaluator() }))
fun createProfile(name: String, targetRoot: File): Profile {
val (profileName, evaluator) = profileEvaluators.entries.firstOrNull { it.key.equals(name, ignoreCase = true) } ?: throw IllegalArgumentException("Profile with name '$name' is not supported")
return Profile(profileName, evaluator(), targetRoot)
}
class Preprocessor(val logger: Logger = SystemOutLogger) {
val fileType = KotlinFileType.INSTANCE
val jetPsiFactory: KtPsiFactory
init {
val configuration = CompilerConfiguration()
val environment = KotlinCoreEnvironment.createForProduction(Disposable { }, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES)
val project = environment.project
jetPsiFactory = KtPsiFactory(project)
}
sealed class FileProcessingResult {
object Skip : FileProcessingResult()
object Copy : FileProcessingResult()
class Modify(val sourceText: String, val modifications: List<Modification>) : FileProcessingResult() {
fun getModifiedText(): String = modifications.applyTo(sourceText)
override fun toString(): String = "Modify(${modifications.size})"
}
override fun toString() = this::class.java.simpleName
}
fun processSources(sourceRoot: File, profile: Profile) {
processDirectorySingleEvaluator(sourceRoot, profile.targetRoot, profile.evaluator)
}
private fun processFileSingleEvaluator(sourceFile: File, evaluator: Evaluator): FileProcessingResult {
if (sourceFile.extension != fileType.defaultExtension)
return FileProcessingResult.Copy
val sourceText = sourceFile.readText().convertLineSeparators()
val psiFile = jetPsiFactory.createFile(sourceFile.name, sourceText)
val fileAnnotations = psiFile.parseConditionalAnnotations()
if (!evaluator(fileAnnotations))
return FileProcessingResult.Skip
val visitor = CollectModificationsVisitor(listOf(evaluator))
psiFile.accept(visitor)
val list = visitor.elementModifications.values.single()
return if (list.isNotEmpty())
FileProcessingResult.Modify(sourceText, list)
else
FileProcessingResult.Copy
}
private fun processDirectorySingleEvaluator(sourceRoot: File, targetRoot: File, evaluator: Evaluator) {
val (sourceFiles, sourceDirectories) = sourceRoot.listFiles().partition { !it.isDirectory }
val processedFiles = hashSetOf<File>()
for (sourceFile in sourceFiles)
{
val result = processFileSingleEvaluator(sourceFile, evaluator)
logger.debug("$result: $sourceFile")
if (result is FileProcessingResult.Skip) {
continue
}
val targetFile = sourceFile.makeRelativeTo(sourceRoot, targetRoot)
processedFiles += targetFile
if (targetFile.exists() && targetFile.isDirectory)
targetFile.deleteRecursively()
// if no modifications — copy
if (result is FileProcessingResult.Copy) {
FileUtil.copy(sourceFile, targetFile)
} else if (result is FileProcessingResult.Modify) {
val resultText = result.getModifiedText()
if (targetFile.exists() && targetFile.isTextEqualTo(resultText))
continue
logger.info("Rewriting modified $targetFile")
targetFile.parentFile!!.mkdirsOrFail()
targetFile.writeText(resultText)
}
}
for (sourceDir in sourceDirectories) {
val targetDir = sourceDir.makeRelativeTo(sourceRoot, targetRoot)
if (targetDir.exists() && !targetDir.isDirectory) {
targetDir.delete()
}
targetDir.mkdirsOrFail()
processDirectorySingleEvaluator(sourceDir, targetDir, evaluator)
processedFiles += targetDir
}
for (targetFile in targetRoot.listFiles()) {
if (!processedFiles.remove(processedFiles.find { FileUtil.filesEqual(it, targetFile) })) {
logger.info("Deleting skipped $targetFile")
targetFile.deleteRecursively()
}
}
}
}
fun String.convertLineSeparators(): String = StringUtil.convertLineSeparators(this)
fun File.isTextEqualTo(content: String): Boolean = readText().lines() == content.lines()
fun File.makeRelativeTo(from: File, to: File) = File(to, toRelativeString(from))
fun File.mkdirsOrFail() {
if (!mkdirs() && !exists()) {
throw IOException("Failed to create directory $this.")
}
}
@@ -1,36 +0,0 @@
/*
* 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.
*/
@file:JvmName("PreprocessorCLI")
package org.jetbrains.kotlin.preprocessor
import java.io.File
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
fun main(args: Array<String>) {
if (args.size != 3) {
println("Usage: <path to sources> <output path> <profile>")
System.exit(1)
}
val sourcePath = File(args[0])
val targetPath = File(args[1])
val profile = createProfile(args[2], targetPath)
println("Preprocessing sources in $sourcePath to $targetPath with profile ${profile.name}")
Preprocessor().processSources(sourcePath, profile)
}
@@ -1,35 +0,0 @@
/*
* 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.KtStringTemplateEntry
import org.jetbrains.kotlin.psi.ValueArgument
import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
data class PositionalAndNamedArguments(val positional: List<ValueArgument>, val named: List<ValueArgument>)
{
operator fun get(position: Int, name: String): ValueArgument? =
positional.getOrNull(position) ?: named.find { it.getArgumentName()!!.asName.asString() == name }
}
fun List<ValueArgument>.splitToPositionalAndNamed(): PositionalAndNamedArguments {
val (positional, named) = partition { !it.isNamed() }
return PositionalAndNamedArguments(positional, named)
}
fun ValueArgument.parseIntegerValue(): Int = getArgumentExpression()!!.text.toInt()
fun ValueArgument.parseStringValue(): String = getArgumentExpression()!!.getChildrenOfType<KtStringTemplateEntry>().joinToString("") { it.text }
@@ -1,51 +0,0 @@
/*
* 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 Logger {
fun debug(msg: CharSequence)
fun info(msg: CharSequence)
fun warn(msg: CharSequence)
fun error(msg: CharSequence)
}
object SystemOutLogger : Logger {
private fun out(level: String, msg: CharSequence) = println("[$level] $msg")
var isDebugEnabled: Boolean = true
override fun debug(msg: CharSequence) {
if (isDebugEnabled) out("DEBUG", msg)
}
override fun info(msg: CharSequence) = out("INFO", msg)
override fun warn(msg: CharSequence) = out("WARN", msg)
override fun error(msg: CharSequence) = out("ERROR", msg)
}
fun Logger.withPrefix(prefix: String): Logger = PrefixedLogger(prefix, this)
class PrefixedLogger(val prefix: String, val logger: Logger) : Logger {
private fun prefix(msg: CharSequence): CharSequence = StringBuilder().apply {
append(prefix)
append(": ")
append(msg)
}
override fun debug(msg: CharSequence) = logger.debug(prefix(msg))
override fun info(msg: CharSequence) = logger.info(prefix(msg))
override fun warn(msg: CharSequence) = logger.warn(prefix(msg))
override fun error(msg: CharSequence) = logger.error(prefix(msg))
}
-1
View File
@@ -20,7 +20,6 @@ include ":kotlin-build-common",
":kotlin-preloader",
":kotlin-runner",
":compiler:container",
":compiler:conditional-preprocessor",
":compiler:resolution",
":compiler:serialization",
":compiler:psi",