diff --git a/libraries/tools/idl2k/src/main/kotlin/gen.kt b/libraries/tools/idl2k/src/main/kotlin/gen.kt index eb0e7fb320c..caff0f75737 100644 --- a/libraries/tools/idl2k/src/main/kotlin/gen.kt +++ b/libraries/tools/idl2k/src/main/kotlin/gen.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2010-2016 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.idl2k private fun Operation.getterOrSetter() = this.attributes.map { it.call }.toSet().let { attributes -> @@ -9,7 +25,7 @@ private fun Operation.getterOrSetter() = this.attributes.map { it.call }.toSet() } fun generateFunction(repository: Repository, function: Operation, functionName: String, nativeGetterOrSetter: NativeGetterOrSetter = function.getterOrSetter()): GenerateFunction = - function.attributes.map { it.call }.toSet().let { attributes -> + function.attributes.map { it.call }.toSet().let { GenerateFunction( name = functionName, returnType = mapType(repository, function.returnType).let { mapped -> if (nativeGetterOrSetter == NativeGetterOrSetter.GETTER) mapped.toNullableIfNonPrimitive() else mapped }, @@ -19,7 +35,7 @@ fun generateFunction(repository: Repository, function: Operation, functionName: GenerateAttribute( name = it.name, type = mappedType, - initializer = mapLiteral(it.defaultValue, mappedType), + initializer = if (it.defaultValue != null) "noImpl" else null, getterSetterNoImpl = false, override = false, kind = AttributeKind.ARGUMENT, @@ -28,7 +44,8 @@ fun generateFunction(repository: Repository, function: Operation, functionName: ) }, nativeGetterOrSetter = nativeGetterOrSetter, - static = function.static + static = function.static, + override = false ) } @@ -69,7 +86,16 @@ fun generateFunctions(repository: Repository, function: Operation): List "arrayOf()" } else -> literal -} \ No newline at end of file +} + +fun implementInterfaces(declarations: List) { + val unimplementedMemberMap = getUnimplementedMembers(declarations) + val nonAbstractDeclarations = declarations.filter { it.kind == GenerateDefinitionKind.CLASS } + for (declaration in nonAbstractDeclarations) { + val unimplementedMembers = unimplementedMemberMap[declaration.name] ?: continue + + for (attribute in unimplementedMembers.attributes) { + declaration.memberAttributes += attribute.copy(override = true) + } + for (function in unimplementedMembers.functions) { + declaration.memberFunctions += function.copy(override = true) + } + } +} + +private fun getUnimplementedMembers(declarations: List): Map { + val declarationMap = declarations.associate { it.name to it } + val unimplementedMemberCache = mutableMapOf() + + fun getForClass(className: String): UnimplementedMembers = unimplementedMemberCache.getOrPut(className) { + val declaration = declarationMap[className] ?: return@getOrPut UnimplementedMembers(emptyList(), emptyList()) + val unimplementedInSuperClasses = declaration.superTypes.map { getForClass(it) } + val attributeMap = unimplementedInSuperClasses + .flatMap { it.attributes } + .associate { it.name to it } + .toMutableMap() + val functionMap = unimplementedInSuperClasses + .flatMap { it.functions } + .associate { "${it.name}(${it.signature})" to it } + .toMutableMap() + + val (implementedAttributes, unimplementedAttributes) = declaration.memberAttributes + .filter { !it.static } + .partition { declaration.kind != GenerateDefinitionKind.INTERFACE && !it.getterSetterNoImpl } + val (implementedFunctions, unimplementedFunctions) = declaration.memberFunctions + .filter { !it.static } + .partition { declaration.kind != GenerateDefinitionKind.INTERFACE } + + attributeMap += unimplementedAttributes.map { it.name to it } + attributeMap.keys -= implementedAttributes.map { it.name } + functionMap += unimplementedFunctions.map { "${it.name}(${it.signature})" to it } + functionMap.keys -= implementedFunctions.map { "${it.name}(${it.signature})" } + + UnimplementedMembers(attributeMap.values.toList(), functionMap.values.toList()) + } + + for (declaration in declarations) { + getForClass(declaration.name) + } + + return unimplementedMemberCache +} + +private class UnimplementedMembers(val attributes: List, val functions: List) \ No newline at end of file diff --git a/libraries/tools/idl2k/src/main/kotlin/main.kt b/libraries/tools/idl2k/src/main/kotlin/main.kt index 13a30074fd4..7f716211ba2 100644 --- a/libraries/tools/idl2k/src/main/kotlin/main.kt +++ b/libraries/tools/idl2k/src/main/kotlin/main.kt @@ -41,6 +41,7 @@ fun main(args: Array) { } val unions = generateUnions(definitions, repository.typeDefs.values) val allPackages = definitions.map { it.namespace }.distinct().sorted() + implementInterfaces(definitions) outDir.deleteRecursively() outDir.mkdirs() diff --git a/libraries/tools/idl2k/src/main/kotlin/model.kt b/libraries/tools/idl2k/src/main/kotlin/model.kt index 170ea71c081..2c2ae3aa610 100644 --- a/libraries/tools/idl2k/src/main/kotlin/model.kt +++ b/libraries/tools/idl2k/src/main/kotlin/model.kt @@ -69,7 +69,8 @@ data class GenerateFunction( val returnType: Type, val arguments: List, val nativeGetterOrSetter: NativeGetterOrSetter, - val static: Boolean + val static: Boolean, + val override: Boolean ) data class ConstructorWithSuperTypeCall(val constructor: GenerateFunction, val constructorAttribute: ExtendedAttribute, val initTypeCall: GenerateFunctionCall?) @@ -78,8 +79,8 @@ data class GenerateTraitOrClass( val namespace: String, val kind: GenerateDefinitionKind, val superTypes: List, - val memberAttributes: List, - val memberFunctions: List, + val memberAttributes: MutableList, + val memberFunctions: MutableList, val constants: List, val primaryConstructor: ConstructorWithSuperTypeCall?, val secondaryConstructors: List, diff --git a/libraries/tools/idl2k/src/main/kotlin/render.kt b/libraries/tools/idl2k/src/main/kotlin/render.kt index 87c4a7c3b89..66a87cdc21d 100644 --- a/libraries/tools/idl2k/src/main/kotlin/render.kt +++ b/libraries/tools/idl2k/src/main/kotlin/render.kt @@ -1,3 +1,19 @@ +/* + * Copyright 2010-2016 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.idl2k import java.math.BigInteger @@ -108,7 +124,7 @@ private fun Appendable.renderFunctionDeclaration(f: GenerateFunction, override: } append("fun ${f.name.replaceKeywords()}") renderArgumentsDeclaration(f.arguments, override) - appendln(": ${f.returnType.render()} = noImpl") + appendln(": ${f.returnType.render()}") } private fun List.hasNoVars() = none { it.isVar } @@ -180,10 +196,7 @@ fun Appendable.render(allTypes: Map, typeNamesToUn val modality = when { attribute.signature in superSignatures -> MemberModality.OVERRIDE iface.kind == GenerateDefinitionKind.CLASS && attribute.isVal -> MemberModality.OPEN - iface.kind == GenerateDefinitionKind.ABSTRACT_CLASS -> when { - attribute.initializer != null || attribute.getterSetterNoImpl -> MemberModality.OPEN - else -> MemberModality.ABSTRACT - } + iface.kind == GenerateDefinitionKind.ABSTRACT_CLASS -> MemberModality.OPEN else -> MemberModality.FINAL } @@ -203,8 +216,8 @@ fun Appendable.render(allTypes: Map, typeNamesToUn ) } } - iface.memberFunctions.filter { it !in superFunctions && !it.static }.map { it.dynamicIfUnknownType(allTypes.keys) }.groupBy { it.signature }.reduceValues(::betterFunction).values.forEach { - renderFunctionDeclaration(it.fixRequiredArguments(iface.name), it.signature in superSignatures, commented = it.isCommented(iface.name)) + iface.memberFunctions.filter { (it !in superFunctions || it.override) && !it.static }.map { it.dynamicIfUnknownType(allTypes.keys) }.groupBy { it.signature }.reduceValues(::betterFunction).values.forEach { + renderFunctionDeclaration(it.fixRequiredArguments(iface.name), it.signature in superSignatures || it.override, commented = it.isCommented(iface.name)) } val staticAttributes = iface.memberAttributes.filter { it.static }