Prototyping preprocessor: stripping declarations and replacing name.
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="kotlin-runtime" level="project" />
|
||||
<orderEntry type="module" module-name="cli" />
|
||||
<orderEntry type="library" name="intellij-core" level="project" />
|
||||
<orderEntry type="module" module-name="frontend" />
|
||||
</component>
|
||||
</module>
|
||||
+61
@@ -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<String, Parser> = listOf<Parser>(JvmVersion, JsVersion, TargetName).toMap { it.name }
|
||||
}
|
||||
}
|
||||
|
||||
fun JetAnnotated.parseConditionalAnnotations(): List<Conditional> =
|
||||
annotationEntries.map {
|
||||
val parser = Conditional.ANNOTATIONS.get(it.typeReferenceName)
|
||||
parser?.parse?.invoke(it.valueArguments.splitToPositionalAndNamed())
|
||||
}.filterNotNull()
|
||||
|
||||
|
||||
@@ -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<List<Conditional>, Boolean>
|
||||
|
||||
abstract class PlatformEvaluator : Evaluator {
|
||||
final override fun invoke(conditions: List<Conditional>): Boolean = evaluate(conditions.filterIsInstance())
|
||||
|
||||
open fun evaluate(conditions: List<Conditional.PlatformVersion>): 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"
|
||||
}
|
||||
+114
@@ -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<String>) {
|
||||
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<File>)
|
||||
.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<Pair<TextRange, (String) -> 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<Conditional.TargetName>().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)
|
||||
|
||||
|
||||
|
||||
+36
@@ -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<ValueArgument>, val named: List<ValueArgument>)
|
||||
{
|
||||
fun get(position: Int, name: String): ValueArgument? =
|
||||
positional.getOrNull(position) ?: named.find { it.getArgumentName()!!.asName.asString() == name }
|
||||
}
|
||||
|
||||
fun List<ValueArgument>.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<JetStringTemplateEntry>().joinToString("") { it.text }
|
||||
Reference in New Issue
Block a user