diff --git a/libraries/tools/kotlin-stdlib-gen/build.gradle b/libraries/tools/kotlin-stdlib-gen/build.gradle index d83a1a20da1..7d2e97900b6 100644 --- a/libraries/tools/kotlin-stdlib-gen/build.gradle +++ b/libraries/tools/kotlin-stdlib-gen/build.gradle @@ -6,6 +6,7 @@ sourceSets { dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib:$bootstrapKotlinVersion" + compile "org.jetbrains.kotlin:kotlin-reflect:$bootstrapKotlinVersion" } compileKotlin { diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/CommonTypes.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/CommonTypes.kt index b3c3d4d63c1..353ac6152a0 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/CommonTypes.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/CommonTypes.kt @@ -83,7 +83,14 @@ enum class Inline { enum class Platform { Common, JVM, - JS + JS, + Native; + + val fullName get() = "Kotlin/$name" + + companion object { + val values = values().toList() + } } enum class SequenceClass { diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/MemberBuilder.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/MemberBuilder.kt index ab40e45cccd..419dcdb237e 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/MemberBuilder.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/MemberBuilder.kt @@ -62,8 +62,8 @@ class MemberBuilder( var operator: Boolean = false; private set val typeParams = mutableListOf() var customReceiver: String? = null; private set - var receiverAsterisk: Boolean = false; private set - var toNullableT: Boolean = false; private set + var receiverAsterisk: Boolean = false // TODO: rename to genericStarProjection + var toNullableT: Boolean = false var returns: String? = null; private set var body: String? = null; private set @@ -72,8 +72,8 @@ class MemberBuilder( fun sourceFile(file: SourceFile) { sourceFile = file } fun deprecate(value: Deprecation) { deprecate = value } - fun deprecate(value: String) { deprecate = Deprecation(value) - } + fun deprecate(value: String) { deprecate = Deprecation(value) } + fun since(value: String) { since = value } fun platformName(name: String) { platformName = name } fun visibility(value: String) { visibility = value } @@ -87,10 +87,11 @@ class MemberBuilder( annotation("""@Suppress("NOTHING_TO_INLINE")""") } } - fun inlineOnly() { inline = Inline.Only - } + fun inlineOnly() { inline = Inline.Only } fun receiver(value: String) { customReceiver = value } + @Deprecated("Use receiver()", ReplaceWith("receiver(value)")) + fun customReceiver(value: String) = receiver(value) fun signature(value: String) { signature = value } fun returns(type: String) { returns = type } @@ -113,6 +114,12 @@ class MemberBuilder( fun body(valueBuilder: () -> String) { body = valueBuilder() } + fun body(f: Family, valueBuilder: () -> String) { + specialFor(f) { body(valueBuilder) } + } + fun body(vararg families: Family, valueBuilder: () -> String) { + specialFor(*families) { body(valueBuilder) } + } fun on(platform: Platform, action: () -> Unit) { @@ -128,6 +135,11 @@ class MemberBuilder( if (family == f) action() } + fun specialFor(vararg families: Family, action: () -> Unit) { + require(families.isNotEmpty()) + if (family in families) + action() + } fun build(builder: Appendable) { @@ -296,8 +308,8 @@ class MemberBuilder( listOfNotNull( visibility ?: "public", - "header".takeIf { headerOnly }, - "impl".takeIf { isImpl }, + "expect".takeIf { headerOnly }, + "actual".takeIf { isImpl }, "external".takeIf { external }, "inline".takeIf { inline.isInline() }, "infix".takeIf { infix }, @@ -325,7 +337,7 @@ class MemberBuilder( val body = (body ?: deprecate?.replaceWith?.let { "return $it" } ?: - throw RuntimeException("No body specified for $signature for ${family to primitive}") + throw RuntimeException("$signature for ${platform.fullName}: no body specified for ${family to primitive}") ).trim('\n') val indent: Int = body.takeWhile { it == ' ' }.length diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/TemplateGroups.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/TemplateGroups.kt new file mode 100644 index 00000000000..06ebb069643 --- /dev/null +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/TemplateGroups.kt @@ -0,0 +1,61 @@ +/* + * Copyright 2010-2017 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 templates + +import kotlin.coroutines.experimental.buildSequence +import kotlin.reflect.KTypeProjection +import kotlin.reflect.full.createType +import kotlin.reflect.full.isSubtypeOf + + +typealias TemplateGroup = () -> Sequence + +fun templateGroupOf(vararg templates: MemberTemplate): TemplateGroup = { templates.asSequence() } + +abstract class TemplateGroupBase : TemplateGroup { + + override fun invoke(): Sequence = buildSequence { + with(this@TemplateGroupBase) { + this::class.members.filter { it.name.startsWith("f_") }.forEach { + require(it.parameters.size == 1) { "Member $it violates naming convention" } + when { + it.returnType.isSubtypeOf(typeMemberTemplate) -> + yield(it.call(this) as MemberTemplate) + it.returnType.isSubtypeOf(typeIterableOfMemberTemplates) -> + @Suppress("UNCHECKED_CAST") + yieldAll(it.call(this) as Iterable) + else -> + error("Member $it violates naming convention") + } + } + } + }.run { + if (defaultActions.isEmpty()) this else onEach { t -> defaultActions.forEach(t::builder) } + } + + private val defaultActions = mutableListOf() + + fun defaultBuilder(builderAction: MemberBuildAction) { + defaultActions += builderAction + } + + companion object { + private val typeMemberTemplate = MemberTemplate::class.createType() + private val typeIterableOfMemberTemplates = Iterable::class.createType(arguments = listOf(KTypeProjection.invariant(typeMemberTemplate))) + } + +} \ No newline at end of file diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/Templates.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/Templates.kt index 54355222bcf..ca7c76f9ec3 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/Templates.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/Templates.kt @@ -16,7 +16,7 @@ package templates -import kotlin.coroutines.experimental.buildSequence +import kotlin.coroutines.experimental.* @DslMarker annotation class TemplateDsl @@ -37,26 +37,26 @@ private fun def(signature: String, memberKind: Keyword): MemberBuildAction = { fun fn(defaultSignature: String): MemberBuildAction = def(defaultSignature, Keyword.Function) -fun fn(defaultSignature: String, setup: FamilyPrimitiveMemberDsl.() -> Unit): MemberTemplate = - FamilyPrimitiveMemberDsl().apply { +fun fn(defaultSignature: String, setup: FamilyPrimitiveMemberDefinition.() -> Unit): FamilyPrimitiveMemberDefinition = + FamilyPrimitiveMemberDefinition().apply { builder(fn(defaultSignature)) setup() } -fun MemberBuildAction.byTwoPrimitives(setup: PairPrimitiveMemberDsl.() -> Unit): MemberTemplate = - PairPrimitiveMemberDsl().apply { +fun MemberBuildAction.byTwoPrimitives(setup: PairPrimitiveMemberDefinition.() -> Unit): PairPrimitiveMemberDefinition = + PairPrimitiveMemberDefinition().apply { builder(this@byTwoPrimitives) setup() } -fun pval(name: String, setup: FamilyPrimitiveMemberDsl.() -> Unit): MemberTemplate = - FamilyPrimitiveMemberDsl().apply { +fun pval(name: String, setup: FamilyPrimitiveMemberDefinition.() -> Unit): FamilyPrimitiveMemberDefinition = + FamilyPrimitiveMemberDefinition().apply { builder(def(name, Keyword.Value)) setup() } -fun pvar(name: String, setup: FamilyPrimitiveMemberDsl.() -> Unit): MemberTemplate = - FamilyPrimitiveMemberDsl().apply { +fun pvar(name: String, setup: FamilyPrimitiveMemberDefinition.() -> Unit): FamilyPrimitiveMemberDefinition = + FamilyPrimitiveMemberDefinition().apply { builder(def(name, Keyword.Variable)) setup() } @@ -66,14 +66,16 @@ interface MemberTemplate { /** Specifies which platforms this member template should be generated for */ fun platforms(vararg platforms: Platform) - fun instantiate(): Sequence + fun instantiate(platforms: List = Platform.values): Sequence /** Registers parameterless member builder function */ fun builder(b: MemberBuildAction) - } -abstract class GenericMemberDsl : MemberTemplate { +infix fun MT.builder(b: MemberBuildAction): MT = apply { builder(b) } +infix fun > MT.builderWith(b: MemberBuildActionP): MT = apply { builderWith(b) } + +abstract class MemberTemplateDefinition : MemberTemplate { sealed class BuildAction { class Generic(val action: MemberBuildAction) : BuildAction() { @@ -87,7 +89,7 @@ abstract class GenericMemberDsl : MemberTemplate { } } - val buildActions = mutableListOf() + private val buildActions = mutableListOf() private var targetPlatforms = setOf(*Platform.values()) override fun platforms(vararg platforms: Platform) { @@ -116,13 +118,15 @@ abstract class GenericMemberDsl : MemberTemplate { } ?: this - override fun instantiate(): Sequence { - val specificPlatforms by lazy { targetPlatforms - Platform.Common } + override fun instantiate(platforms: List): Sequence { + val resultingPlatforms = platforms.intersect(targetPlatforms) + val specificPlatforms by lazy { resultingPlatforms - Platform.Common } fun platformMemberBuilders(family: Family, p: TParam) = if (Platform.Common in targetPlatforms) { val commonMemberBuilder = createMemberBuilder(Platform.Common, family, p) - mutableListOf(commonMemberBuilder).also { builders -> + mutableListOf().also { builders -> + if (Platform.Common in resultingPlatforms) builders.add(commonMemberBuilder) if (commonMemberBuilder.hasPlatformSpecializations) { specificPlatforms.mapTo(builders) { createMemberBuilder(it, family, p) @@ -130,7 +134,7 @@ abstract class GenericMemberDsl : MemberTemplate { } } } else { - targetPlatforms.map { createMemberBuilder(it, family, p) } + resultingPlatforms.map { createMemberBuilder(it, family, p) } } return parametrize() @@ -152,17 +156,20 @@ abstract class GenericMemberDsl : MemberTemplate { } + private fun defaultPrimitives(f: Family): Set = if (f.isPrimitiveSpecialization) PrimitiveType.defaultPrimitives else emptySet() @TemplateDsl -class FamilyPrimitiveMemberDsl : GenericMemberDsl() { +class FamilyPrimitiveMemberDefinition : MemberTemplateDefinition() { - private val familyPrimitives = mutableMapOf>() + private val familyPrimitives = mutableMapOf>() fun include(vararg fs: Family) { for (f in fs) familyPrimitives[f] = defaultPrimitives(f) } + @Deprecated("Use include()", ReplaceWith("include(*fs)")) + fun only(vararg fs: Family) = include(*fs) fun include(fs: Collection) { for (f in fs) familyPrimitives[f] = defaultPrimitives(f) @@ -172,7 +179,7 @@ class FamilyPrimitiveMemberDsl : GenericMemberDsl() { include(Family.defaultFamilies) } - fun include(f: Family, primitives: Set) { + fun include(f: Family, primitives: Set) { familyPrimitives[f] = primitives } @@ -198,7 +205,7 @@ class FamilyPrimitiveMemberDsl : GenericMemberDsl() { } @TemplateDsl -class PairPrimitiveMemberDsl : GenericMemberDsl>() { +class PairPrimitiveMemberDefinition : MemberTemplateDefinition>() { private val familyPrimitives = mutableMapOf>>() @@ -217,77 +224,9 @@ class PairPrimitiveMemberDsl : GenericMemberDsl().apply { - parametrization = buildSequence { - val allPlatforms = setOf(*Platform.values()) - yield(DefaultParametrization(InvariantArraysOfObjects, platforms = allPlatforms)) - yieldAll(PrimitiveType.defaultPrimitives.map { DefaultParametrization(ArraysOfPrimitives, it, platforms = allPlatforms) }) - } - builder = { p, platform, builder -> - builder.family = if (p.family == InvariantArraysOfObjects && platform == Platform.JS) - ArraysOfObjects else p.family - - if (platform == Platform.JVM) - builder.inline = Inline.Only - - builder.doc = "Returns new array which is a copy of the original array." - builder.returns = "SELF" - if (platform == Platform.JS && p.family == ArraysOfObjects) - builder.returns = "Array" - - if (platform == Platform.JVM) { - builder.body = "return java.util.Arrays.copyOf(this, size)" - } else if (platform == Platform.JS) { - when (p.primitive) { - null -> - builder.body = "return this.asDynamic().slice()" - PrimitiveType.Char, PrimitiveType.Boolean, PrimitiveType.Long -> - builder.body = "return withType(\"${p.primitive}Array\", this.asDynamic().slice())" - else -> { - builder.annotations += """@Suppress("NOTHING_TO_INLINE")""" - builder.inline = Inline.Yes - builder.body = "return this.asDynamic().slice()" - } - } - } - - - } -} -interface MemberTemplate { - - fun instantiate(): Sequence -} - -class MemberTemplatePar : MemberTemplate { - - val keyword: String = "fun" - - lateinit var parametrization: Sequence - lateinit var builder: (TParametrization, Platform, MemberBuilder) -> Unit - - override fun instantiate(): Sequence = - parametrization.flatMap { - it.platforms.asSequence().map { p -> - val memberBuilder = MemberBuilder().apply { - builder(it, p, this) - } - MemberInstance(memberBuilder::build, PlatformSourceFile(p, memberBuilder.sourceFile)) - } - } - -} +Replacement pattern: + templates add f\(\"(\w+)(\(.*) + val f_$1 = fn("$1$2 */ - - -/* - -class MemberInstance( - val textBuilder: (Appendable) -> Unit, - val platformSourceFile: PlatformSourceFile) -*/ - - diff --git a/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/Writers.kt b/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/Writers.kt index 89a53452ed9..c97a6e56218 100644 --- a/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/Writers.kt +++ b/libraries/tools/kotlin-stdlib-gen/src/templates/dsl/Writers.kt @@ -28,7 +28,7 @@ data class PlatformSourceFile( fun Sequence.groupByFileAndWrite( fileNameBuilder: (PlatformSourceFile) -> File ) { - val groupedMembers = map { it.instantiate() }.flatten().groupBy { + val groupedMembers = map { it.instantiate(Platform.values - Platform.Native) }.flatten().groupBy { PlatformSourceFile(it.platform, it.sourceFile) }